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; |
-} |