toolkit/components/telemetry/gen-histogram-data.py

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 # Write out histogram information for C++. The histograms are defined
michael@0 6 # in a file provided as a command-line argument.
michael@0 7
michael@0 8 from __future__ import with_statement
michael@0 9
michael@0 10 import sys
michael@0 11 import histogram_tools
michael@0 12 import itertools
michael@0 13
michael@0 14 banner = """/* This file is auto-generated, see gen-histogram-data.py. */
michael@0 15 """
michael@0 16
michael@0 17 # Write out the gHistograms array.
michael@0 18
michael@0 19 class StringTable:
michael@0 20 def __init__(self):
michael@0 21 self.current_index = 0;
michael@0 22 self.table = {}
michael@0 23
michael@0 24 def c_strlen(self, string):
michael@0 25 return len(string) + 1
michael@0 26
michael@0 27 def stringIndex(self, string):
michael@0 28 if string in self.table:
michael@0 29 return self.table[string]
michael@0 30 else:
michael@0 31 result = self.current_index
michael@0 32 self.table[string] = result
michael@0 33 self.current_index += self.c_strlen(string)
michael@0 34 return result
michael@0 35
michael@0 36 def writeDefinition(self, f, name):
michael@0 37 entries = self.table.items()
michael@0 38 entries.sort(key=lambda x:x[1])
michael@0 39 # Avoid null-in-string warnings with GCC and potentially
michael@0 40 # overlong string constants; write everything out the long way.
michael@0 41 def explodeToCharArray(string):
michael@0 42 def toCChar(s):
michael@0 43 if s == "'":
michael@0 44 return "'\\''"
michael@0 45 else:
michael@0 46 return "'%s'" % s
michael@0 47 return ", ".join(map(toCChar, string))
michael@0 48 f.write("const char %s[] = {\n" % name)
michael@0 49 for (string, offset) in entries[:-1]:
michael@0 50 e = explodeToCharArray(string)
michael@0 51 if e:
michael@0 52 f.write(" /* %5d */ %s, '\\0',\n"
michael@0 53 % (offset, explodeToCharArray(string)))
michael@0 54 else:
michael@0 55 f.write(" /* %5d */ '\\0',\n" % offset)
michael@0 56 f.write(" /* %5d */ %s, '\\0' };\n\n"
michael@0 57 % (entries[-1][1], explodeToCharArray(entries[-1][0])))
michael@0 58
michael@0 59 def print_array_entry(histogram, name_index, exp_index):
michael@0 60 cpp_guard = histogram.cpp_guard()
michael@0 61 if cpp_guard:
michael@0 62 print "#if defined(%s)" % cpp_guard
michael@0 63 print " { %s, %s, %s, %s, %d, %d, %s }," \
michael@0 64 % (histogram.low(), histogram.high(),
michael@0 65 histogram.n_buckets(), histogram.nsITelemetry_kind(),
michael@0 66 name_index, exp_index,
michael@0 67 "true" if histogram.extended_statistics_ok() else "false")
michael@0 68 if cpp_guard:
michael@0 69 print "#endif"
michael@0 70
michael@0 71 def write_histogram_table(histograms):
michael@0 72 table = StringTable()
michael@0 73
michael@0 74 print "const TelemetryHistogram gHistograms[] = {"
michael@0 75 for histogram in histograms:
michael@0 76 name_index = table.stringIndex(histogram.name())
michael@0 77 exp_index = table.stringIndex(histogram.expiration())
michael@0 78 print_array_entry(histogram, name_index, exp_index)
michael@0 79 print "};"
michael@0 80
michael@0 81 strtab_name = "gHistogramStringTable"
michael@0 82 table.writeDefinition(sys.stdout, strtab_name)
michael@0 83 static_assert("sizeof(%s) <= UINT32_MAX" % strtab_name,
michael@0 84 "index overflow")
michael@0 85
michael@0 86 # Write out static asserts for histogram data. We'd prefer to perform
michael@0 87 # these checks in this script itself, but since several histograms
michael@0 88 # (generally enumerated histograms) use compile-time constants for
michael@0 89 # their upper bounds, we have to let the compiler do the checking.
michael@0 90
michael@0 91 def static_assert(expression, message):
michael@0 92 print "static_assert(%s, \"%s\");" % (expression, message)
michael@0 93
michael@0 94 def static_asserts_for_boolean(histogram):
michael@0 95 pass
michael@0 96
michael@0 97 def static_asserts_for_flag(histogram):
michael@0 98 pass
michael@0 99
michael@0 100 def static_asserts_for_enumerated(histogram):
michael@0 101 n_values = histogram.high()
michael@0 102 static_assert("%s > 2" % n_values,
michael@0 103 "Not enough values for %s" % histogram.name())
michael@0 104
michael@0 105 def shared_static_asserts(histogram):
michael@0 106 name = histogram.name()
michael@0 107 low = histogram.low()
michael@0 108 high = histogram.high()
michael@0 109 n_buckets = histogram.n_buckets()
michael@0 110 static_assert("%s < %s" % (low, high), "low >= high for %s" % name)
michael@0 111 static_assert("%s > 2" % n_buckets, "Not enough values for %s" % name)
michael@0 112 static_assert("%s >= 1" % low, "Incorrect low value for %s" % name)
michael@0 113 static_assert("%s > %s" % (high, n_buckets),
michael@0 114 "high must be > number of buckets for %s; you may want an enumerated histogram" % name)
michael@0 115
michael@0 116 def static_asserts_for_linear(histogram):
michael@0 117 shared_static_asserts(histogram)
michael@0 118
michael@0 119 def static_asserts_for_exponential(histogram):
michael@0 120 shared_static_asserts(histogram)
michael@0 121
michael@0 122 def write_histogram_static_asserts(histograms):
michael@0 123 print """
michael@0 124 // Perform the checks at the beginning of HistogramGet at
michael@0 125 // compile time, so that incorrect histogram definitions
michael@0 126 // give compile-time errors, not runtime errors."""
michael@0 127
michael@0 128 table = {
michael@0 129 'boolean' : static_asserts_for_boolean,
michael@0 130 'flag' : static_asserts_for_flag,
michael@0 131 'enumerated' : static_asserts_for_enumerated,
michael@0 132 'linear' : static_asserts_for_linear,
michael@0 133 'exponential' : static_asserts_for_exponential,
michael@0 134 }
michael@0 135
michael@0 136 for histogram in histograms:
michael@0 137 histogram_tools.table_dispatch(histogram.kind(), table,
michael@0 138 lambda f: f(histogram))
michael@0 139
michael@0 140 def write_debug_histogram_ranges(histograms):
michael@0 141 ranges_lengths = []
michael@0 142
michael@0 143 # Collect all the range information from individual histograms.
michael@0 144 # Write that information out as well.
michael@0 145 print "#ifdef DEBUG"
michael@0 146 print "const int gBucketLowerBounds[] = {"
michael@0 147 for histogram in histograms:
michael@0 148 ranges = []
michael@0 149 try:
michael@0 150 ranges = histogram.ranges()
michael@0 151 except histogram_tools.DefinitionException:
michael@0 152 pass
michael@0 153 ranges_lengths.append(len(ranges))
michael@0 154 # Note that we do not test cpp_guard here. We do this so we
michael@0 155 # will have complete information about all the histograms in
michael@0 156 # this array. Just having information about the ranges of
michael@0 157 # histograms is not platform-specific; if there are histograms
michael@0 158 # that have platform-specific constants in their definitions,
michael@0 159 # those histograms will fail in the .ranges() call above and
michael@0 160 # we'll have a zero-length array to deal with here.
michael@0 161 if len(ranges) > 0:
michael@0 162 print ','.join(map(str, ranges)), ','
michael@0 163 else:
michael@0 164 print '/* Skipping %s */' % histogram.name()
michael@0 165 print "};"
michael@0 166
michael@0 167 # Write the offsets into gBucketLowerBounds.
michael@0 168 print "struct bounds { int offset; int length; };"
michael@0 169 print "const struct bounds gBucketLowerBoundIndex[] = {"
michael@0 170 offset = 0
michael@0 171 for (histogram, range_length) in itertools.izip(histograms, ranges_lengths):
michael@0 172 cpp_guard = histogram.cpp_guard()
michael@0 173 # We do test cpp_guard here, so that histogram IDs are valid
michael@0 174 # indexes into this array.
michael@0 175 if cpp_guard:
michael@0 176 print "#if defined(%s)" % cpp_guard
michael@0 177 print "{ %d, %d }," % (offset, range_length)
michael@0 178 if cpp_guard:
michael@0 179 print "#endif"
michael@0 180 offset += range_length
michael@0 181 print "};"
michael@0 182 print "#endif"
michael@0 183
michael@0 184 def main(argv):
michael@0 185 filename = argv[0]
michael@0 186
michael@0 187 histograms = list(histogram_tools.from_file(filename))
michael@0 188
michael@0 189 print banner
michael@0 190 write_histogram_table(histograms)
michael@0 191 write_histogram_static_asserts(histograms)
michael@0 192 write_debug_histogram_ranges(histograms)
michael@0 193
michael@0 194 main(sys.argv[1:])

mercurial