Chromium Code Reviews| Index: tracing/tracing/value/histogram.html |
| diff --git a/tracing/tracing/value/histogram.html b/tracing/tracing/value/histogram.html |
| index 7bc517f3095ba97579d0e4b3d5d4a31afea47223..93c4e836cc4b0eafd8383efd03d69109f14a70b7 100644 |
| --- a/tracing/tracing/value/histogram.html |
| +++ b/tracing/tracing/value/histogram.html |
| @@ -34,9 +34,10 @@ tr.exportTo('tr.v', function() { |
| /** |
| * Converts the given percent to a string in the format specified above. |
| * @param {number} percent The percent must be between 0.0 and 1.0. |
| + * @param {boolean=} opt_force3 Whether to force the result to be 3 chars long |
| * @return {string} |
| */ |
| - function percentToString(percent) { |
| + function percentToString(percent, opt_force3) { |
| if (percent < 0 || percent > 1) { |
| throw new Error('percent must be in [0,1]'); |
| } |
| @@ -48,7 +49,14 @@ tr.exportTo('tr.v', function() { |
| } |
| // Pad short strings with zeros. |
| str = str + '0'.repeat(Math.max(4 - str.length, 0)); |
| - if (str.length > 4) str = str.slice(0, 4) + '_' + str.slice(4); |
| + |
| + if (str.length > 4) { |
| + if (opt_force3) { |
| + str = str.slice(0, 4); |
| + } else { |
| + str = str.slice(0, 4) + '_' + str.slice(4); |
| + } |
| + } |
| return '0' + str.slice(2); |
| } |
| @@ -124,9 +132,9 @@ tr.exportTo('tr.v', function() { |
| ['nans', false], |
| ['std', true], |
|
tdresser
2017/05/11 21:03:12
Should std and avg be default? In the long term, i
benjhayden
2017/05/11 21:24:15
We have vague plans to redo the default statistics
|
| ['sum', true], |
| - // Don't include 'percentile' here. Its default value is [], which is |
| - // modifiable. Callers may push to it, so there must be a different Array |
| - // instance for each Histogram instance. |
| + // Don't include 'percentile' or 'iprs' here. Their default values are [], |
| + // which is mutable. Callers may push to it, so there must be a different |
| + // Array instance for each Histogram instance. |
| ]); |
| /** |
| @@ -174,6 +182,7 @@ tr.exportTo('tr.v', function() { |
| this.shortName = undefined; |
| this.summaryOptions = new Map(DEFAULT_SUMMARY_OPTIONS); |
| this.summaryOptions.set('percentile', []); |
| + this.summaryOptions.set('iprs', []); |
| this.unit = unit; |
| } |
| @@ -243,6 +252,12 @@ tr.exportTo('tr.v', function() { |
| hist.running_ = tr.b.math.RunningStatistics.fromDict(dict.running); |
| } |
| if (dict.summaryOptions) { |
| + if (dict.summaryOptions.iprs) { |
| + // Range.fromDict() requires isEmpty, which is unnecessarily verbose |
| + // for this use case. |
| + dict.summaryOptions.iprs = dict.summaryOptions.iprs.map( |
| + r => tr.b.math.Range.fromExplicitRange(r[0], r[1])); |
| + } |
| hist.customizeSummaryOptions(dict.summaryOptions); |
| } |
| if (dict.maxNumSampleValues !== undefined) { |
| @@ -511,11 +526,19 @@ tr.exportTo('tr.v', function() { |
| for (const [stat, option] of other.summaryOptions) { |
| if (stat === 'percentile') { |
| + const percentiles = this.summaryOptions.get(stat); |
| for (const percent of option) { |
| - const percentiles = this.summaryOptions.get(stat); |
| - if (percentiles.indexOf(percent) < 0) { |
| - percentiles.push(percent); |
| + if (!percentiles.includes(percent)) percentiles.push(percent); |
| + } |
| + } else if (stat === 'iprs') { |
| + const thisIprs = this.summaryOptions.get(stat); |
| + for (const ipr of option) { |
| + let found = false; |
| + for (const thisIpr of thisIprs) { |
| + found = ipr.equals(thisIpr); |
| + if (found) break; |
| } |
| + if (!found) thisIprs.push(ipr); |
| } |
| } else if (option && !this.summaryOptions.get(stat)) { |
| this.summaryOptions.set(stat, true); |
| @@ -537,6 +560,8 @@ tr.exportTo('tr.v', function() { |
| * @param {boolean=} summaryOptions.std |
| * @param {boolean=} summaryOptions.sum |
| * @param {!Array.<number>=} summaryOptions.percentile Numbers in (0,1) |
| + * @param {!Array.<!tr.b.Range>=} summaryOptions.iprs Ranges of numbers in |
| + * (0,1). |
| */ |
| customizeSummaryOptions(summaryOptions) { |
| for (const [key, value] of Object.entries(summaryOptions)) { |
| @@ -584,6 +609,16 @@ tr.exportTo('tr.v', function() { |
| const percentile = this.getApproximatePercentile(percent); |
| return new tr.b.Scalar(this.unit, percentile); |
| } |
| + if (statName.substr(0, 4) === 'ipr_') { |
| + let lower = percentFromString(statName.substr(4, 3)); |
| + let upper = percentFromString(statName.substr(8)); |
| + if (lower >= upper) { |
| + throw new Error('Invalid inter-percentile range: ' + statName); |
| + } |
| + lower = this.getApproximatePercentile(lower); |
| + upper = this.getApproximatePercentile(upper); |
| + return new tr.b.Scalar(this.unit, upper - lower); |
| + } |
| if (!this.canCompare(opt_referenceHistogram)) { |
| throw new Error( |
| @@ -640,6 +675,12 @@ tr.exportTo('tr.v', function() { |
| for (const pctile of option) { |
| statisticsNames.add('pct_' + tr.v.percentToString(pctile)); |
| } |
| + } else if (statName === 'iprs') { |
| + for (const range of option) { |
| + statisticsNames.add( |
| + 'ipr_' + tr.v.percentToString(range.min, true) + |
| + '_' + tr.v.percentToString(range.max, true)); |
| + } |
| } else if (option) { |
| statisticsNames.add(statName); |
| } |
| @@ -734,8 +775,8 @@ tr.exportTo('tr.v', function() { |
| this.binBoundariesDict_); |
| const hist = new Histogram(this.name, this.unit, binBoundaries); |
| for (const [stat, option] of this.summaryOptions) { |
| - // Copy arrays. |
| - if (stat === 'percentile') { |
| + // Copy arrays, but not ipr Ranges. |
| + if (stat === 'percentile' || stat === 'iprs') { |
|
tdresser
2017/05/11 21:03:12
It's not completely clear to me why these are excl
benjhayden
2017/05/11 21:24:15
Sorry, I'm not sure what you mean by "excluded".
p
tdresser
2017/05/12 12:31:17
Gotcha, this SGTM.
|
| hist.summaryOptions.set(stat, Array.from(option)); |
| } else { |
| hist.summaryOptions.set(stat, option); |
| @@ -815,10 +856,12 @@ tr.exportTo('tr.v', function() { |
| for (const [name, value] of this.summaryOptions) { |
| let option; |
| if (name === 'percentile') { |
| - if (value.length === 0) { |
| - continue; |
| - } |
| + if (value.length === 0) continue; |
| option = Array.from(value); |
| + } else if (name === 'iprs') { |
| + // Use a more compact JSON format than Range supports. |
| + if (value.length === 0) continue; |
| + option = value.map(r => [r.min, r.max]); |
| } else if (value === DEFAULT_SUMMARY_OPTIONS.get(name)) { |
| continue; |
| } else { |