Bug 748444 - eliminate relocations from histogram data; r=taras
authorNathan Froyd <froydnj@mozilla.com>
Tue, 28 Aug 2012 12:55:32 -0400
changeset 103797 a8b7d2524e94
parent 103796 3e9ed1fd45b9
child 103798 982d02faef3f
push id14171
push usernfroyd@mozilla.com
push date2012-08-29 19:17 +0000
treeherdermozilla-inbound@a8b7d2524e94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstaras
bugs748444
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 748444 - eliminate relocations from histogram data; r=taras
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/gen-histogram-data.py
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -182,27 +182,42 @@ private:
 
 TelemetryImpl*  TelemetryImpl::sTelemetry = NULL;
 
 // A initializer to initialize histogram collection
 StatisticsRecorder gStatisticsRecorder;
 
 // Hardcoded probes
 struct TelemetryHistogram {
-  const char *id;
   uint32_t min;
   uint32_t max;
   uint32_t bucketCount;
   uint32_t histogramType;
-  const char *comment;
+  uint16_t id_offset;
+  uint16_t comment_offset;
+
+  const char *id() const;
+  const char *comment() const;
 };
 
 #include "TelemetryHistogramData.inc"
 bool gCorruptHistograms[Telemetry::HistogramCount];
 
+const char *
+TelemetryHistogram::id() const
+{
+  return &gHistogramStringTable[this->id_offset];
+}
+
+const char *
+TelemetryHistogram::comment() const
+{
+  return &gHistogramStringTable[this->comment_offset];
+}
+
 bool
 TelemetryHistogramType(Histogram *h, uint32_t *result)
 {
   switch (h->histogram_type()) {
   case Histogram::HISTOGRAM:
     *result = nsITelemetry::HISTOGRAM_EXPONENTIAL;
     break;
   case Histogram::LINEAR_HISTOGRAM:
@@ -263,17 +278,17 @@ GetHistogramByEnumId(Telemetry::ID id, H
   static Histogram* knownHistograms[Telemetry::HistogramCount] = {0};
   Histogram *h = knownHistograms[id];
   if (h) {
     *ret = h;
     return NS_OK;
   }
 
   const TelemetryHistogram &p = gHistograms[id];
-  nsresult rv = HistogramGet(p.id, p.min, p.max, p.bucketCount, p.histogramType, &h);
+  nsresult rv = HistogramGet(p.id(), p.min, p.max, p.bucketCount, p.histogramType, &h);
   if (NS_FAILED(rv))
     return rv;
 
 #ifdef DEBUG
   // Check that the C++ Histogram code computes the same ranges as the
   // Python histogram code.
   const struct bounds &b = gBucketLowerBoundIndex[id];
   if (b.length != 0) {
@@ -580,17 +595,17 @@ TelemetryImpl::GetHistogramEnumId(const 
     return NS_ERROR_FAILURE;
   }
 
   // Cache names
   // Note the histogram names are statically allocated
   TelemetryImpl::HistogramMapType *map = &sTelemetry->mHistogramMap;
   if (!map->Count()) {
     for (uint32_t i = 0; i < Telemetry::HistogramCount; i++) {
-      CharPtrEntryType *entry = map->PutEntry(gHistograms[i].id);
+      CharPtrEntryType *entry = map->PutEntry(gHistograms[i].id());
       if (NS_UNLIKELY(!entry)) {
         map->Clear();
         return NS_ERROR_OUT_OF_MEMORY;
       }
       entry->mData = (Telemetry::ID) i;
     }
   }
 
@@ -1148,20 +1163,20 @@ TelemetryImpl::GetRegisteredHistograms(J
 {
   size_t count = ArrayLength(gHistograms);
   JSObject *info = JS_NewObject(cx, NULL, NULL, NULL);
   if (!info)
     return NS_ERROR_FAILURE;
   JS::AutoObjectRooter root(cx, info);
 
   for (size_t i = 0; i < count; ++i) {
-    JSString *comment = JS_InternString(cx, gHistograms[i].comment);
+    JSString *comment = JS_InternString(cx, gHistograms[i].comment());
     
     if (!(comment
-          && JS_DefineProperty(cx, info, gHistograms[i].id,
+          && JS_DefineProperty(cx, info, gHistograms[i].id(),
                                STRING_TO_JSVAL(comment), NULL, NULL,
                                JSPROP_ENUMERATE))) {
       return NS_ERROR_FAILURE;
     }
   }
 
   *ret = OBJECT_TO_JSVAL(info);
   return NS_OK;
--- a/toolkit/components/telemetry/gen-histogram-data.py
+++ b/toolkit/components/telemetry/gen-histogram-data.py
@@ -11,32 +11,77 @@ import sys
 import histogram_tools
 import itertools
 
 banner = """/* This file is auto-generated, see gen-histogram-data.py.  */
 """
 
 # Write out the gHistograms array.
 
-def print_array_entry(histogram):
+class StringTable:
+    def __init__(self):
+        self.current_index = 0;
+        self.table = {}
+
+    def c_strlen(self, string):
+        return len(string) + 1
+
+    def stringIndex(self, string):
+        if string in self.table:
+            return self.table[string]
+        else:
+            result = self.current_index
+            self.table[string] = result
+            self.current_index += self.c_strlen(string)
+            return result
+
+    def writeDefinition(self, f, name):
+        entries = self.table.items()
+        entries.sort(key=lambda x:x[1])
+        # Avoid null-in-string warnings with GCC and potentially
+        # overlong string constants; write everything out the long way.
+        def explodeToCharArray(string):
+            def toCChar(s):
+                if s == "'":
+                    return "'\\''"
+                else:
+                    return "'%s'" % s
+            return ", ".join(map(toCChar, string))
+        f.write("const char %s[] = {\n" % name)
+        for (string, offset) in entries[:-1]:
+            f.write("  /* %5d */ %s, '\\0',\n"
+                    % (offset, explodeToCharArray(string)))
+        f.write("  /* %5d */ %s, '\\0' };\n\n"
+                % (entries[-1][1], explodeToCharArray(entries[-1][0])))
+
+def print_array_entry(histogram, name_index, desc_index):
     cpp_guard = histogram.cpp_guard()
     if cpp_guard:
         print "#if defined(%s)" % cpp_guard
-    print "  { \"%s\", %s, %s, %s, %s, \"%s\" }," \
-        % (histogram.name(), histogram.low(), histogram.high(),
+    print "  { %s, %s, %s, %s, %d, %d }," \
+        % (histogram.low(), histogram.high(),
            histogram.n_buckets(), histogram.nsITelemetry_kind(),
-           histogram.description())
+           name_index, desc_index)
     if cpp_guard:
         print "#endif"
 
 def write_histogram_table(histograms):
+    table = StringTable()
+
     print "const TelemetryHistogram gHistograms[] = {"
     for histogram in histograms:
-        print_array_entry(histogram)
+        name_index = table.stringIndex(histogram.name())
+        desc_index = table.stringIndex(histogram.description())
+        print_array_entry(histogram, name_index, desc_index)
     print "};"
+
+    strtab_name = "gHistogramStringTable"
+    table.writeDefinition(sys.stdout, strtab_name)
+    static_assert("sizeof(%s) <= UINT16_MAX" % strtab_name,
+                  "index overflow")
 
 # 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_assert(expression, message):
     print "MOZ_STATIC_ASSERT(%s, \"%s\");" % (expression, message)