| Index: sandbox/linux/seccomp/timestats.cc
|
| ===================================================================
|
| --- sandbox/linux/seccomp/timestats.cc (revision 57969)
|
| +++ sandbox/linux/seccomp/timestats.cc (working copy)
|
| @@ -1,191 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -// Helper program to analyze the time that Chrome's renderers spend in system
|
| -// calls. Start Chrome like this:
|
| -//
|
| -// SECCOMP_SANDBOX_DEBUGGING=1 chrome --enable-seccomp-sandbox 2>&1 | timestats
|
| -//
|
| -// The program prints CPU time (0-100%) spent within system calls. This gives
|
| -// a general idea of where it is worthwhile to spend effort optimizing Chrome.
|
| -//
|
| -// Caveats:
|
| -// - there currently is no way to estimate what the overhead is for running
|
| -// inside of the sandbox vs. running without a sandbox.
|
| -// - we currently use a very simple heuristic to decide whether a system call
|
| -// is blocking or not. Blocking system calls should not be included in the
|
| -// computations. But it is quite possible for the numbers to be somewhat
|
| -// wrong, because the heuristic failed.
|
| -// - in order to collect this data, we have to turn on sandbox debugging.
|
| -// There is a measurable performance penalty to doing so. Production numbers
|
| -// are strictly better than the numbers reported by this tool.
|
| -#include <set>
|
| -#include <vector>
|
| -
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <string.h>
|
| -#include <sys/time.h>
|
| -#include <time.h>
|
| -
|
| -static const int kAvgWindowSizeMs = 500;
|
| -static const int kPeakWindowSizeMs = 2*1000;
|
| -
|
| -// Class containing information on a single system call. Most notably, it
|
| -// contains the time when the system call happened, and the time that it
|
| -// took to complete.
|
| -class Datum {
|
| - friend class Data;
|
| - public:
|
| - Datum(const char* name, double ms)
|
| - : name_(name),
|
| - ms_(ms) {
|
| - struct timeval tv;
|
| - gettimeofday(&tv, NULL);
|
| - timestamp_ = tv.tv_sec*1000.0 + tv.tv_usec/1000.0;
|
| - }
|
| - virtual ~Datum() { }
|
| -
|
| - double operator-(const Datum& b) {
|
| - return timestamp_ - b.timestamp_;
|
| - }
|
| -
|
| - protected:
|
| - const char* name_;
|
| - double ms_;
|
| - double timestamp_;
|
| -};
|
| -
|
| -// Class containing data on the most recent system calls. It maintains
|
| -// sliding averages for total CPU time used, and it also maintains a peak
|
| -// CPU usage. The peak usage is usually updated slower than the average
|
| -// usage, as that makes it easier to inspect visually.
|
| -class Data {
|
| - public:
|
| - Data() { }
|
| - virtual ~Data() { }
|
| -
|
| - void addData(const char* name, double ms) {
|
| - average_.push_back(Datum(name, ms));
|
| - peak_.push_back(Datum(name, ms));
|
| -
|
| - // Prune entries outside of the window
|
| - std::vector<Datum>::iterator iter;
|
| - for (iter = average_.begin();
|
| - *average_.rbegin() - *iter > kAvgWindowSizeMs;
|
| - ++iter) {
|
| - }
|
| - average_.erase(average_.begin(), iter);
|
| -
|
| - for (iter = peak_.begin();
|
| - *peak_.rbegin() - *iter > kPeakWindowSizeMs;
|
| - ++iter){
|
| - }
|
| - peak_.erase(peak_.begin(), iter);
|
| -
|
| - // Add the total usage of all system calls inside of the window
|
| - double total = 0;
|
| - for (iter = average_.begin(); iter != average_.end(); ++iter) {
|
| - total += iter->ms_;
|
| - }
|
| -
|
| - // Compute the peak CPU usage during the last window
|
| - double peak = 0;
|
| - double max = 0;
|
| - std::vector<Datum>::iterator tail = peak_.begin();
|
| - for (iter = tail; iter != peak_.end(); ++iter) {
|
| - while (*iter - *tail > kAvgWindowSizeMs) {
|
| - peak -= tail->ms_;
|
| - ++tail;
|
| - }
|
| - peak += iter->ms_;
|
| - if (peak > max) {
|
| - max = peak;
|
| - }
|
| - }
|
| -
|
| - // Print the average CPU usage in the last window
|
| - char buf[80];
|
| - total *= 100.0/kAvgWindowSizeMs;
|
| - max *= 100.0/kAvgWindowSizeMs;
|
| - sprintf(buf, "%6.2f%% (peak=%6.2f%%) ", total, max);
|
| -
|
| - // Animate the actual usage, displaying both average and peak values
|
| - int len = strlen(buf);
|
| - int space = sizeof(buf) - len - 1;
|
| - int mark = (total * space + 50)/100;
|
| - int bar = (max * space + 50)/100;
|
| - for (int i = 0; i < mark; ++i) {
|
| - buf[len++] = '*';
|
| - }
|
| - if (mark == bar) {
|
| - if (bar) {
|
| - len--;
|
| - }
|
| - } else {
|
| - for (int i = 0; i < bar - mark - 1; ++i) {
|
| - buf[len++] = ' ';
|
| - }
|
| - }
|
| - buf[len++] = '|';
|
| - while (len < static_cast<int>(sizeof(buf))) {
|
| - buf[len++] = ' ';
|
| - }
|
| - strcpy(buf + len, "\r");
|
| - fwrite(buf, len + 1, 1, stdout);
|
| - fflush(stdout);
|
| - }
|
| -
|
| - private:
|
| - std::vector<Datum> average_;
|
| - std::vector<Datum> peak_;
|
| -};
|
| -static Data data;
|
| -
|
| -
|
| -int main(int argc, char *argv[]) {
|
| - char buf[80];
|
| - bool expensive = false;
|
| - while (fgets(buf, sizeof(buf), stdin)) {
|
| - // Allow longer delays for expensive system calls
|
| - if (strstr(buf, "This is an expensive system call")) {
|
| - expensive = true;
|
| - continue;
|
| - }
|
| -
|
| - // Parse the string and extract the elapsed time
|
| - const char elapsed[] = "Elapsed time: ";
|
| - char* ms_string = strstr(buf, elapsed);
|
| - char* endptr;
|
| - double ms;
|
| - char* colon = strchr(buf, ':');
|
| -
|
| - // If this string doesn't match, then it must be some other type of
|
| - // message. Just ignore it.
|
| - // It is quite likely that we will regularly encounter debug messages
|
| - // that either should be parsed by a completely different tool, or
|
| - // messages that were intended for humans to read.
|
| - if (!ms_string ||
|
| - ((ms = strtod(ms_string + sizeof(elapsed) - 1, &endptr)),
|
| - endptr == ms_string) ||
|
| - !colon) {
|
| - continue;
|
| - }
|
| -
|
| - // Filter out system calls that were probably just blocking
|
| - // TODO(markus): automatically compute the cut-off for blocking calls
|
| - if (!expensive && ms > 0.05) {
|
| - continue;
|
| - }
|
| - expensive = false;
|
| -
|
| - // Extract the name of the system call
|
| - *colon = '\000';
|
| -
|
| - // Add the data point and update the display
|
| - data.addData(buf, ms);
|
| - }
|
| - puts("");
|
| - return 0;
|
| -}
|
|
|