Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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:]) |