Updating submodules
[hiphop-php.git] / hphp / tools / perf-rollup.php
blob350424087a12e68facf24ac0d8eb69701865d655
1 #!/usr/bin/env hhvm
2 <?hh
3 // Copyright 2004-present Facebook. All Rights Reserved.
5 function usage($script_name) {
6 echo <<<EOT
7 Usage:
9 perf script -f comm,ip,sym | $script_name
11 EOT;
14 // If $stack has any frames in the translation cache, return the C++ frame
15 // directly called by the deepest translation cache frame. If $stack has no TC
16 // frames, return null.
17 function tc_callee($stack) {
18 for ($i = 0; $i < count($stack); ++$i) {
19 // Normal translations starts with PHP::.
20 if (!starts_with($stack[$i], 'PHP::')) {
21 continue;
24 while (--$i >= 0) {
25 if ($stack[$i] === '[unknown]') continue;
26 return $stack[$i];
28 return '<unknown>';
30 return null;
33 // If $container is an int, return it. Otherwise, assume $container is a
34 // Map<string, int> and return the sum of its values.
35 function count_leaves($container) {
36 if (is_int($container)) return $container;
38 $count = 0;
39 foreach ($container as $value) {
40 $count += $value;
42 return $count;
45 // Print a summary of the data in $map, using keys as categories and values
46 // as sample counts. If the values in $map are more Maps, sample counts will be
47 // obtained by counting leaves, allowing for multiple levels of categorization.
48 function print_map($header, $map, $total) {
49 printf("%s\n", $header);
50 uasort(inout $map, ($a, $b) ==> count_leaves($b) - count_leaves($a));
52 foreach ($map as $name => $samples) {
53 $count = count_leaves($samples);
54 $pct_total = $count * 100.0 / $total;
55 if ($pct_total < 0.10) break;
56 printf(" %5.2f%% - %s\n", $pct_total, $name);
58 printf("\n");
61 // Increment $map[$key] by 1, setting it to 0 first if it doesn't exist.
62 function increment_key($map, $key) {
63 if (!isset($map[$key])) $map[$key] = 0;
64 $map[$key]++;
67 // Increment $map[$key1][$key2] by 1, setting it to 0 first if it doesn't exist.
68 function increment_key2($map, $key1, $key2) {
69 if (!isset($map[$key1])) $map[$key1] = Map {};
70 increment_key($map[$key1], $key2);
73 <<__Memoize>>
74 function get_categories() {
75 return Map {
76 'InterpOne' => Vector {
77 '/interpOne/',
79 'Iterators' => Vector {
80 '/iter/i',
82 'Async' => Vector {
83 '/WaitHandle/',
84 '/AsioBlockableChain/',
85 '/^HPHP::f_join/',
87 'CacheClient' => Vector {
88 '/c_CacheClient2/',
89 '/c_PhpTaoClient/',
91 'Arrays' => Vector {
92 '/Elem/i',
93 '/::array/',
94 '/(Mixed|Packed|Bespoke)Array/',
95 '/Vanilla(Dict|Vec)/',
96 '/ArrayData/',
97 '/^HPHP::bespoke::/',
98 '/^HPHP::f_(.?.?sort|array)/',
99 '/NameValueTable/',
100 '/jit::dict/',
101 '/MInstrHelpers::dict/',
102 '/MInstrHelpers::keyset/',
104 'Objects' => Vector {
105 '/::ObjectData::/',
106 '/initSProps/',
107 '/MethodCache/',
108 '/lookupClsMethodHelper/',
109 '/newInstance/',
110 '/Prop/',
111 '/::closureInstance.tor/',
113 'Strings' => Vector {
114 '/::concat/',
115 '/::StringData::/',
116 '/^HPHP::f_(explode|str|mb_strtolower|substr|preg_)/',
117 '/^HPHP::conv_10/',
119 'Memoization' => Vector {
120 '/^HPHP::memoCache/',
122 'OBC' => Vector {
123 '/::ObcStore::/',
124 '/^HPHP::f_obc_/',
126 'Extensions' => Vector {
127 '/^HPHP::f_/',
128 '/^HPHP::thrift::f_/',
129 '/^HPHP::math_mt_rand/',
130 '/^HPHP::\(anonymous namespace\)::f_/',
132 'Collections' => Vector {
133 '/deepInitHelper/',
134 '/Vector/',
135 '/mapSetImpl/',
136 '/Map/',
137 '/Set/',
138 '/ImmSet/',
139 '/HashCollection/',
141 'UniqueStubs' => Vector {
142 '/^HHVM::/',
147 function categorize_helper($func) {
148 // Order is important in this Map: we return the first category with a match,
149 // even though a later category may also match.
150 $categories = get_categories();
152 foreach ($categories as $cat => $regexes) {
153 foreach ($regexes as $regex) {
154 if (preg_match($regex, $func) === 1) return $cat;
157 return 'Uncategorized';
160 <<__EntryPoint>>
161 function main() {
162 require(__DIR__.'/perf-lib.php');
164 $argv = $_SERVER['argv'];
165 ini_set('memory_limit', '64G');
166 if (posix_isatty(STDIN)) {
167 usage($argv[0]);
168 exit(1);
171 fprintf(STDERR, ">> Parsing samples from stdin...\n");
172 $samples = read_perf_samples(STDIN);
173 $groups = Map {};
174 $helpers = Map {};
176 fprintf(STDERR, ">> Categorizing samples...\n");
177 foreach ($samples as $stack) {
178 if (starts_with($stack[0], 'PHP::')) {
179 increment_key($groups, 'TC');
180 } else if (starts_with($stack[0], 'HHVM::pcre_jit::')) {
181 increment_key($groups, 'PCRE JIT');
182 } else if ($callee = tc_callee($stack)) {
183 increment_key($groups, 'TC helpers');
184 $category = categorize_helper($callee);
185 increment_key2($helpers, $category, $callee);
186 } else {
187 increment_key($groups, 'Other');
191 $total_samples = count($samples);
192 print_map('Summary', $groups, $total_samples);
193 print_map('Helper categories', $helpers, $total_samples);
194 foreach ($helpers as $category => $map) {
195 print_map($category, $map, $total_samples);