mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1714100 - Add an Intl.DateTimeFormat microbenchmark;r=dminor,nordzilla
Differential Revision: https://phabricator.services.mozilla.com/D116657
This commit is contained in:
parent
1a7c5a8df1
commit
a40da379a7
9
intl/benchmarks/.eslintrc.js
Normal file
9
intl/benchmarks/.eslintrc.js
Normal file
@ -0,0 +1,9 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
extends: ["plugin:mozilla/xpcshell-test"],
|
||||
};
|
20
intl/benchmarks/README.md
Normal file
20
intl/benchmarks/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Intl Performance Microbenchmarks
|
||||
|
||||
This folder contains micro benchmarks using the [mozperftest][] suite.
|
||||
|
||||
[mozperftest](https://firefox-source-docs.mozilla.org/testing/perfdocs/mozperftest.html)
|
||||
|
||||
## Recording profiles for the Firefox Profiler
|
||||
|
||||
```sh
|
||||
# Run the perftest as an xpcshell test.
|
||||
MOZ_PROFILER_STARTUP=1 \
|
||||
MOZ_PROFILER_SHUTDOWN=/path/to/perf-profile.json \
|
||||
./mach xpcshell-test intl/benchmarks/perftest_dateTimeFormat.js
|
||||
|
||||
# Install the profiler-symbol-server tool.
|
||||
cargo install profiler-symbol-server
|
||||
|
||||
# Open the path to the file.
|
||||
profiler-symbol-server --open /path/to/perf-profile.json
|
||||
```
|
131
intl/benchmarks/head.js
Normal file
131
intl/benchmarks/head.js
Normal file
@ -0,0 +1,131 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* Create an interface to measure iterations for a micro benchmark. These iterations
|
||||
* will then be reported to the perftest runner.
|
||||
*
|
||||
* @param {string} metricName
|
||||
*/
|
||||
function measureIterations(metricName) {
|
||||
let accumulatedTime = 0;
|
||||
let iterations = 0;
|
||||
let now = 0;
|
||||
return {
|
||||
/**
|
||||
* Start a measurement.
|
||||
*/
|
||||
start() {
|
||||
now = Cu.now();
|
||||
},
|
||||
/**
|
||||
* Stop a measurement, and record the elapsed time.
|
||||
*/
|
||||
stop() {
|
||||
accumulatedTime += Cu.now() - now;
|
||||
iterations++;
|
||||
},
|
||||
/**
|
||||
* Report the metrics to perftest after finishing the microbenchmark.
|
||||
*/
|
||||
reportMetrics() {
|
||||
const metrics = {};
|
||||
metrics[metricName + " iterations"] = iterations;
|
||||
metrics[metricName + " accumulatedTime"] = accumulatedTime;
|
||||
metrics[metricName + " perCallTime"] = accumulatedTime / iterations;
|
||||
|
||||
info("perfMetrics", metrics);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
let _seed = 123456;
|
||||
/**
|
||||
* A cheap and simple pseudo-random number generator that avoids adding new dependencies.
|
||||
* This function ensures tests are repeatable, but can be fed random configurations.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Linear_congruential_generator
|
||||
*
|
||||
* It has the following distribution for the first 100,000 runs:
|
||||
*
|
||||
* 0.0 - 0.1: 9948
|
||||
* 0.1 - 0.2: 10037
|
||||
* 0.2 - 0.3: 10049
|
||||
* 0.3 - 0.4: 10041
|
||||
* 0.4 - 0.5: 10036
|
||||
* 0.5 - 0.6: 10085
|
||||
* 0.6 - 0.7: 9987
|
||||
* 0.7 - 0.8: 9872
|
||||
* 0.8 - 0.9: 10007
|
||||
* 0.9 - 1.0: 9938
|
||||
*
|
||||
* @returns {number} float values ranged 0-1
|
||||
*/
|
||||
function prng() {
|
||||
_seed = Math.imul(_seed, 22695477) + 1;
|
||||
return (_seed >> 1) / 0x7fffffff + 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distribution of locales. The number represents the ratio of total users in that
|
||||
* locale. The numbers should add up to ~1.0.
|
||||
*
|
||||
* https://sql.telemetry.mozilla.org/dashboard/firefox-localization
|
||||
*/
|
||||
const localeDistribution = {
|
||||
"en-US": 0.373,
|
||||
de: 0.129,
|
||||
fr: 0.084,
|
||||
"zh-CN": 0.053,
|
||||
ru: 0.048,
|
||||
"es-ES": 0.047,
|
||||
pl: 0.041,
|
||||
"pt-BR": 0.034,
|
||||
it: 0.028,
|
||||
"en-GB": 0.027,
|
||||
ja: 0.019,
|
||||
"es-MX": 0.014,
|
||||
nl: 0.01,
|
||||
cs: 0.009,
|
||||
hu: 0.008,
|
||||
id: 0.006,
|
||||
"en-CA": 0.006,
|
||||
"es-AR": 0.006,
|
||||
tr: 0.005,
|
||||
el: 0.005,
|
||||
"zh-TW": 0.005,
|
||||
fi: 0.005,
|
||||
"sv-SE": 0.004,
|
||||
"pt-PT": 0.004,
|
||||
sk: 0.003,
|
||||
ar: 0.003,
|
||||
vi: 0.003,
|
||||
"es-CL": 0.002,
|
||||
th: 0.002,
|
||||
da: 0.002,
|
||||
bg: 0.002,
|
||||
ro: 0.002,
|
||||
"nb-NO": 0.002,
|
||||
ko: 0.002,
|
||||
};
|
||||
|
||||
/**
|
||||
* Go through the top Firefox locales, and pick one at random that is representative
|
||||
* of the Firefox population as of 2021-06-03. It uses a pseudo-random number generator
|
||||
* to make the results repeatable.
|
||||
*
|
||||
* @returns {string} locale
|
||||
*/
|
||||
function pickRepresentativeLocale() {
|
||||
const n = prng();
|
||||
let ratio = 1;
|
||||
for (const [locale, representation] of Object.entries(localeDistribution)) {
|
||||
ratio -= representation;
|
||||
if (n > ratio) {
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
// In case we fall through the "for" loop, return the most common locale.
|
||||
return "en-US";
|
||||
}
|
1
intl/benchmarks/perftest.ini
Normal file
1
intl/benchmarks/perftest.ini
Normal file
@ -0,0 +1 @@
|
||||
[perftest_dateTimeFormat.js]
|
122
intl/benchmarks/perftest_dateTimeFormat.js
Normal file
122
intl/benchmarks/perftest_dateTimeFormat.js
Normal file
@ -0,0 +1,122 @@
|
||||
/* 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/. */
|
||||
// @ts-check
|
||||
|
||||
var perfMetadata = {
|
||||
owner: "Internationalization Team",
|
||||
name: "Intl.DateTimeFormat",
|
||||
description: "Test the speed of the Intl.DateTimeFormat implementation.",
|
||||
options: {
|
||||
default: {
|
||||
perfherder: true,
|
||||
perfherder_metrics: [
|
||||
{
|
||||
name: "Intl.DateTimeFormat constructor iterations",
|
||||
unit: "iterations",
|
||||
},
|
||||
{ name: "Intl.DateTimeFormat constructor accumulatedTime", unit: "ms" },
|
||||
{ name: "Intl.DateTimeFormat constructor perCallTime", unit: "ms" },
|
||||
|
||||
{
|
||||
name: "Intl.DateTimeFormat.prototype.format iterations",
|
||||
unit: "iterations",
|
||||
},
|
||||
{
|
||||
name: "Intl.DateTimeFormat.prototype.format accumulatedTime",
|
||||
unit: "ms",
|
||||
},
|
||||
{
|
||||
name: "Intl.DateTimeFormat.prototype.format perCallTime",
|
||||
unit: "ms",
|
||||
},
|
||||
],
|
||||
verbose: true,
|
||||
},
|
||||
},
|
||||
tags: ["intl", "ecma402"],
|
||||
};
|
||||
|
||||
add_task(function measure_date() {
|
||||
const measureConstructor = measureIterations(
|
||||
"Intl.DateTimeFormat constructor"
|
||||
);
|
||||
const measureFormat = measureIterations(
|
||||
"Intl.DateTimeFormat.prototype.format"
|
||||
);
|
||||
|
||||
// Re-use the config between runs.
|
||||
|
||||
const fieldOptions = {
|
||||
weekday: ["narrow", "short", "long"],
|
||||
era: ["narrow", "short", "long"],
|
||||
year: ["2-digit", "numeric"],
|
||||
month: ["2-digit", "numeric", "narrow", "short", "long"],
|
||||
day: ["2-digit", "numeric"],
|
||||
hour: ["2-digit", "numeric"],
|
||||
minute: ["2-digit", "numeric"],
|
||||
second: ["2-digit", "numeric"],
|
||||
timeZoneName: ["short", "long"],
|
||||
};
|
||||
|
||||
const config = {};
|
||||
function randomizeConfig(name, chance) {
|
||||
const option = fieldOptions[name];
|
||||
if (prng() < chance) {
|
||||
config[name] = option[Math.floor(option.length * prng())];
|
||||
} else {
|
||||
delete config[name];
|
||||
}
|
||||
}
|
||||
|
||||
let date = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
|
||||
|
||||
// Split each step of the benchmark into separate JS functions so that performance
|
||||
// profiles are easy to analyze.
|
||||
|
||||
function benchmarkDateTimeFormatConstructor() {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
// Create a random configuration powered by a pseudo-random number generator. This
|
||||
// way the configurations will be the same between 2 different runs.
|
||||
const locale = pickRepresentativeLocale();
|
||||
randomizeConfig("year", 0.5);
|
||||
randomizeConfig("month", 0.5);
|
||||
randomizeConfig("day", 0.5);
|
||||
randomizeConfig("hour", 0.5);
|
||||
randomizeConfig("minute", 0.5);
|
||||
// Set the following to some lower probabilities:
|
||||
randomizeConfig("second", 0.2);
|
||||
randomizeConfig("timeZoneName", 0.2);
|
||||
randomizeConfig("weekday", 0.2);
|
||||
randomizeConfig("era", 0.1);
|
||||
|
||||
// Measure the constructor.
|
||||
measureConstructor.start();
|
||||
const formatter = Intl.DateTimeFormat(locale, config);
|
||||
// Also include one format operation to ensure the constructor is de-lazified.
|
||||
formatter.format(date);
|
||||
measureConstructor.stop();
|
||||
|
||||
benchmarkFormatOperation(formatter);
|
||||
}
|
||||
}
|
||||
|
||||
const start = Date.UTC(2000);
|
||||
const end = Date.UTC(2030);
|
||||
const dateDiff = end - start;
|
||||
function benchmarkFormatOperation(formatter) {
|
||||
// Measure the format operation.
|
||||
for (let j = 0; j < 100; j++) {
|
||||
date = new Date(start + prng() * dateDiff);
|
||||
measureFormat.start();
|
||||
formatter.format(date);
|
||||
measureFormat.stop();
|
||||
}
|
||||
}
|
||||
|
||||
benchmarkDateTimeFormatConstructor();
|
||||
measureConstructor.reportMetrics();
|
||||
measureFormat.reportMetrics();
|
||||
|
||||
ok(true);
|
||||
});
|
8
intl/benchmarks/xpcshell.ini
Normal file
8
intl/benchmarks/xpcshell.ini
Normal file
@ -0,0 +1,8 @@
|
||||
[DEFAULT]
|
||||
head = head.js
|
||||
|
||||
# Add perftests here as it's useful to run them as xpcshell tests, but we don't need them
|
||||
# to be run in CI.
|
||||
|
||||
[perftest_dateTimeFormat.js]
|
||||
skip-if = true
|
@ -37,6 +37,10 @@ EXPORTS += [
|
||||
"../third_party/rust/shift_or_euc_c/include/shift_or_euc.h",
|
||||
]
|
||||
|
||||
|
||||
PERFTESTS_MANIFESTS += ["benchmarks/perftest.ini"]
|
||||
XPCSHELL_TESTS_MANIFESTS += ["benchmarks/xpcshell.ini"]
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Internationalization")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user