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

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

mercurial