diff --git a/toolkit/content/aboutTelemetry.js b/toolkit/content/aboutTelemetry.js index 591cb3aba24..6eceb8eed37 100644 --- a/toolkit/content/aboutTelemetry.js +++ b/toolkit/content/aboutTelemetry.js @@ -1126,11 +1126,11 @@ var ThreadHangStats = { // Don't localize the histogram name, because the // name is also used as the div element's ID Histogram.render(div, aThread.name + "-Activity", - aThread.activity, {exponential: true}); + aThread.activity, {exponential: true}, true); aThread.hangs.forEach((hang, index) => { let hangName = aThread.name + "-Hang-" + (index + 1); let hangDiv = Histogram.render( - div, hangName, hang.histogram, {exponential: true}); + div, hangName, hang.histogram, {exponential: true}, true); let stackDiv = document.createElement("div"); let stack = hang.nativeStack || hang.stack; stack.forEach((frame) => { @@ -1163,10 +1163,11 @@ var Histogram = { * @param aHgram Histogram information * @param aOptions Object with render options * * exponential: bars follow logarithmic scale + * @param aIsBHR whether or not requires fixing the labels for TimeHistogram */ - render: function Histogram_render(aParent, aName, aHgram, aOptions) { + render: function Histogram_render(aParent, aName, aHgram, aOptions, aIsBHR) { let options = aOptions || {}; - let hgram = this.processHistogram(aHgram, aName); + let hgram = this.processHistogram(aHgram, aName, aIsBHR); let outerDiv = document.createElement("div"); outerDiv.className = "histogram"; @@ -1207,7 +1208,7 @@ var Histogram = { return outerDiv; }, - processHistogram: function(aHgram, aName) { + processHistogram: function(aHgram, aName, aIsBHR) { const values = Object.keys(aHgram.values).map(k => aHgram.values[k]); if (!values.length) { // If we have no values collected for this histogram, just return @@ -1225,7 +1226,27 @@ var Histogram = { const average = Math.round(aHgram.sum * 10 / sample_count) / 10; const max_value = Math.max(...values); - const labelledValues = Object.keys(aHgram.values).map(k => [Number(k), aHgram.values[k]]); + function labelFunc(k) { + // - BHR histograms are TimeHistograms: Exactly power-of-two buckets (from 0) + // (buckets: [0..1], [2..3], [4..7], [8..15], ... note the 0..1 anomaly - same bucket) + // - TimeHistogram's JS representation adds a dummy (empty) "0" bucket, and + // the rest of the buckets have the label as the upper value of the + // bucket (non TimeHistograms have the lower value of the bucket as label). + // So JS TimeHistograms bucket labels are: 0 (dummy), 1, 3, 7, 15, ... + // - see toolkit/components/telemetry/Telemetry.cpp + // (CreateJSTimeHistogram, CreateJSThreadHangStats, CreateJSHangHistogram) + // - see toolkit/components/telemetry/ThreadHangStats.h + // Fix BHR labels to the "standard" format for about:telemetry as follows: + // - The dummy 0 label+bucket will be filtered before arriving here + // - If it's 1 -> manually correct it to 0 (the 0..1 anomaly) + // - For the rest, set the label as the bottom value instead of the upper. + // --> so we'll end with the following (non dummy) labels: 0, 2, 4, 8, 16, ... + return !aIsBHR ? k : k == 1 ? 0 : (k + 1) / 2; + } + + const labelledValues = Object.keys(aHgram.values) + .filter(label => !aIsBHR || Number(label) != 0) // remove dummy 0 label for BHR + .map(k => [labelFunc(Number(k)), aHgram.values[k]]); let result = { values: labelledValues,