1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/telemetry/gen-histogram-data.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,194 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +# Write out histogram information for C++. The histograms are defined 1.9 +# in a file provided as a command-line argument. 1.10 + 1.11 +from __future__ import with_statement 1.12 + 1.13 +import sys 1.14 +import histogram_tools 1.15 +import itertools 1.16 + 1.17 +banner = """/* This file is auto-generated, see gen-histogram-data.py. */ 1.18 +""" 1.19 + 1.20 +# Write out the gHistograms array. 1.21 + 1.22 +class StringTable: 1.23 + def __init__(self): 1.24 + self.current_index = 0; 1.25 + self.table = {} 1.26 + 1.27 + def c_strlen(self, string): 1.28 + return len(string) + 1 1.29 + 1.30 + def stringIndex(self, string): 1.31 + if string in self.table: 1.32 + return self.table[string] 1.33 + else: 1.34 + result = self.current_index 1.35 + self.table[string] = result 1.36 + self.current_index += self.c_strlen(string) 1.37 + return result 1.38 + 1.39 + def writeDefinition(self, f, name): 1.40 + entries = self.table.items() 1.41 + entries.sort(key=lambda x:x[1]) 1.42 + # Avoid null-in-string warnings with GCC and potentially 1.43 + # overlong string constants; write everything out the long way. 1.44 + def explodeToCharArray(string): 1.45 + def toCChar(s): 1.46 + if s == "'": 1.47 + return "'\\''" 1.48 + else: 1.49 + return "'%s'" % s 1.50 + return ", ".join(map(toCChar, string)) 1.51 + f.write("const char %s[] = {\n" % name) 1.52 + for (string, offset) in entries[:-1]: 1.53 + e = explodeToCharArray(string) 1.54 + if e: 1.55 + f.write(" /* %5d */ %s, '\\0',\n" 1.56 + % (offset, explodeToCharArray(string))) 1.57 + else: 1.58 + f.write(" /* %5d */ '\\0',\n" % offset) 1.59 + f.write(" /* %5d */ %s, '\\0' };\n\n" 1.60 + % (entries[-1][1], explodeToCharArray(entries[-1][0]))) 1.61 + 1.62 +def print_array_entry(histogram, name_index, exp_index): 1.63 + cpp_guard = histogram.cpp_guard() 1.64 + if cpp_guard: 1.65 + print "#if defined(%s)" % cpp_guard 1.66 + print " { %s, %s, %s, %s, %d, %d, %s }," \ 1.67 + % (histogram.low(), histogram.high(), 1.68 + histogram.n_buckets(), histogram.nsITelemetry_kind(), 1.69 + name_index, exp_index, 1.70 + "true" if histogram.extended_statistics_ok() else "false") 1.71 + if cpp_guard: 1.72 + print "#endif" 1.73 + 1.74 +def write_histogram_table(histograms): 1.75 + table = StringTable() 1.76 + 1.77 + print "const TelemetryHistogram gHistograms[] = {" 1.78 + for histogram in histograms: 1.79 + name_index = table.stringIndex(histogram.name()) 1.80 + exp_index = table.stringIndex(histogram.expiration()) 1.81 + print_array_entry(histogram, name_index, exp_index) 1.82 + print "};" 1.83 + 1.84 + strtab_name = "gHistogramStringTable" 1.85 + table.writeDefinition(sys.stdout, strtab_name) 1.86 + static_assert("sizeof(%s) <= UINT32_MAX" % strtab_name, 1.87 + "index overflow") 1.88 + 1.89 +# Write out static asserts for histogram data. We'd prefer to perform 1.90 +# these checks in this script itself, but since several histograms 1.91 +# (generally enumerated histograms) use compile-time constants for 1.92 +# their upper bounds, we have to let the compiler do the checking. 1.93 + 1.94 +def static_assert(expression, message): 1.95 + print "static_assert(%s, \"%s\");" % (expression, message) 1.96 + 1.97 +def static_asserts_for_boolean(histogram): 1.98 + pass 1.99 + 1.100 +def static_asserts_for_flag(histogram): 1.101 + pass 1.102 + 1.103 +def static_asserts_for_enumerated(histogram): 1.104 + n_values = histogram.high() 1.105 + static_assert("%s > 2" % n_values, 1.106 + "Not enough values for %s" % histogram.name()) 1.107 + 1.108 +def shared_static_asserts(histogram): 1.109 + name = histogram.name() 1.110 + low = histogram.low() 1.111 + high = histogram.high() 1.112 + n_buckets = histogram.n_buckets() 1.113 + static_assert("%s < %s" % (low, high), "low >= high for %s" % name) 1.114 + static_assert("%s > 2" % n_buckets, "Not enough values for %s" % name) 1.115 + static_assert("%s >= 1" % low, "Incorrect low value for %s" % name) 1.116 + static_assert("%s > %s" % (high, n_buckets), 1.117 + "high must be > number of buckets for %s; you may want an enumerated histogram" % name) 1.118 + 1.119 +def static_asserts_for_linear(histogram): 1.120 + shared_static_asserts(histogram) 1.121 + 1.122 +def static_asserts_for_exponential(histogram): 1.123 + shared_static_asserts(histogram) 1.124 + 1.125 +def write_histogram_static_asserts(histograms): 1.126 + print """ 1.127 +// Perform the checks at the beginning of HistogramGet at 1.128 +// compile time, so that incorrect histogram definitions 1.129 +// give compile-time errors, not runtime errors.""" 1.130 + 1.131 + table = { 1.132 + 'boolean' : static_asserts_for_boolean, 1.133 + 'flag' : static_asserts_for_flag, 1.134 + 'enumerated' : static_asserts_for_enumerated, 1.135 + 'linear' : static_asserts_for_linear, 1.136 + 'exponential' : static_asserts_for_exponential, 1.137 + } 1.138 + 1.139 + for histogram in histograms: 1.140 + histogram_tools.table_dispatch(histogram.kind(), table, 1.141 + lambda f: f(histogram)) 1.142 + 1.143 +def write_debug_histogram_ranges(histograms): 1.144 + ranges_lengths = [] 1.145 + 1.146 + # Collect all the range information from individual histograms. 1.147 + # Write that information out as well. 1.148 + print "#ifdef DEBUG" 1.149 + print "const int gBucketLowerBounds[] = {" 1.150 + for histogram in histograms: 1.151 + ranges = [] 1.152 + try: 1.153 + ranges = histogram.ranges() 1.154 + except histogram_tools.DefinitionException: 1.155 + pass 1.156 + ranges_lengths.append(len(ranges)) 1.157 + # Note that we do not test cpp_guard here. We do this so we 1.158 + # will have complete information about all the histograms in 1.159 + # this array. Just having information about the ranges of 1.160 + # histograms is not platform-specific; if there are histograms 1.161 + # that have platform-specific constants in their definitions, 1.162 + # those histograms will fail in the .ranges() call above and 1.163 + # we'll have a zero-length array to deal with here. 1.164 + if len(ranges) > 0: 1.165 + print ','.join(map(str, ranges)), ',' 1.166 + else: 1.167 + print '/* Skipping %s */' % histogram.name() 1.168 + print "};" 1.169 + 1.170 + # Write the offsets into gBucketLowerBounds. 1.171 + print "struct bounds { int offset; int length; };" 1.172 + print "const struct bounds gBucketLowerBoundIndex[] = {" 1.173 + offset = 0 1.174 + for (histogram, range_length) in itertools.izip(histograms, ranges_lengths): 1.175 + cpp_guard = histogram.cpp_guard() 1.176 + # We do test cpp_guard here, so that histogram IDs are valid 1.177 + # indexes into this array. 1.178 + if cpp_guard: 1.179 + print "#if defined(%s)" % cpp_guard 1.180 + print "{ %d, %d }," % (offset, range_length) 1.181 + if cpp_guard: 1.182 + print "#endif" 1.183 + offset += range_length 1.184 + print "};" 1.185 + print "#endif" 1.186 + 1.187 +def main(argv): 1.188 + filename = argv[0] 1.189 + 1.190 + histograms = list(histogram_tools.from_file(filename)) 1.191 + 1.192 + print banner 1.193 + write_histogram_table(histograms) 1.194 + write_histogram_static_asserts(histograms) 1.195 + write_debug_histogram_ranges(histograms) 1.196 + 1.197 +main(sys.argv[1:])