OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2015 the V8 project authors. All rights reserved. | 3 # Copyright 2015 the V8 project authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """This script is used to analyze GCTracer's NVP output.""" | 7 """This script is used to analyze GCTracer's NVP output.""" |
8 | 8 |
9 | 9 |
10 from argparse import ArgumentParser | 10 from argparse import ArgumentParser |
11 from copy import deepcopy | 11 from copy import deepcopy |
12 from gc_nvp_common import split_nvp | 12 from gc_nvp_common import split_nvp |
13 from math import log | 13 from math import ceil,log |
14 from sys import stdin | 14 from sys import stdin |
15 | 15 |
16 | 16 |
17 class LinearBucket: | 17 class LinearBucket: |
18 def __init__(self, granularity): | 18 def __init__(self, granularity): |
19 self.granularity = granularity | 19 self.granularity = granularity |
20 | 20 |
21 def value_to_bucket(self, value): | 21 def value_to_bucket(self, value): |
22 return int(value / self.granularity) | 22 return int(value / self.granularity) |
23 | 23 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 ret.append(" [{0},{1}[: {2}".format( | 67 ret.append(" [{0},{1}[: {2}".format( |
68 str(min_value), str(max_value), self.histogram[i])) | 68 str(min_value), str(max_value), self.histogram[i])) |
69 else: | 69 else: |
70 if self.fill_empty: | 70 if self.fill_empty: |
71 ret.append(" [{0},{1}[: {2}".format( | 71 ret.append(" [{0},{1}[: {2}".format( |
72 str(min_value), str(max_value), 0)) | 72 str(min_value), str(max_value), 0)) |
73 return "\n".join(ret) | 73 return "\n".join(ret) |
74 | 74 |
75 | 75 |
76 class Category: | 76 class Category: |
77 def __init__(self, key, histogram, csv): | 77 def __init__(self, key, histogram, csv, percentiles): |
78 self.key = key | 78 self.key = key |
79 self.values = [] | 79 self.values = [] |
80 self.histogram = histogram | 80 self.histogram = histogram |
81 self.csv = csv | 81 self.csv = csv |
| 82 self.percentiles = percentiles |
82 | 83 |
83 def process_entry(self, entry): | 84 def process_entry(self, entry): |
84 if self.key in entry: | 85 if self.key in entry: |
85 self.values.append(float(entry[self.key])) | 86 self.values.append(float(entry[self.key])) |
86 if self.histogram: | 87 if self.histogram: |
87 self.histogram.add(float(entry[self.key])) | 88 self.histogram.add(float(entry[self.key])) |
88 | 89 |
89 def min(self): | 90 def min(self): |
90 return min(self.values) | 91 return min(self.values) |
91 | 92 |
92 def max(self): | 93 def max(self): |
93 return max(self.values) | 94 return max(self.values) |
94 | 95 |
95 def avg(self): | 96 def avg(self): |
96 if len(self.values) == 0: | 97 if len(self.values) == 0: |
97 return 0.0 | 98 return 0.0 |
98 return sum(self.values) / len(self.values) | 99 return sum(self.values) / len(self.values) |
99 | 100 |
100 def empty(self): | 101 def empty(self): |
101 return len(self.values) == 0 | 102 return len(self.values) == 0 |
102 | 103 |
| 104 def _compute_percentiles(self): |
| 105 ret = [] |
| 106 if len(self.values) == 0: |
| 107 return ret |
| 108 sorted_values = sorted(self.values) |
| 109 for percentile in self.percentiles: |
| 110 index = int(ceil((len(self.values) - 1) * percentile / 100)) |
| 111 ret.append(" {0}%: {1}".format(percentile, sorted_values[index])) |
| 112 return ret |
| 113 |
103 def __str__(self): | 114 def __str__(self): |
104 if self.csv: | 115 if self.csv: |
105 ret = [self.key] | 116 ret = [self.key] |
106 ret.append(len(self.values)) | 117 ret.append(len(self.values)) |
107 ret.append(self.min()) | 118 ret.append(self.min()) |
108 ret.append(self.max()) | 119 ret.append(self.max()) |
109 ret.append(self.avg()) | 120 ret.append(self.avg()) |
110 ret = [str(x) for x in ret] | 121 ret = [str(x) for x in ret] |
111 return ",".join(ret) | 122 return ",".join(ret) |
112 else: | 123 else: |
113 ret = [self.key] | 124 ret = [self.key] |
114 ret.append(" len: {0}".format(len(self.values))) | 125 ret.append(" len: {0}".format(len(self.values))) |
115 if len(self.values) > 0: | 126 if len(self.values) > 0: |
116 ret.append(" min: {0}".format(self.min())) | 127 ret.append(" min: {0}".format(self.min())) |
117 ret.append(" max: {0}".format(self.max())) | 128 ret.append(" max: {0}".format(self.max())) |
118 ret.append(" avg: {0}".format(self.avg())) | 129 ret.append(" avg: {0}".format(self.avg())) |
119 if self.histogram: | 130 if self.histogram: |
120 ret.append(str(self.histogram)) | 131 ret.append(str(self.histogram)) |
| 132 if self.percentiles: |
| 133 ret.append("\n".join(self._compute_percentiles())) |
121 return "\n".join(ret) | 134 return "\n".join(ret) |
122 | 135 |
123 def __repr__(self): | 136 def __repr__(self): |
124 return "<Category: {0}>".format(self.key) | 137 return "<Category: {0}>".format(self.key) |
125 | 138 |
126 | 139 |
127 def make_key_func(cmp_metric): | 140 def make_key_func(cmp_metric): |
128 def key_func(a): | 141 def key_func(a): |
129 return getattr(a, cmp_metric)() | 142 return getattr(a, cmp_metric)() |
130 return key_func | 143 return key_func |
(...skipping 22 matching lines...) Expand all Loading... |
153 parser.add_argument('--no-histogram', dest='histogram', | 166 parser.add_argument('--no-histogram', dest='histogram', |
154 action='store_false', help='do not print histogram') | 167 action='store_false', help='do not print histogram') |
155 parser.set_defaults(histogram=True) | 168 parser.set_defaults(histogram=True) |
156 parser.set_defaults(histogram_omit_empty=False) | 169 parser.set_defaults(histogram_omit_empty=False) |
157 parser.add_argument('--rank', metavar='<no|min|max|avg>', | 170 parser.add_argument('--rank', metavar='<no|min|max|avg>', |
158 type=str, nargs='?', | 171 type=str, nargs='?', |
159 default="no", | 172 default="no", |
160 help="rank keys by metric (default: no)") | 173 help="rank keys by metric (default: no)") |
161 parser.add_argument('--csv', dest='csv', | 174 parser.add_argument('--csv', dest='csv', |
162 action='store_true', help='provide output as csv') | 175 action='store_true', help='provide output as csv') |
| 176 parser.add_argument('--percentiles', dest='percentiles', |
| 177 type=str, default="", |
| 178 help='comma separated list of percentiles') |
163 args = parser.parse_args() | 179 args = parser.parse_args() |
164 | 180 |
165 histogram = None | 181 histogram = None |
166 if args.histogram: | 182 if args.histogram: |
167 bucket_trait = None | 183 bucket_trait = None |
168 if args.histogram_type == "log2": | 184 if args.histogram_type == "log2": |
169 bucket_trait = Log2Bucket(args.log2_histogram_init_bucket) | 185 bucket_trait = Log2Bucket(args.log2_histogram_init_bucket) |
170 else: | 186 else: |
171 bucket_trait = LinearBucket(args.linear_histogram_granularity) | 187 bucket_trait = LinearBucket(args.linear_histogram_granularity) |
172 histogram = Histogram(bucket_trait, not args.histogram_omit_empty) | 188 histogram = Histogram(bucket_trait, not args.histogram_omit_empty) |
173 | 189 |
174 categories = [ Category(key, deepcopy(histogram), args.csv) | 190 percentiles = [] |
| 191 for percentile in args.percentiles.split(','): |
| 192 try: |
| 193 percentiles.append(float(percentile)) |
| 194 except ValueError: |
| 195 pass |
| 196 |
| 197 categories = [ Category(key, deepcopy(histogram), args.csv, percentiles) |
175 for key in args.keys ] | 198 for key in args.keys ] |
176 | 199 |
177 while True: | 200 while True: |
178 line = stdin.readline() | 201 line = stdin.readline() |
179 if not line: | 202 if not line: |
180 break | 203 break |
181 obj = split_nvp(line) | 204 obj = split_nvp(line) |
182 for category in categories: | 205 for category in categories: |
183 category.process_entry(obj) | 206 category.process_entry(obj) |
184 | 207 |
185 # Filter out empty categories. | 208 # Filter out empty categories. |
186 categories = [x for x in categories if not x.empty()] | 209 categories = [x for x in categories if not x.empty()] |
187 | 210 |
188 if args.rank != "no": | 211 if args.rank != "no": |
189 categories = sorted(categories, key=make_key_func(args.rank), reverse=True) | 212 categories = sorted(categories, key=make_key_func(args.rank), reverse=True) |
190 | 213 |
191 for category in categories: | 214 for category in categories: |
192 print(category) | 215 print(category) |
193 | 216 |
194 | 217 |
195 if __name__ == '__main__': | 218 if __name__ == '__main__': |
196 main() | 219 main() |
OLD | NEW |