diff options
Diffstat (limited to 'toolkit/components/telemetry/gen-histogram-data.py')
-rw-r--r-- | toolkit/components/telemetry/gen-histogram-data.py | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/gen-histogram-data.py b/toolkit/components/telemetry/gen-histogram-data.py new file mode 100644 index 000000000..8e227201d --- /dev/null +++ b/toolkit/components/telemetry/gen-histogram-data.py @@ -0,0 +1,178 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Write out histogram information for C++. The histograms are defined +# in a file provided as a command-line argument. + +from __future__ import print_function +from shared_telemetry_utils import StringTable, static_assert + +import sys +import histogram_tools +import itertools + +banner = """/* This file is auto-generated, see gen-histogram-data.py. */ +""" + +def print_array_entry(output, histogram, name_index, exp_index, label_index, label_count): + cpp_guard = histogram.cpp_guard() + if cpp_guard: + print("#if defined(%s)" % cpp_guard, file=output) + print(" { %s, %s, %s, %s, %d, %d, %s, %d, %d, %s }," \ + % (histogram.low(), + histogram.high(), + histogram.n_buckets(), + histogram.nsITelemetry_kind(), + name_index, + exp_index, + histogram.dataset(), + label_index, + label_count, + "true" if histogram.keyed() else "false"), file=output) + if cpp_guard: + print("#endif", file=output) + +def write_histogram_table(output, histograms): + string_table = StringTable() + label_table = [] + label_count = 0 + + print("const HistogramInfo gHistograms[] = {", file=output) + for histogram in histograms: + name_index = string_table.stringIndex(histogram.name()) + exp_index = string_table.stringIndex(histogram.expiration()) + + labels = histogram.labels() + label_index = 0 + if len(labels) > 0: + label_index = label_count + label_table.append((histogram.name(), string_table.stringIndexes(labels))) + label_count += len(labels) + + print_array_entry(output, histogram, + name_index, exp_index, + label_index, len(labels)) + print("};\n", file=output) + + strtab_name = "gHistogramStringTable" + string_table.writeDefinition(output, strtab_name) + static_assert(output, "sizeof(%s) <= UINT32_MAX" % strtab_name, + "index overflow") + + print("\nconst uint32_t gHistogramLabelTable[] = {", file=output) + for name,indexes in label_table: + print("/* %s */ %s," % (name, ", ".join(map(str, indexes))), file=output) + print("};", file=output) + + +# Write out static asserts for histogram data. We'd prefer to perform +# these checks in this script itself, but since several histograms +# (generally enumerated histograms) use compile-time constants for +# their upper bounds, we have to let the compiler do the checking. + +def static_asserts_for_boolean(output, histogram): + pass + +def static_asserts_for_flag(output, histogram): + pass + +def static_asserts_for_count(output, histogram): + pass + +def static_asserts_for_enumerated(output, histogram): + n_values = histogram.high() + static_assert(output, "%s > 2" % n_values, + "Not enough values for %s" % histogram.name()) + +def shared_static_asserts(output, histogram): + name = histogram.name() + low = histogram.low() + high = histogram.high() + n_buckets = histogram.n_buckets() + static_assert(output, "%s < %s" % (low, high), "low >= high for %s" % name) + static_assert(output, "%s > 2" % n_buckets, "Not enough values for %s" % name) + static_assert(output, "%s >= 1" % low, "Incorrect low value for %s" % name) + static_assert(output, "%s > %s" % (high, n_buckets), + "high must be > number of buckets for %s; you may want an enumerated histogram" % name) + +def static_asserts_for_linear(output, histogram): + shared_static_asserts(output, histogram) + +def static_asserts_for_exponential(output, histogram): + shared_static_asserts(output, histogram) + +def write_histogram_static_asserts(output, histograms): + print(""" +// Perform the checks at the beginning of HistogramGet at +// compile time, so that incorrect histogram definitions +// give compile-time errors, not runtime errors.""", file=output) + + table = { + 'boolean' : static_asserts_for_boolean, + 'flag' : static_asserts_for_flag, + 'count': static_asserts_for_count, + 'enumerated' : static_asserts_for_enumerated, + 'categorical' : static_asserts_for_enumerated, + 'linear' : static_asserts_for_linear, + 'exponential' : static_asserts_for_exponential, + } + + for histogram in histograms: + histogram_tools.table_dispatch(histogram.kind(), table, + lambda f: f(output, histogram)) + +def write_debug_histogram_ranges(output, histograms): + ranges_lengths = [] + + # Collect all the range information from individual histograms. + # Write that information out as well. + print("#ifdef DEBUG", file=output) + print("const int gBucketLowerBounds[] = {", file=output) + for histogram in histograms: + ranges = [] + try: + ranges = histogram.ranges() + except histogram_tools.DefinitionException: + pass + ranges_lengths.append(len(ranges)) + # Note that we do not test cpp_guard here. We do this so we + # will have complete information about all the histograms in + # this array. Just having information about the ranges of + # histograms is not platform-specific; if there are histograms + # that have platform-specific constants in their definitions, + # those histograms will fail in the .ranges() call above and + # we'll have a zero-length array to deal with here. + if len(ranges) > 0: + print(','.join(map(str, ranges)), ',', file=output) + else: + print('/* Skipping %s */' % histogram.name(), file=output) + print("};", file=output) + + # Write the offsets into gBucketLowerBounds. + print("struct bounds { int offset; int length; };", file=output) + print("const struct bounds gBucketLowerBoundIndex[] = {", file=output) + offset = 0 + for (histogram, range_length) in itertools.izip(histograms, ranges_lengths): + cpp_guard = histogram.cpp_guard() + # We do test cpp_guard here, so that histogram IDs are valid + # indexes into this array. + if cpp_guard: + print("#if defined(%s)" % cpp_guard, file=output) + print("{ %d, %d }," % (offset, range_length), file=output) + if cpp_guard: + print("#endif", file=output) + offset += range_length + print("};", file=output) + print("#endif", file=output) + +def main(output, *filenames): + histograms = list(histogram_tools.from_files(filenames)) + + print(banner, file=output) + write_histogram_table(output, histograms) + write_histogram_static_asserts(output, histograms) + write_debug_histogram_ranges(output, histograms) + +if __name__ == '__main__': + main(sys.stdout, *sys.argv[1:]) |