2015-09-22 13:59:19 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
"""This script is used to analyze GCTracer's NVP output."""
|
|
|
|
|
2015-09-23 13:52:35 +00:00
|
|
|
|
2015-09-22 13:59:19 +00:00
|
|
|
from argparse import ArgumentParser
|
2015-09-23 13:52:35 +00:00
|
|
|
from copy import deepcopy
|
2015-09-22 13:59:19 +00:00
|
|
|
from gc_nvp_common import split_nvp
|
2015-09-25 16:14:03 +00:00
|
|
|
from math import log
|
2015-09-22 13:59:19 +00:00
|
|
|
from sys import stdin
|
|
|
|
|
2015-09-23 13:52:35 +00:00
|
|
|
|
2015-09-25 16:14:03 +00:00
|
|
|
class LinearBucket:
|
|
|
|
def __init__(self, granularity):
|
2015-09-22 13:59:19 +00:00
|
|
|
self.granularity = granularity
|
2015-09-25 16:14:03 +00:00
|
|
|
|
|
|
|
def value_to_bucket(self, value):
|
|
|
|
return int(value / self.granularity)
|
|
|
|
|
|
|
|
def bucket_to_range(self, bucket):
|
|
|
|
return (bucket * self.granularity, (bucket + 1) * self.granularity)
|
|
|
|
|
|
|
|
|
|
|
|
class Log2Bucket:
|
|
|
|
def __init__(self, start):
|
|
|
|
self.start = int(log(start, 2)) - 1
|
|
|
|
|
|
|
|
def value_to_bucket(self, value):
|
|
|
|
index = int(log(value, 2))
|
|
|
|
index -= self.start
|
|
|
|
if index < 0:
|
|
|
|
index = 0
|
|
|
|
return index
|
|
|
|
|
|
|
|
def bucket_to_range(self, bucket):
|
|
|
|
if bucket == 0:
|
|
|
|
return (0, 2 ** (self.start + 1))
|
|
|
|
bucket += self.start
|
|
|
|
return (2 ** bucket, 2 ** (bucket + 1))
|
|
|
|
|
|
|
|
|
|
|
|
class Histogram:
|
|
|
|
def __init__(self, bucket_trait, fill_empty):
|
2015-09-23 13:52:35 +00:00
|
|
|
self.histogram = {}
|
|
|
|
self.fill_empty = fill_empty
|
2015-09-25 16:14:03 +00:00
|
|
|
self.bucket_trait = bucket_trait
|
2015-09-23 13:52:35 +00:00
|
|
|
|
|
|
|
def add(self, key):
|
2015-09-25 16:14:03 +00:00
|
|
|
index = self.bucket_trait.value_to_bucket(key)
|
2015-09-23 13:52:35 +00:00
|
|
|
if index not in self.histogram:
|
|
|
|
self.histogram[index] = 0
|
|
|
|
self.histogram[index] += 1
|
2015-09-22 13:59:19 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
ret = []
|
2015-09-23 13:52:35 +00:00
|
|
|
keys = self.histogram.keys()
|
|
|
|
keys.sort()
|
2015-09-25 16:14:03 +00:00
|
|
|
last = keys[len(keys) - 1]
|
|
|
|
for i in range(0, last + 1):
|
|
|
|
(min_value, max_value) = self.bucket_trait.bucket_to_range(i)
|
|
|
|
if i == keys[0]:
|
|
|
|
keys.pop(0)
|
|
|
|
ret.append(" [{0},{1}[: {2}".format(
|
|
|
|
str(min_value), str(max_value), self.histogram[i]))
|
|
|
|
else:
|
|
|
|
if self.fill_empty:
|
2015-09-23 13:52:35 +00:00
|
|
|
ret.append(" [{0},{1}[: {2}".format(
|
2015-09-25 16:14:03 +00:00
|
|
|
str(min_value), str(max_value), 0))
|
2015-09-22 13:59:19 +00:00
|
|
|
return "\n".join(ret)
|
|
|
|
|
|
|
|
|
|
|
|
class Category:
|
2015-09-23 13:52:35 +00:00
|
|
|
def __init__(self, key, histogram):
|
2015-09-22 13:59:19 +00:00
|
|
|
self.key = key
|
|
|
|
self.values = []
|
|
|
|
self.histogram = histogram
|
|
|
|
|
|
|
|
def process_entry(self, entry):
|
|
|
|
if self.key in entry:
|
|
|
|
self.values.append(float(entry[self.key]))
|
2015-09-23 13:52:35 +00:00
|
|
|
if self.histogram:
|
|
|
|
self.histogram.add(float(entry[self.key]))
|
2015-09-22 13:59:19 +00:00
|
|
|
|
2015-10-15 11:37:30 +00:00
|
|
|
def min(self):
|
|
|
|
return min(self.values)
|
|
|
|
|
|
|
|
def max(self):
|
|
|
|
return max(self.values)
|
|
|
|
|
|
|
|
def avg(self):
|
|
|
|
return sum(self.values) / len(self.values)
|
|
|
|
|
2015-09-22 13:59:19 +00:00
|
|
|
def __str__(self):
|
|
|
|
ret = [self.key]
|
|
|
|
ret.append(" len: {0}".format(len(self.values)))
|
|
|
|
if len(self.values) > 0:
|
|
|
|
ret.append(" min: {0}".format(min(self.values)))
|
|
|
|
ret.append(" max: {0}".format(max(self.values)))
|
|
|
|
ret.append(" avg: {0}".format(sum(self.values) / len(self.values)))
|
|
|
|
if self.histogram:
|
2015-09-23 13:52:35 +00:00
|
|
|
ret.append(str(self.histogram))
|
2015-09-22 13:59:19 +00:00
|
|
|
return "\n".join(ret)
|
|
|
|
|
2015-10-15 11:37:30 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return "<Category: {0}>".format(self.key)
|
|
|
|
|
|
|
|
|
|
|
|
def make_key_func(cmp_metric):
|
|
|
|
def key_func(a):
|
|
|
|
return getattr(a, cmp_metric)()
|
|
|
|
return key_func
|
|
|
|
|
2015-09-22 13:59:19 +00:00
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = ArgumentParser(description="Process GCTracer's NVP output")
|
|
|
|
parser.add_argument('keys', metavar='KEY', type=str, nargs='+',
|
2015-09-25 16:14:03 +00:00
|
|
|
help='the keys of NVPs to process')
|
|
|
|
parser.add_argument('--histogram-type', metavar='<linear|log2>',
|
|
|
|
type=str, nargs='?', default="linear",
|
|
|
|
help='histogram type to use (default: linear)')
|
|
|
|
linear_group = parser.add_argument_group('linear histogram specific')
|
|
|
|
linear_group.add_argument('--linear-histogram-granularity',
|
|
|
|
metavar='GRANULARITY', type=int, nargs='?',
|
|
|
|
default=5,
|
|
|
|
help='histogram granularity (default: 5)')
|
|
|
|
log2_group = parser.add_argument_group('log2 histogram specific')
|
|
|
|
log2_group.add_argument('--log2-histogram-init-bucket', metavar='START',
|
|
|
|
type=int, nargs='?', default=64,
|
|
|
|
help='initial buck size (default: 64)')
|
|
|
|
parser.add_argument('--histogram-omit-empty-buckets',
|
|
|
|
dest='histogram_omit_empty',
|
|
|
|
action='store_true',
|
|
|
|
help='omit empty histogram buckets')
|
|
|
|
parser.add_argument('--no-histogram', dest='histogram',
|
|
|
|
action='store_false', help='do not print histogram')
|
2015-09-22 13:59:19 +00:00
|
|
|
parser.set_defaults(histogram=True)
|
2015-09-25 16:14:03 +00:00
|
|
|
parser.set_defaults(histogram_omit_empty=False)
|
2015-10-15 11:37:30 +00:00
|
|
|
parser.add_argument('--rank', metavar='<no|min|max|avg>',
|
|
|
|
type=str, nargs='?',
|
|
|
|
default="no",
|
|
|
|
help="rank keys by metric (default: no)")
|
2015-09-22 13:59:19 +00:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
2015-09-23 13:52:35 +00:00
|
|
|
histogram = None
|
|
|
|
if args.histogram:
|
2015-09-25 16:14:03 +00:00
|
|
|
bucket_trait = None
|
|
|
|
if args.histogram_type == "log2":
|
|
|
|
bucket_trait = Log2Bucket(args.log2_histogram_init_bucket)
|
|
|
|
else:
|
|
|
|
bucket_trait = LinearBucket(args.linear_histogram_granularity)
|
|
|
|
histogram = Histogram(bucket_trait, not args.histogram_omit_empty)
|
2015-09-23 13:52:35 +00:00
|
|
|
|
|
|
|
categories = [ Category(key, deepcopy(histogram))
|
2015-09-22 13:59:19 +00:00
|
|
|
for key in args.keys ]
|
|
|
|
|
|
|
|
while True:
|
|
|
|
line = stdin.readline()
|
|
|
|
if not line:
|
|
|
|
break
|
|
|
|
obj = split_nvp(line)
|
|
|
|
for category in categories:
|
|
|
|
category.process_entry(obj)
|
|
|
|
|
2015-10-15 11:37:30 +00:00
|
|
|
if args.rank != "no":
|
|
|
|
categories = sorted(categories, key=make_key_func(args.rank), reverse=True)
|
|
|
|
|
2015-09-22 13:59:19 +00:00
|
|
|
for category in categories:
|
|
|
|
print(category)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|