From 00de2ae85cca0d0125c91d577a30ea3a87dc6419 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Mon, 18 Aug 2025 12:06:47 +0200 Subject: [PATCH 1/9] adding intl test --- JetStreamDriver.js | 9 ++ intl/benchmark.js | 344 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 intl/benchmark.js diff --git a/JetStreamDriver.js b/JetStreamDriver.js index eaf430e5..3f2f0c45 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -2522,6 +2522,15 @@ let BENCHMARKS = [ iterations: 15, worstCaseCount: 2, tags: ["Default", "Wasm", "dotnet"], + }), + new AsyncBenchmark({ + name: "intl", + files: [ + "./intl/benchmark.js", + ], + iterations: 15, + worstCaseCount: 2, + tags: ["Default", "Javascript", "int"], }) ]; diff --git a/intl/benchmark.js b/intl/benchmark.js new file mode 100644 index 00000000..99714b2d --- /dev/null +++ b/intl/benchmark.js @@ -0,0 +1,344 @@ +function shuffleOptions(optionsGenerator) { + const options = Array.from(optionsGenerator()); + for (let i = options.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [options[i], options[j]] = [options[j], options[i]]; + } + return options; +} + +const LOCALES = [ + "ar-SA", + "zh-CN", + "zh-TW", + "da-DK", + "en-US", + "en-GB", + "en-CA", + "en-AU", + "fr-FR", + "fr-CA", + "de-DE", + "hi-IN", + "it-IT", + "ja-JP", + "ko-KR", + "pt-BR", + "pt-PT", + "ru-RU", + "es-ES", + "es-MX", + "sw-KE", + "sv-SE", + "th-TH", + "tr-TR", + "vi-VN", +]; + +globalThis.console ??= {}; +console.log ??= (...args) => print(...args); + +function generateRandomDates(count) { + const firstDate = new Date(1800, 11, 5, 13, 6); + let currentTimeStamp = firstDate.getTime(); + const dates = []; + + for (let i = 0; i < count; i++) { + dates.push(new Date(currentTimeStamp)); + currentTimeStamp += 1234569; + } + return dates; +} + +const DATE_STYLE_OPTIONS = ["full", "long", "medium", "short"]; +const TIME_STYLE_OPTIONS = ["full", "long", "medium", "short"]; + +function* dateTimeFormatOptions() { + for (const locale of LOCALES) { + for (const dateStyle of DATE_STYLE_OPTIONS) { + for (const timeStyle of TIME_STYLE_OPTIONS) { + yield { locale, dateStyle, timeStyle }; + } + } + } +} + +function DateTimeFormatPerformanceTest() { + let totalLength = 0; + let lastFormatResult; + let lastFormatPartResult; + let lastFormatRangeResult; + const dates = generateRandomDates(100); + let dateIndex = 0; + + const FORMAT_COUNT = 17; + const FORMAT_RANGE_COUNT = 7; + for (const { locale, dateStyle, timeStyle } of shuffleOptions( + dateTimeFormatOptions + )) { + const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle }); + for (let i = 0; i < FORMAT_COUNT; i++) { + let date = dates[dateIndex % dates.length]; + lastFormatResult = formatter.format(date); + totalLength += lastFormatResult.length; + dateIndex++; + + date = dates[dateIndex % dates.length]; + lastFormatPartResult = formatter.formatToParts(date); + for (const part of lastFormatPartResult) { + totalLength += part.value.length; + } + dateIndex++; + } + let dateRangeStart = dates[0]; + for (let i = 0; i < FORMAT_RANGE_COUNT; i++) { + const date = dates[dateIndex % dates.length]; + if (dateRangeStart < date) + lastFormatRangeResult = formatter.formatRange(dateRangeStart, date); + dateRangeStart = date; + } + } + return {lastResult: lastFormatResult + lastFormatRangeResult, totalLength}; +} + +const LISTS = [ + ["One"], + ["1", "2"], + ["Motorcycle", "Bus", "Car"], + LOCALES, + new Array(100).fill(9).map((_, index) => index.toString()), +]; + +function* listOptions() { + const styleOptions = ["long", "short", "narrow"]; + const typeOptions = ["conjunction", "disjunction", "unit"]; + for (const locale of LOCALES) { + for (const style of styleOptions) { + for (const type of typeOptions) { + yield { locale, style, type }; + } + } + } +} + +function ListFormatPerformanceTest() { + let lastResult; + let totalLength = 0; + const LIST_FORMAT_COUNT = 10; + let listIndex = 0; + for (const { locale, style, type } of shuffleOptions(listOptions)) { + const formatter = new Intl.ListFormat(locale, { style, type }); + for (let i = 0; i < LIST_FORMAT_COUNT; i++) { + const list = LISTS[listIndex % LISTS.length]; + listIndex++; + lastResult = formatter.format(list); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(list); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} + +const UNITS = [ + "year", + "quarter", + "month", + "week", + "day", + "hour", + "minute", + "second", +]; + +function* relativeTimeFormatOptions() { + const styleOptions = ["long", "short", "narrow"]; + const numericOptions = ["always", "auto"]; + for (const locale of LOCALES) { + for (const style of styleOptions) { + for (const numeric of numericOptions) { + yield { locale, style, numeric }; + } + } + } +} + +function RelativeTimeFormatPerformanceTest() { + let lastResult; + let totalLength = 0; + const RELATIVE_TIME_FORMAT_COUNT = 100; + let unitIndex = 0; + for (const { locale, style, numeric } of shuffleOptions( + relativeTimeFormatOptions + )) { + const formatter = new Intl.RelativeTimeFormat(locale, { style, numeric }); + for (let i = 0; i < RELATIVE_TIME_FORMAT_COUNT; i++) { + const unit = UNITS[unitIndex % UNITS.length]; + unitIndex++; + const value = Math.random() * 100 - 50; + lastResult = formatter.format(value, unit); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(value, unit); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} + +const CURRENCIES = [ + "USD", + "EUR", + "JPY", + "INR", + "NGN", +]; + +const NUMBER_UNITS = [ + "acre", + "bit", + "byte", + "celsius", + "centimeter", + "day", + "degree", + "fahrenheit", + "fluid-ounce", + "foot", + "gallon", + "gigabit", + "gigabyte", + "gram", + "hectare", + "hour", + "inch", + "kilobit", + "kilobyte", + "kilogram", + "kilometer", + "liter", + "megabit", + "megabyte", + "meter", + "microsecond", + "mile", + "mile-scandinavian", + "milliliter", + "millimeter", + "millisecond", + "minute", + "month", + "nanosecond", + "ounce", + "percent", + "petabyte", + "pound", + "second", + "stone", + "terabit", + "terabyte", + "week", + "yard", + "year", +]; + +function* numberFormatOptions() { + const currencyDisplayOptions = ["symbol", "narrowSymbol", "code", "name"]; + const unitDisplayOptions = ["short", "long", "narrow"]; + + for (const locale of LOCALES) { + for (const currency of CURRENCIES) { + for (const currencyDisplay of currencyDisplayOptions) { + yield { locale, style: "currency", currency, currencyDisplay }; + } + } + for (const unit of NUMBER_UNITS.slice(0, 20)) { + for (const unitDisplay of unitDisplayOptions) { + yield { locale, style: "unit", unit, unitDisplay }; + } + } + yield { locale, style: "decimal" }; + yield { locale, style: "percent" }; + } +} + +function NumberFormatPerformanceTest() { + let lastResult; + let totalLength = 0; + const NUMBER_FORMAT_COUNT = 10; + for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { + const formatter = new Intl.NumberFormat(options.locale, options); + for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { + const value = Math.random() * 10_000; + lastResult = formatter.format(value); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(value); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} + +function* pluralRulesOptions() { + const typeOptions = ["cardinal", "ordinal"]; + for (const locale of LOCALES) { + for (const type of typeOptions) { + yield { locale, type }; + } + } +} + +function PluralRulesPerformanceTest() { + let lastResult; + let totalLength = 0; + const PLURAL_RULES_COUNT = 1000; + for (const { locale, type } of shuffleOptions(pluralRulesOptions)) { + const formatter = new Intl.PluralRules(locale, { type }); + let i = 0; + for (let value = 0; value < 4; value++) { + lastResult = formatter.select(value); + totalLength += lastResult.length; + i++; + } + for (; i < PLURAL_RULES_COUNT; i++) { + const value = Math.floor(Math.random() * 1000); + lastResult = formatter.select(value); + totalLength += lastResult.length; + } + } + return {lastResult, totalLength}; +} + +class Benchmark { + measureItems = false + lastResult; + totalLength = 0; + + runIteration() { + this.run(DateTimeFormatPerformanceTest); + this.run(ListFormatPerformanceTest); + this.run(RelativeTimeFormatPerformanceTest); + this.run(NumberFormatPerformanceTest); + this.run(PluralRulesPerformanceTest); + } + + run(fn) { + let result; + if (!this.measureItems) { + result = fn(); + } else { + const start = performance.now(); + result = fn(); + const end = performance.now(); + console.log(` ${fn.name}: ${(end - start).toFixed(2)}ms`); + } + const {lastResult, totalLength} = result; + this.lastResult = lastResult; + this.totalLength += totalLength; + } +} From db0182e05ecfbe6616e8e53eaa68d1ab0e6cc6c8 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Wed, 20 Aug 2025 13:26:38 +0200 Subject: [PATCH 2/9] separate files --- JetStreamDriver.js | 32 +++- intl/benchmark.js | 335 +-------------------------------- intl/src/DateTimeFormat.js | 63 +++++++ intl/src/ListFormat.js | 40 ++++ intl/src/NumberFormat.js | 96 ++++++++++ intl/src/PluralRules.js | 30 +++ intl/src/RelativeTimeFormat.js | 46 +++++ intl/src/helper.js | 39 ++++ 8 files changed, 343 insertions(+), 338 deletions(-) create mode 100644 intl/src/DateTimeFormat.js create mode 100644 intl/src/ListFormat.js create mode 100644 intl/src/NumberFormat.js create mode 100644 intl/src/PluralRules.js create mode 100644 intl/src/RelativeTimeFormat.js create mode 100644 intl/src/helper.js diff --git a/JetStreamDriver.js b/JetStreamDriver.js index 3f2f0c45..9803c2f8 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -2523,16 +2523,38 @@ let BENCHMARKS = [ worstCaseCount: 2, tags: ["Default", "Wasm", "dotnet"], }), - new AsyncBenchmark({ - name: "intl", + +]; + + +const INTL_TESTS = [ + "DateTimeFormat", + "ListFormat", + "RelativeTimeFormat", + "NumberFormat", + "PluralRules", +]; +const INTL_BENCHMARKS = []; +for (const test of INTL_TESTS) { + const benchmark = new AsyncBenchmark({ + name: `${test}-intl`, files: [ + "./intl/src/helper.js", + `./intl/src/${test}.js`, "./intl/benchmark.js", ], iterations: 15, worstCaseCount: 2, - tags: ["Default", "Javascript", "int"], - }) -]; + tags: ["Javascript", "int"], + }); + INTL_BENCHMARKS.push(benchmark); +} +BENCHMARKS.push( + new GroupedBenchmark({ + name: "intl", + tags: ["Default", "Javascript", "int"], + }, INTL_BENCHMARKS)); + // SunSpider tests diff --git a/intl/benchmark.js b/intl/benchmark.js index 99714b2d..17b6ec40 100644 --- a/intl/benchmark.js +++ b/intl/benchmark.js @@ -1,318 +1,3 @@ -function shuffleOptions(optionsGenerator) { - const options = Array.from(optionsGenerator()); - for (let i = options.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [options[i], options[j]] = [options[j], options[i]]; - } - return options; -} - -const LOCALES = [ - "ar-SA", - "zh-CN", - "zh-TW", - "da-DK", - "en-US", - "en-GB", - "en-CA", - "en-AU", - "fr-FR", - "fr-CA", - "de-DE", - "hi-IN", - "it-IT", - "ja-JP", - "ko-KR", - "pt-BR", - "pt-PT", - "ru-RU", - "es-ES", - "es-MX", - "sw-KE", - "sv-SE", - "th-TH", - "tr-TR", - "vi-VN", -]; - -globalThis.console ??= {}; -console.log ??= (...args) => print(...args); - -function generateRandomDates(count) { - const firstDate = new Date(1800, 11, 5, 13, 6); - let currentTimeStamp = firstDate.getTime(); - const dates = []; - - for (let i = 0; i < count; i++) { - dates.push(new Date(currentTimeStamp)); - currentTimeStamp += 1234569; - } - return dates; -} - -const DATE_STYLE_OPTIONS = ["full", "long", "medium", "short"]; -const TIME_STYLE_OPTIONS = ["full", "long", "medium", "short"]; - -function* dateTimeFormatOptions() { - for (const locale of LOCALES) { - for (const dateStyle of DATE_STYLE_OPTIONS) { - for (const timeStyle of TIME_STYLE_OPTIONS) { - yield { locale, dateStyle, timeStyle }; - } - } - } -} - -function DateTimeFormatPerformanceTest() { - let totalLength = 0; - let lastFormatResult; - let lastFormatPartResult; - let lastFormatRangeResult; - const dates = generateRandomDates(100); - let dateIndex = 0; - - const FORMAT_COUNT = 17; - const FORMAT_RANGE_COUNT = 7; - for (const { locale, dateStyle, timeStyle } of shuffleOptions( - dateTimeFormatOptions - )) { - const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle }); - for (let i = 0; i < FORMAT_COUNT; i++) { - let date = dates[dateIndex % dates.length]; - lastFormatResult = formatter.format(date); - totalLength += lastFormatResult.length; - dateIndex++; - - date = dates[dateIndex % dates.length]; - lastFormatPartResult = formatter.formatToParts(date); - for (const part of lastFormatPartResult) { - totalLength += part.value.length; - } - dateIndex++; - } - let dateRangeStart = dates[0]; - for (let i = 0; i < FORMAT_RANGE_COUNT; i++) { - const date = dates[dateIndex % dates.length]; - if (dateRangeStart < date) - lastFormatRangeResult = formatter.formatRange(dateRangeStart, date); - dateRangeStart = date; - } - } - return {lastResult: lastFormatResult + lastFormatRangeResult, totalLength}; -} - -const LISTS = [ - ["One"], - ["1", "2"], - ["Motorcycle", "Bus", "Car"], - LOCALES, - new Array(100).fill(9).map((_, index) => index.toString()), -]; - -function* listOptions() { - const styleOptions = ["long", "short", "narrow"]; - const typeOptions = ["conjunction", "disjunction", "unit"]; - for (const locale of LOCALES) { - for (const style of styleOptions) { - for (const type of typeOptions) { - yield { locale, style, type }; - } - } - } -} - -function ListFormatPerformanceTest() { - let lastResult; - let totalLength = 0; - const LIST_FORMAT_COUNT = 10; - let listIndex = 0; - for (const { locale, style, type } of shuffleOptions(listOptions)) { - const formatter = new Intl.ListFormat(locale, { style, type }); - for (let i = 0; i < LIST_FORMAT_COUNT; i++) { - const list = LISTS[listIndex % LISTS.length]; - listIndex++; - lastResult = formatter.format(list); - totalLength += lastResult.length; - const formatPartsResult = formatter.formatToParts(list); - for (const part of formatPartsResult) { - totalLength += part.value.length; - } - } - } - return {lastResult, totalLength}; -} - -const UNITS = [ - "year", - "quarter", - "month", - "week", - "day", - "hour", - "minute", - "second", -]; - -function* relativeTimeFormatOptions() { - const styleOptions = ["long", "short", "narrow"]; - const numericOptions = ["always", "auto"]; - for (const locale of LOCALES) { - for (const style of styleOptions) { - for (const numeric of numericOptions) { - yield { locale, style, numeric }; - } - } - } -} - -function RelativeTimeFormatPerformanceTest() { - let lastResult; - let totalLength = 0; - const RELATIVE_TIME_FORMAT_COUNT = 100; - let unitIndex = 0; - for (const { locale, style, numeric } of shuffleOptions( - relativeTimeFormatOptions - )) { - const formatter = new Intl.RelativeTimeFormat(locale, { style, numeric }); - for (let i = 0; i < RELATIVE_TIME_FORMAT_COUNT; i++) { - const unit = UNITS[unitIndex % UNITS.length]; - unitIndex++; - const value = Math.random() * 100 - 50; - lastResult = formatter.format(value, unit); - totalLength += lastResult.length; - const formatPartsResult = formatter.formatToParts(value, unit); - for (const part of formatPartsResult) { - totalLength += part.value.length; - } - } - } - return {lastResult, totalLength}; -} - -const CURRENCIES = [ - "USD", - "EUR", - "JPY", - "INR", - "NGN", -]; - -const NUMBER_UNITS = [ - "acre", - "bit", - "byte", - "celsius", - "centimeter", - "day", - "degree", - "fahrenheit", - "fluid-ounce", - "foot", - "gallon", - "gigabit", - "gigabyte", - "gram", - "hectare", - "hour", - "inch", - "kilobit", - "kilobyte", - "kilogram", - "kilometer", - "liter", - "megabit", - "megabyte", - "meter", - "microsecond", - "mile", - "mile-scandinavian", - "milliliter", - "millimeter", - "millisecond", - "minute", - "month", - "nanosecond", - "ounce", - "percent", - "petabyte", - "pound", - "second", - "stone", - "terabit", - "terabyte", - "week", - "yard", - "year", -]; - -function* numberFormatOptions() { - const currencyDisplayOptions = ["symbol", "narrowSymbol", "code", "name"]; - const unitDisplayOptions = ["short", "long", "narrow"]; - - for (const locale of LOCALES) { - for (const currency of CURRENCIES) { - for (const currencyDisplay of currencyDisplayOptions) { - yield { locale, style: "currency", currency, currencyDisplay }; - } - } - for (const unit of NUMBER_UNITS.slice(0, 20)) { - for (const unitDisplay of unitDisplayOptions) { - yield { locale, style: "unit", unit, unitDisplay }; - } - } - yield { locale, style: "decimal" }; - yield { locale, style: "percent" }; - } -} - -function NumberFormatPerformanceTest() { - let lastResult; - let totalLength = 0; - const NUMBER_FORMAT_COUNT = 10; - for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { - const formatter = new Intl.NumberFormat(options.locale, options); - for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { - const value = Math.random() * 10_000; - lastResult = formatter.format(value); - totalLength += lastResult.length; - const formatPartsResult = formatter.formatToParts(value); - for (const part of formatPartsResult) { - totalLength += part.value.length; - } - } - } - return {lastResult, totalLength}; -} - -function* pluralRulesOptions() { - const typeOptions = ["cardinal", "ordinal"]; - for (const locale of LOCALES) { - for (const type of typeOptions) { - yield { locale, type }; - } - } -} - -function PluralRulesPerformanceTest() { - let lastResult; - let totalLength = 0; - const PLURAL_RULES_COUNT = 1000; - for (const { locale, type } of shuffleOptions(pluralRulesOptions)) { - const formatter = new Intl.PluralRules(locale, { type }); - let i = 0; - for (let value = 0; value < 4; value++) { - lastResult = formatter.select(value); - totalLength += lastResult.length; - i++; - } - for (; i < PLURAL_RULES_COUNT; i++) { - const value = Math.floor(Math.random() * 1000); - lastResult = formatter.select(value); - totalLength += lastResult.length; - } - } - return {lastResult, totalLength}; -} class Benchmark { measureItems = false @@ -320,24 +5,8 @@ class Benchmark { totalLength = 0; runIteration() { - this.run(DateTimeFormatPerformanceTest); - this.run(ListFormatPerformanceTest); - this.run(RelativeTimeFormatPerformanceTest); - this.run(NumberFormatPerformanceTest); - this.run(PluralRulesPerformanceTest); - } - - run(fn) { - let result; - if (!this.measureItems) { - result = fn(); - } else { - const start = performance.now(); - result = fn(); - const end = performance.now(); - console.log(` ${fn.name}: ${(end - start).toFixed(2)}ms`); - } - const {lastResult, totalLength} = result; + // See implementations in src/. + const {lastResult, totalLength} = runTest(); this.lastResult = lastResult; this.totalLength += totalLength; } diff --git a/intl/src/DateTimeFormat.js b/intl/src/DateTimeFormat.js new file mode 100644 index 00000000..148143fb --- /dev/null +++ b/intl/src/DateTimeFormat.js @@ -0,0 +1,63 @@ + +function generateRandomDates(count) { + const firstDate = new Date(1800, 11, 5, 13, 6); + let currentTimeStamp = firstDate.getTime(); + const dates = []; + + for (let i = 0; i < count; i++) { + dates.push(new Date(currentTimeStamp)); + currentTimeStamp += 1234569; + } + return dates; +} + +const DATE_STYLE_OPTIONS = ["full", "long", "medium", "short"]; +const TIME_STYLE_OPTIONS = ["full", "long", "medium", "short"]; + +function* dateTimeFormatOptions() { + for (const locale of LOCALES) { + for (const dateStyle of DATE_STYLE_OPTIONS) { + for (const timeStyle of TIME_STYLE_OPTIONS) { + yield { locale, dateStyle, timeStyle }; + } + } + } +} + +function runTest() { + let totalLength = 0; + let lastFormatResult; + let lastFormatPartResult; + let lastFormatRangeResult; + const dates = generateRandomDates(100); + let dateIndex = 0; + + const FORMAT_COUNT = 17; + const FORMAT_RANGE_COUNT = 7; + for (const { locale, dateStyle, timeStyle } of shuffleOptions( + dateTimeFormatOptions + )) { + const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle }); + for (let i = 0; i < FORMAT_COUNT; i++) { + let date = dates[dateIndex % dates.length]; + lastFormatResult = formatter.format(date); + totalLength += lastFormatResult.length; + dateIndex++; + + date = dates[dateIndex % dates.length]; + lastFormatPartResult = formatter.formatToParts(date); + for (const part of lastFormatPartResult) { + totalLength += part.value.length; + } + dateIndex++; + } + let dateRangeStart = dates[0]; + for (let i = 0; i < FORMAT_RANGE_COUNT; i++) { + const date = dates[dateIndex % dates.length]; + if (dateRangeStart < date) + lastFormatRangeResult = formatter.formatRange(dateRangeStart, date); + dateRangeStart = date; + } + } + return {lastResult: lastFormatResult + lastFormatRangeResult, totalLength}; +} \ No newline at end of file diff --git a/intl/src/ListFormat.js b/intl/src/ListFormat.js new file mode 100644 index 00000000..477096cf --- /dev/null +++ b/intl/src/ListFormat.js @@ -0,0 +1,40 @@ +const LISTS = [ + ["One"], + ["1", "2"], + ["Motorcycle", "Bus", "Car"], + LOCALES, + new Array(100).fill(9).map((_, index) => index.toString()), +]; + +function* listOptions() { + const styleOptions = ["long", "short", "narrow"]; + const typeOptions = ["conjunction", "disjunction", "unit"]; + for (const locale of LOCALES) { + for (const style of styleOptions) { + for (const type of typeOptions) { + yield { locale, style, type }; + } + } + } +} + +function runTest() { + let lastResult; + let totalLength = 0; + const LIST_FORMAT_COUNT = 10; + let listIndex = 0; + for (const { locale, style, type } of shuffleOptions(listOptions)) { + const formatter = new Intl.ListFormat(locale, { style, type }); + for (let i = 0; i < LIST_FORMAT_COUNT; i++) { + const list = LISTS[listIndex % LISTS.length]; + listIndex++; + lastResult = formatter.format(list); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(list); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} diff --git a/intl/src/NumberFormat.js b/intl/src/NumberFormat.js new file mode 100644 index 00000000..3fcf5b94 --- /dev/null +++ b/intl/src/NumberFormat.js @@ -0,0 +1,96 @@ + + +const CURRENCIES = [ + "USD", + "EUR", + "JPY", + "INR", + "NGN", +]; + +const NUMBER_UNITS = [ + "acre", + "bit", + "byte", + "celsius", + "centimeter", + "day", + "degree", + "fahrenheit", + "fluid-ounce", + "foot", + "gallon", + "gigabit", + "gigabyte", + "gram", + "hectare", + "hour", + "inch", + "kilobit", + "kilobyte", + "kilogram", + "kilometer", + "liter", + "megabit", + "megabyte", + "meter", + "microsecond", + "mile", + "mile-scandinavian", + "milliliter", + "millimeter", + "millisecond", + "minute", + "month", + "nanosecond", + "ounce", + "percent", + "petabyte", + "pound", + "second", + "stone", + "terabit", + "terabyte", + "week", + "yard", + "year", +]; + +function* numberFormatOptions() { + const currencyDisplayOptions = ["symbol", "narrowSymbol", "code", "name"]; + const unitDisplayOptions = ["short", "long", "narrow"]; + + for (const locale of LOCALES) { + for (const currency of CURRENCIES) { + for (const currencyDisplay of currencyDisplayOptions) { + yield { locale, style: "currency", currency, currencyDisplay }; + } + } + for (const unit of NUMBER_UNITS.slice(0, 20)) { + for (const unitDisplay of unitDisplayOptions) { + yield { locale, style: "unit", unit, unitDisplay }; + } + } + yield { locale, style: "decimal" }; + yield { locale, style: "percent" }; + } +} + +function runTest() { + let lastResult; + let totalLength = 0; + const NUMBER_FORMAT_COUNT = 10; + for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { + const formatter = new Intl.NumberFormat(options.locale, options); + for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { + const value = Math.random() * 10_000; + lastResult = formatter.format(value); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(value); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} diff --git a/intl/src/PluralRules.js b/intl/src/PluralRules.js new file mode 100644 index 00000000..038ceb83 --- /dev/null +++ b/intl/src/PluralRules.js @@ -0,0 +1,30 @@ + +function* pluralRulesOptions() { + const typeOptions = ["cardinal", "ordinal"]; + for (const locale of LOCALES) { + for (const type of typeOptions) { + yield { locale, type }; + } + } +} + +function runTest() { + let lastResult; + let totalLength = 0; + const PLURAL_RULES_COUNT = 1000; + for (const { locale, type } of shuffleOptions(pluralRulesOptions)) { + const formatter = new Intl.PluralRules(locale, { type }); + let i = 0; + for (let value = 0; value < 4; value++) { + lastResult = formatter.select(value); + totalLength += lastResult.length; + i++; + } + for (; i < PLURAL_RULES_COUNT; i++) { + const value = Math.floor(Math.random() * 1000); + lastResult = formatter.select(value); + totalLength += lastResult.length; + } + } + return {lastResult, totalLength}; +} \ No newline at end of file diff --git a/intl/src/RelativeTimeFormat.js b/intl/src/RelativeTimeFormat.js new file mode 100644 index 00000000..e6918818 --- /dev/null +++ b/intl/src/RelativeTimeFormat.js @@ -0,0 +1,46 @@ +const UNITS = [ + "year", + "quarter", + "month", + "week", + "day", + "hour", + "minute", + "second", +]; + +function* relativeTimeFormatOptions() { + const styleOptions = ["long", "short", "narrow"]; + const numericOptions = ["always", "auto"]; + for (const locale of LOCALES) { + for (const style of styleOptions) { + for (const numeric of numericOptions) { + yield { locale, style, numeric }; + } + } + } +} + +function runTest() { + let lastResult; + let totalLength = 0; + const RELATIVE_TIME_FORMAT_COUNT = 100; + let unitIndex = 0; + for (const { locale, style, numeric } of shuffleOptions( + relativeTimeFormatOptions + )) { + const formatter = new Intl.RelativeTimeFormat(locale, { style, numeric }); + for (let i = 0; i < RELATIVE_TIME_FORMAT_COUNT; i++) { + const unit = UNITS[unitIndex % UNITS.length]; + unitIndex++; + const value = Math.random() * 100 - 50; + lastResult = formatter.format(value, unit); + totalLength += lastResult.length; + const formatPartsResult = formatter.formatToParts(value, unit); + for (const part of formatPartsResult) { + totalLength += part.value.length; + } + } + } + return {lastResult, totalLength}; +} diff --git a/intl/src/helper.js b/intl/src/helper.js new file mode 100644 index 00000000..9a173f68 --- /dev/null +++ b/intl/src/helper.js @@ -0,0 +1,39 @@ +function shuffleOptions(optionsGenerator) { + const options = Array.from(optionsGenerator()); + for (let i = options.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [options[i], options[j]] = [options[j], options[i]]; + } + return options; +} + +const LOCALES = [ + "ar-SA", + "zh-CN", + "zh-TW", + "da-DK", + "en-US", + "en-GB", + "en-CA", + "en-AU", + "fr-FR", + "fr-CA", + "de-DE", + "hi-IN", + "it-IT", + "ja-JP", + "ko-KR", + "pt-BR", + "pt-PT", + "ru-RU", + "es-ES", + "es-MX", + "sw-KE", + "sv-SE", + "th-TH", + "tr-TR", + "vi-VN", +]; + +globalThis.console ??= {}; +console.log ??= (...args) => print(...args); From 4ff33ebef59c8b7c6a8393ade26f484bb259ef89 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Wed, 20 Aug 2025 13:29:03 +0200 Subject: [PATCH 3/9] fix names --- JetStreamDriver.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index 9803c2f8..8eabf5ac 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -2545,14 +2545,14 @@ for (const test of INTL_TESTS) { ], iterations: 15, worstCaseCount: 2, - tags: ["Javascript", "int"], + tags: ["Javascript", "intl"], }); INTL_BENCHMARKS.push(benchmark); } BENCHMARKS.push( new GroupedBenchmark({ name: "intl", - tags: ["Default", "Javascript", "int"], + tags: ["Default", "Javascript", "intl"], }, INTL_BENCHMARKS)); From 93770818e0cb6091095770eba2280bad52dc61b7 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Tue, 26 Aug 2025 17:15:51 +0200 Subject: [PATCH 4/9] fix validation and add license --- JetStreamDriver.js | 5 ++-- intl/benchmark.js | 42 ++++++++++++++++++++++++++++++++-- intl/src/DateTimeFormat.js | 9 +++++--- intl/src/ListFormat.js | 2 +- intl/src/NumberFormat.js | 16 ++++--------- intl/src/PluralRules.js | 5 ++-- intl/src/RelativeTimeFormat.js | 4 +++- 7 files changed, 60 insertions(+), 23 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index ded103f7..7711d894 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -2548,8 +2548,9 @@ for (const test of INTL_TESTS) { `./intl/src/${test}.js`, "./intl/benchmark.js", ], - iterations: 15, - worstCaseCount: 2, + iterations: 2, + worstCaseCount: 1, + deterministicRandom: true, tags: ["Javascript", "intl"], }); INTL_BENCHMARKS.push(benchmark); diff --git a/intl/benchmark.js b/intl/benchmark.js index 17b6ec40..da719079 100644 --- a/intl/benchmark.js +++ b/intl/benchmark.js @@ -1,13 +1,51 @@ +/* + * Copyright (C) 2025 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ class Benchmark { - measureItems = false + iterationCount; lastResult; totalLength = 0; + expectedLength = 0; + + constructor(iterationCount) { + this.iterationCount = iterationCount; + } runIteration() { // See implementations in src/. - const {lastResult, totalLength} = runTest(); + const { lastResult, totalLength, expectedLength } = runTest(); this.lastResult = lastResult; this.totalLength += totalLength; + this.expectedLength = expectedLength; + } + + validate() { + const expectedTotalLength = this.expectedLength * this.iterationCount; + console.assert( + this.totalLength == expectedTotalLength, + `Invalid totalLength = ${this.totalLength}, expected ${expectedTotalLength}` + ); } } diff --git a/intl/src/DateTimeFormat.js b/intl/src/DateTimeFormat.js index 148143fb..88829910 100644 --- a/intl/src/DateTimeFormat.js +++ b/intl/src/DateTimeFormat.js @@ -1,4 +1,3 @@ - function generateRandomDates(count) { const firstDate = new Date(1800, 11, 5, 13, 6); let currentTimeStamp = firstDate.getTime(); @@ -59,5 +58,9 @@ function runTest() { dateRangeStart = date; } } - return {lastResult: lastFormatResult + lastFormatRangeResult, totalLength}; -} \ No newline at end of file + return { + lastResult: lastFormatResult + lastFormatRangeResult, + totalLength, + expectedLength: 442105, + }; +} diff --git a/intl/src/ListFormat.js b/intl/src/ListFormat.js index 477096cf..dc87403c 100644 --- a/intl/src/ListFormat.js +++ b/intl/src/ListFormat.js @@ -36,5 +36,5 @@ function runTest() { } } } - return {lastResult, totalLength}; + return { lastResult, totalLength, expectedLength: 508496 }; } diff --git a/intl/src/NumberFormat.js b/intl/src/NumberFormat.js index 3fcf5b94..23346595 100644 --- a/intl/src/NumberFormat.js +++ b/intl/src/NumberFormat.js @@ -1,12 +1,4 @@ - - -const CURRENCIES = [ - "USD", - "EUR", - "JPY", - "INR", - "NGN", -]; +const CURRENCIES = ["USD", "EUR", "JPY", "INR", "NGN"]; const NUMBER_UNITS = [ "acre", @@ -80,10 +72,12 @@ function runTest() { let lastResult; let totalLength = 0; const NUMBER_FORMAT_COUNT = 10; + let counter = 1; for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { const formatter = new Intl.NumberFormat(options.locale, options); for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { - const value = Math.random() * 10_000; + counter += 599; + const value = counter % 10_000; lastResult = formatter.format(value); totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(value); @@ -92,5 +86,5 @@ function runTest() { } } } - return {lastResult, totalLength}; + return { lastResult, totalLength, expectedLength: 40988 }; } diff --git a/intl/src/PluralRules.js b/intl/src/PluralRules.js index 038ceb83..df426f05 100644 --- a/intl/src/PluralRules.js +++ b/intl/src/PluralRules.js @@ -1,4 +1,3 @@ - function* pluralRulesOptions() { const typeOptions = ["cardinal", "ordinal"]; for (const locale of LOCALES) { @@ -26,5 +25,5 @@ function runTest() { totalLength += lastResult.length; } } - return {lastResult, totalLength}; -} \ No newline at end of file + return { lastResult, totalLength, expectedLength: 244941 }; +} diff --git a/intl/src/RelativeTimeFormat.js b/intl/src/RelativeTimeFormat.js index e6918818..e8f4323f 100644 --- a/intl/src/RelativeTimeFormat.js +++ b/intl/src/RelativeTimeFormat.js @@ -21,6 +21,8 @@ function* relativeTimeFormatOptions() { } } + + function runTest() { let lastResult; let totalLength = 0; @@ -42,5 +44,5 @@ function runTest() { } } } - return {lastResult, totalLength}; + return { lastResult, totalLength, expectedLength: 434328 }; } From 1d6ce711c1b5151b4c04a390ccc1454d61c75cd6 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Tue, 26 Aug 2025 22:49:16 +0200 Subject: [PATCH 5/9] support custom benchmark arguments --- JetStreamDriver.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index 0ef099ba..cd25ef1f 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -740,9 +740,16 @@ class Benchmark { return tags.some((tag) => this.tags.has(tag.toLowerCase())); } + get benchmarkArguments() { + return { + ...this.plan.arguments, + iterationCount: this.iterations, + }; + } + get runnerCode() { return `{ - const benchmark = new Benchmark(${this.iterations}); + const benchmark = new Benchmark(${JSON.stringify(this.benchmarkArguments)}); const results = []; const benchmarkName = "${this.name}"; @@ -1404,7 +1411,7 @@ class WSLBenchmark extends Benchmark { get runnerCode() { return `{ - const benchmark = new Benchmark(); + const benchmark = new Benchmark(${JSON.stringify(this.benchmarkArguments)}); const benchmarkName = "${this.name}"; const results = []; From 087fb8f0df2fc7de804966e22b4fd2924501ba01 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Wed, 27 Aug 2025 15:37:02 +0200 Subject: [PATCH 6/9] update workload --- JetStreamDriver.js | 10 +++++----- intl/benchmark.js | 5 +++-- intl/src/NumberFormat.js | 2 ++ intl/src/RelativeTimeFormat.js | 3 +++ 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index 7177880a..eedbdb58 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -1327,7 +1327,7 @@ class AsyncBenchmark extends DefaultBenchmark { get runnerCode() { return ` async function doRun() { - const benchmark = new Benchmark(${this.iterations}); + const benchmark = new Benchmark(${JSON.stringify(this.benchmarkArguments)}); await benchmark.init?.(); const results = []; const benchmarkName = "${this.name}"; @@ -2540,11 +2540,11 @@ let BENCHMARKS = [ const INTL_TESTS = [ - "DateTimeFormat", - "ListFormat", - "RelativeTimeFormat", + // "DateTimeFormat", + // "ListFormat", + // "RelativeTimeFormat", "NumberFormat", - "PluralRules", + // "PluralRules", ]; const INTL_BENCHMARKS = []; for (const test of INTL_TESTS) { diff --git a/intl/benchmark.js b/intl/benchmark.js index da719079..f7838dc8 100644 --- a/intl/benchmark.js +++ b/intl/benchmark.js @@ -29,7 +29,7 @@ class Benchmark { totalLength = 0; expectedLength = 0; - constructor(iterationCount) { + constructor({ iterationCount }) { this.iterationCount = iterationCount; } @@ -39,12 +39,13 @@ class Benchmark { this.lastResult = lastResult; this.totalLength += totalLength; this.expectedLength = expectedLength; + console.log(this.totalLength, this.expectedLength) } validate() { const expectedTotalLength = this.expectedLength * this.iterationCount; console.assert( - this.totalLength == expectedTotalLength, + this.totalLength === expectedTotalLength, `Invalid totalLength = ${this.totalLength}, expected ${expectedTotalLength}` ); } diff --git a/intl/src/NumberFormat.js b/intl/src/NumberFormat.js index 23346595..c23c495f 100644 --- a/intl/src/NumberFormat.js +++ b/intl/src/NumberFormat.js @@ -75,10 +75,12 @@ function runTest() { let counter = 1; for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { const formatter = new Intl.NumberFormat(options.locale, options); + console.log(options.locale, JSON.stringify(options)) for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { counter += 599; const value = counter % 10_000; lastResult = formatter.format(value); + console.log(value, lastResult, ) totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(value); for (const part of formatPartsResult) { diff --git a/intl/src/RelativeTimeFormat.js b/intl/src/RelativeTimeFormat.js index e8f4323f..53ebbcc5 100644 --- a/intl/src/RelativeTimeFormat.js +++ b/intl/src/RelativeTimeFormat.js @@ -32,11 +32,14 @@ function runTest() { relativeTimeFormatOptions )) { const formatter = new Intl.RelativeTimeFormat(locale, { style, numeric }); + console.log(style, numeric); for (let i = 0; i < RELATIVE_TIME_FORMAT_COUNT; i++) { const unit = UNITS[unitIndex % UNITS.length]; unitIndex++; const value = Math.random() * 100 - 50; + console.log(value, unit); lastResult = formatter.format(value, unit); + console.log(lastResult); totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(value, unit); for (const part of formatPartsResult) { From a3a38ffaa544a42380f11eaaea5201b1522a8f99 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Mon, 1 Sep 2025 18:04:50 +0200 Subject: [PATCH 7/9] remove default tag --- JetStreamDriver.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/JetStreamDriver.js b/JetStreamDriver.js index eedbdb58..109fc553 100644 --- a/JetStreamDriver.js +++ b/JetStreamDriver.js @@ -2540,11 +2540,11 @@ let BENCHMARKS = [ const INTL_TESTS = [ - // "DateTimeFormat", - // "ListFormat", - // "RelativeTimeFormat", + "DateTimeFormat", + "ListFormat", + "RelativeTimeFormat", "NumberFormat", - // "PluralRules", + "PluralRules", ]; const INTL_BENCHMARKS = []; for (const test of INTL_TESTS) { @@ -2565,7 +2565,7 @@ for (const test of INTL_TESTS) { BENCHMARKS.push( new GroupedBenchmark({ name: "intl", - tags: ["Default", "Javascript", "intl"], + tags: ["Javascript", "intl"], }, INTL_BENCHMARKS)); From 33a03ee08e73239c01470fa53f500fed6e644b47 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Mon, 1 Sep 2025 18:18:35 +0200 Subject: [PATCH 8/9] update benchmark --- intl/benchmark.js | 21 +++++++++++++-------- intl/src/DateTimeFormat.js | 17 ++++++++++++++--- intl/src/ListFormat.js | 11 +++++++++-- intl/src/NumberFormat.js | 10 +++++++--- intl/src/PluralRules.js | 11 ++++++++++- intl/src/RelativeTimeFormat.js | 16 +++++++++------- 6 files changed, 62 insertions(+), 24 deletions(-) diff --git a/intl/benchmark.js b/intl/benchmark.js index f7838dc8..c7443852 100644 --- a/intl/benchmark.js +++ b/intl/benchmark.js @@ -25,28 +25,33 @@ class Benchmark { iterationCount; + verbose; lastResult; totalLength = 0; - expectedLength = 0; + expectedMinLength = 0; - constructor({ iterationCount }) { + constructor({ iterationCount, verbose = false } = {}) { this.iterationCount = iterationCount; + this.verbose = verbose; } runIteration() { // See implementations in src/. - const { lastResult, totalLength, expectedLength } = runTest(); + const { + lastResult, + totalLength, + expectedLength: expectedMinLength, + } = runTest(this.verbose); this.lastResult = lastResult; this.totalLength += totalLength; - this.expectedLength = expectedLength; - console.log(this.totalLength, this.expectedLength) + this.expectedMinLength = expectedMinLength; } validate() { - const expectedTotalLength = this.expectedLength * this.iterationCount; + const expectedMinTotalLength = this.expectedMinLength * this.iterationCount; console.assert( - this.totalLength === expectedTotalLength, - `Invalid totalLength = ${this.totalLength}, expected ${expectedTotalLength}` + this.totalLength >= expectedMinTotalLength, + `Invalid totalLength = ${this.totalLength}, expected ${expectedMinTotalLength}` ); } } diff --git a/intl/src/DateTimeFormat.js b/intl/src/DateTimeFormat.js index 88829910..61f26e93 100644 --- a/intl/src/DateTimeFormat.js +++ b/intl/src/DateTimeFormat.js @@ -23,7 +23,7 @@ function* dateTimeFormatOptions() { } } -function runTest() { +function runTest(verbose = false) { let totalLength = 0; let lastFormatResult; let lastFormatPartResult; @@ -36,11 +36,18 @@ function runTest() { for (const { locale, dateStyle, timeStyle } of shuffleOptions( dateTimeFormatOptions )) { - const formatter = new Intl.DateTimeFormat(locale, { dateStyle, timeStyle }); + const options = { dateStyle, timeStyle }; + if (verbose) { + console.log(locale, JSON.stringify(options)); + } + const formatter = new Intl.DateTimeFormat(locale, options); for (let i = 0; i < FORMAT_COUNT; i++) { let date = dates[dateIndex % dates.length]; lastFormatResult = formatter.format(date); totalLength += lastFormatResult.length; + if (verbose) { + console.log(date, lastFormatResult); + } dateIndex++; date = dates[dateIndex % dates.length]; @@ -53,8 +60,12 @@ function runTest() { let dateRangeStart = dates[0]; for (let i = 0; i < FORMAT_RANGE_COUNT; i++) { const date = dates[dateIndex % dates.length]; - if (dateRangeStart < date) + if (dateRangeStart < date) { lastFormatRangeResult = formatter.formatRange(dateRangeStart, date); + if (verbose) { + console.log(dateRangeStart, date, lastFormatRangeResult); + } + } dateRangeStart = date; } } diff --git a/intl/src/ListFormat.js b/intl/src/ListFormat.js index dc87403c..6e2ba068 100644 --- a/intl/src/ListFormat.js +++ b/intl/src/ListFormat.js @@ -18,19 +18,26 @@ function* listOptions() { } } -function runTest() { +function runTest(verbose = false) { let lastResult; let totalLength = 0; const LIST_FORMAT_COUNT = 10; let listIndex = 0; for (const { locale, style, type } of shuffleOptions(listOptions)) { - const formatter = new Intl.ListFormat(locale, { style, type }); + const options = { style, type }; + if (verbose) { + console.log(locale, JSON.stringify(options)); + } + const formatter = new Intl.ListFormat(locale, options); for (let i = 0; i < LIST_FORMAT_COUNT; i++) { const list = LISTS[listIndex % LISTS.length]; listIndex++; lastResult = formatter.format(list); totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(list); + if (verbose) { + console.log(value, lastResult); + } for (const part of formatPartsResult) { totalLength += part.value.length; } diff --git a/intl/src/NumberFormat.js b/intl/src/NumberFormat.js index c23c495f..873a20c3 100644 --- a/intl/src/NumberFormat.js +++ b/intl/src/NumberFormat.js @@ -68,19 +68,23 @@ function* numberFormatOptions() { } } -function runTest() { +function runTest(verbose = false) { let lastResult; let totalLength = 0; const NUMBER_FORMAT_COUNT = 10; let counter = 1; for (const options of shuffleOptions(numberFormatOptions).slice(0, 200)) { const formatter = new Intl.NumberFormat(options.locale, options); - console.log(options.locale, JSON.stringify(options)) + if (verbose) { + console.log(options.locale, JSON.stringify(options)); + } for (let i = 0; i < NUMBER_FORMAT_COUNT; i++) { counter += 599; const value = counter % 10_000; lastResult = formatter.format(value); - console.log(value, lastResult, ) + if (verbose) { + console.log(value, lastResult); + } totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(value); for (const part of formatPartsResult) { diff --git a/intl/src/PluralRules.js b/intl/src/PluralRules.js index df426f05..3bb7047a 100644 --- a/intl/src/PluralRules.js +++ b/intl/src/PluralRules.js @@ -7,22 +7,31 @@ function* pluralRulesOptions() { } } -function runTest() { +function runTest(verbose = false) { let lastResult; let totalLength = 0; const PLURAL_RULES_COUNT = 1000; for (const { locale, type } of shuffleOptions(pluralRulesOptions)) { + if (verbose) { + console.log(locale, type); + } const formatter = new Intl.PluralRules(locale, { type }); let i = 0; for (let value = 0; value < 4; value++) { lastResult = formatter.select(value); totalLength += lastResult.length; + if (verbose) { + console.log(value, lastResult); + } i++; } for (; i < PLURAL_RULES_COUNT; i++) { const value = Math.floor(Math.random() * 1000); lastResult = formatter.select(value); totalLength += lastResult.length; + if (verbose) { + console.log(value, lastResult); + } } } return { lastResult, totalLength, expectedLength: 244941 }; diff --git a/intl/src/RelativeTimeFormat.js b/intl/src/RelativeTimeFormat.js index 53ebbcc5..ee6f13f7 100644 --- a/intl/src/RelativeTimeFormat.js +++ b/intl/src/RelativeTimeFormat.js @@ -21,9 +21,7 @@ function* relativeTimeFormatOptions() { } } - - -function runTest() { +function runTest(verbose = false) { let lastResult; let totalLength = 0; const RELATIVE_TIME_FORMAT_COUNT = 100; @@ -31,15 +29,19 @@ function runTest() { for (const { locale, style, numeric } of shuffleOptions( relativeTimeFormatOptions )) { - const formatter = new Intl.RelativeTimeFormat(locale, { style, numeric }); - console.log(style, numeric); + const options = { style, numeric }; + if (verbose) { + console.log(locale, JSON.stringify(options)); + } + const formatter = new Intl.RelativeTimeFormat(locale, options); for (let i = 0; i < RELATIVE_TIME_FORMAT_COUNT; i++) { const unit = UNITS[unitIndex % UNITS.length]; unitIndex++; const value = Math.random() * 100 - 50; - console.log(value, unit); lastResult = formatter.format(value, unit); - console.log(lastResult); + if (verbose) { + console.log(value, unit, lastResult); + } totalLength += lastResult.length; const formatPartsResult = formatter.formatToParts(value, unit); for (const part of formatPartsResult) { From 33d507c7692468fd519764902ffdd8b862f63a64 Mon Sep 17 00:00:00 2001 From: Camillo Bruni Date: Mon, 1 Sep 2025 18:23:09 +0200 Subject: [PATCH 9/9] fix --- intl/benchmark.js | 10 ++++------ intl/src/DateTimeFormat.js | 2 +- intl/src/ListFormat.js | 2 +- intl/src/NumberFormat.js | 2 +- intl/src/PluralRules.js | 2 +- intl/src/RelativeTimeFormat.js | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/intl/benchmark.js b/intl/benchmark.js index c7443852..8c835952 100644 --- a/intl/benchmark.js +++ b/intl/benchmark.js @@ -37,11 +37,9 @@ class Benchmark { runIteration() { // See implementations in src/. - const { - lastResult, - totalLength, - expectedLength: expectedMinLength, - } = runTest(this.verbose); + const { lastResult, totalLength, expectedMinLength } = runTest( + this.verbose + ); this.lastResult = lastResult; this.totalLength += totalLength; this.expectedMinLength = expectedMinLength; @@ -51,7 +49,7 @@ class Benchmark { const expectedMinTotalLength = this.expectedMinLength * this.iterationCount; console.assert( this.totalLength >= expectedMinTotalLength, - `Invalid totalLength = ${this.totalLength}, expected ${expectedMinTotalLength}` + `Invalid totalLength = ${this.totalLength}, expected >= ${expectedMinTotalLength}` ); } } diff --git a/intl/src/DateTimeFormat.js b/intl/src/DateTimeFormat.js index 61f26e93..ee981bf2 100644 --- a/intl/src/DateTimeFormat.js +++ b/intl/src/DateTimeFormat.js @@ -72,6 +72,6 @@ function runTest(verbose = false) { return { lastResult: lastFormatResult + lastFormatRangeResult, totalLength, - expectedLength: 442105, + expectedMinLength: 438_000, }; } diff --git a/intl/src/ListFormat.js b/intl/src/ListFormat.js index 6e2ba068..9849853c 100644 --- a/intl/src/ListFormat.js +++ b/intl/src/ListFormat.js @@ -43,5 +43,5 @@ function runTest(verbose = false) { } } } - return { lastResult, totalLength, expectedLength: 508496 }; + return { lastResult, totalLength, expectedMinLength: 506_000 }; } diff --git a/intl/src/NumberFormat.js b/intl/src/NumberFormat.js index 873a20c3..6a847214 100644 --- a/intl/src/NumberFormat.js +++ b/intl/src/NumberFormat.js @@ -92,5 +92,5 @@ function runTest(verbose = false) { } } } - return { lastResult, totalLength, expectedLength: 40988 }; + return { lastResult, totalLength, expectedMinLength: 40_000 }; } diff --git a/intl/src/PluralRules.js b/intl/src/PluralRules.js index 3bb7047a..944aa390 100644 --- a/intl/src/PluralRules.js +++ b/intl/src/PluralRules.js @@ -34,5 +34,5 @@ function runTest(verbose = false) { } } } - return { lastResult, totalLength, expectedLength: 244941 }; + return { lastResult, totalLength, expectedMinLength: 244_000 }; } diff --git a/intl/src/RelativeTimeFormat.js b/intl/src/RelativeTimeFormat.js index ee6f13f7..e0d0394a 100644 --- a/intl/src/RelativeTimeFormat.js +++ b/intl/src/RelativeTimeFormat.js @@ -49,5 +49,5 @@ function runTest(verbose = false) { } } } - return { lastResult, totalLength, expectedLength: 434328 }; + return { lastResult, totalLength, expectedMinLength: 432_000 }; }