From fefa4c061b6c55b4e649c1b3aa5888f24a7f037e Mon Sep 17 00:00:00 2001 From: Olivier Yiptong Date: Wed, 5 May 2021 15:42:36 -0700 Subject: [PATCH] Compute Pressure API: Initial implementation without platform support. This CL implements the API described in the following explainer: https://github.com/oyiptong/compute-pressure/blob/main/README.md The browser-side implementation has all the infrastructure for collecting compute pressure information, but no platform-specific implementation. Per-platform code will be landed in follow-up CLs. Intent to Prototype thread: https://groups.google.com/a/chromium.org/g/blink-dev/c/LTIRZ24C5Os/ Fixed: 1183600 Change-Id: I4fd929950b2a0d7810780e5af8d85063f4a3c6e3 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727134 Reviewed-by: Olivier Yiptong Reviewed-by: Victor Costan Reviewed-by: John Abd-El-Malek Reviewed-by: Mike West Commit-Queue: Olivier Yiptong Cr-Commit-Position: refs/heads/master@{#879584} --- compute-pressure/README.md | 2 + ...essure_arguments.tentative.https.window.js | 73 ++++++++++++++++ ...e_pressure_basic.tentative.https.window.js | 24 +++++ ...essure_detached_iframe.tenative.https.html | 83 ++++++++++++++++++ ...nt_quantizations.tentative.https.window.js | 79 +++++++++++++++++ ...s_across_iframes.tentative.https.window.js | 87 +++++++++++++++++++ ...ressure_multiple.tentative.https.window.js | 34 ++++++++ ...e_across_iframes.tentative.https.window.js | 42 +++++++++ ...serve_idempotent.tentative.https.window.js | 27 ++++++ ...te_pressure_stop.tentative.https.window.js | 58 +++++++++++++ ..._stop_idempotent.tentative.https.window.js | 59 +++++++++++++ ...stop_immediately.tentative.https.window.js | 58 +++++++++++++ ...e_pressure_values.tenative.https.window.js | 18 ++++ 13 files changed, 644 insertions(+) create mode 100644 compute-pressure/README.md create mode 100644 compute-pressure/compute_pressure_arguments.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_basic.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_detached_iframe.tenative.https.html create mode 100644 compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_multiple.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_stop.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_stop_idempotent.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_stop_immediately.tentative.https.window.js create mode 100644 compute-pressure/compute_pressure_values.tenative.https.window.js diff --git a/compute-pressure/README.md b/compute-pressure/README.md new file mode 100644 index 00000000000000..9766bb075f3618 --- /dev/null +++ b/compute-pressure/README.md @@ -0,0 +1,2 @@ +This directory contains (tentative) tests for the +[Compute Pressure](https://oyiptong.github.io/compute-pressure/) specification. diff --git a/compute-pressure/compute_pressure_arguments.tentative.https.window.js b/compute-pressure/compute_pressure_arguments.tentative.https.window.js new file mode 100644 index 00000000000000..515c9d72423b93 --- /dev/null +++ b/compute-pressure/compute_pressure_arguments.tentative.https.window.js @@ -0,0 +1,73 @@ +'use strict'; + +for (const property of ['cpuUtilizationThresholds', 'cpuSpeedThresholds']) { + for (const out_of_range_value of [-1.0, 0.0, 1.0, 2.0]) { + test(t => { + const callback = () => {}; + + const options = { + cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5] }; + options[property] = [out_of_range_value]; + + assert_throws_js(TypeError, () => { + new ComputePressureObserver(callback, options); + }); + }, `ComputePressureObserver constructor throws when ${property} ` + + `is [${out_of_range_value}]`); + } + + for (const valid_value of [0.05, 0.1, 0.2, 0.5, 0.9, 0.95]) { + test(t => { + const callback = () => {}; + + const options = { + cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5] }; + options[property] = [valid_value]; + + const observer = new ComputePressureObserver(callback, options); + assert_true(observer instanceof ComputePressureObserver); + }, `ComputePressureObserver constructor accepts ${property} value ` + + `[${valid_value}]`); + } + + promise_test(async t => { + const many_thresholds = [0.5]; + for (let i = 0.01; i < 0.5; i += 0.0001) { + many_thresholds.push(0.5 + i); + many_thresholds.push(0.5 - i); + } + + const options = { + cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5] }; + options[property] = many_thresholds; + + const update = await new Promise((resolve, reject) => { + const observer = new ComputePressureObserver(resolve, options); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const effective_thresholds = update.options[property]; + assert_less_than(effective_thresholds.length, many_thresholds.length, + 'only a small number of thresholds are selected'); + + const expected_thresholds = + many_thresholds.slice(0, effective_thresholds.length); + expected_thresholds.sort(); + assert_array_equals( + effective_thresholds, expected_thresholds, + 'thresholds are selected in the given order, before sorting'); + }, `ComputePressureObserver filters thresholds in ${property}`); +} + +test(t => { + const callback = () => {}; + + + assert_throws_js(TypeError, () => { + new ComputePressureObserver( + callback, + { cpuUtilizationThresholds: [0.5, 0.5], cpuSpeedThresholds: [0.5] }); + }); +}, 'ComputePressureObserver constructor throws when cpuUtilizationThresholds ' + + 'has duplicates'); diff --git a/compute-pressure/compute_pressure_basic.tentative.https.window.js b/compute-pressure/compute_pressure_basic.tentative.https.window.js new file mode 100644 index 00000000000000..dac1dabee0fa40 --- /dev/null +++ b/compute-pressure/compute_pressure_basic.tentative.https.window.js @@ -0,0 +1,24 @@ +'use strict'; + +promise_test(async t => { + // The quantization thresholds and the quantized values that they lead to can + // be represented exactly in floating-point, so === comparison works. + + const update = await new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + assert_equals(typeof update.cpuUtilization, 'number'); + assert_greater_than_equal(update.cpuUtilization, 0.0, 'cpuUtilization range'); + assert_less_than_equal(update.cpuUtilization, 1.0, 'cpuUtilization range'); + assert_in_array(update.cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + + assert_equals(typeof update.cpuSpeed, 'number'); + assert_greater_than_equal(update.cpuSpeed, 0.0, 'cpuSpeed range'); + assert_less_than_equal(update.cpuSpeed, 1.0, 'cpuUSpeed range'); + assert_in_array(update.cpuSpeed, [0.25, 0.75], 'cpuSpeed quantization'); +}, 'An active ComputePressureObserver calls its callback at least once'); diff --git a/compute-pressure/compute_pressure_detached_iframe.tenative.https.html b/compute-pressure/compute_pressure_detached_iframe.tenative.https.html new file mode 100644 index 00000000000000..be0b9380c35e43 --- /dev/null +++ b/compute-pressure/compute_pressure_detached_iframe.tenative.https.html @@ -0,0 +1,83 @@ + + +ComputePressureObserver on DOMWindow of detached iframe + + + + + diff --git a/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js b/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js new file mode 100644 index 00000000000000..6f1d6d8784187d --- /dev/null +++ b/compute-pressure/compute_pressure_different_quantizations.tentative.https.window.js @@ -0,0 +1,79 @@ +'use strict'; + +promise_test(async t => { + const observer1_updates = []; + const observer1 = new ComputePressureObserver( + update => { observer1_updates.push(update); }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer1.stop()); + // Ensure that observer1's quantization scheme gets registered as the origin's + // scheme before observer2 starts. + await observer1.observe(); + + const observer2_updates = []; + await new Promise((resolve, reject) => { + const observer2 = new ComputePressureObserver( + update => { + observer2_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.25], cpuSpeedThresholds: [0.75]}); + t.add_cleanup(() => observer2.stop()); + observer2.observe().catch(reject); + }); + + // observer2 uses a different quantization scheme than observer1. After + // observer2.observe() completes, observer1 should no longer be active. + // + // The check below assumes that observer2.observe() completes before the + // browser dispatches any update for observer1. This assumption is highly + // likely to be true, because there shold be a 1-second delay between + // observer1.observe() and the first update that observer1 would receive. + assert_equals( + observer1_updates.length, 0, + 'observer2.observe() should have stopped observer1; the two observers ' + + 'have different quantization schemes'); + + assert_equals(observer2_updates.length, 1); + assert_in_array(observer2_updates[0].cpuUtilization, [0.125, 0.625], + 'cpuUtilization quantization'); + assert_in_array(observer2_updates[0].cpuSpeed, [0.375, 0.875], + 'cpuSpeed quantization'); + + // Go through one more update cycle so any (incorrect) update for observer1 + // makes it through the IPC queues. + observer1_updates.length = 0; + observer2_updates.length = 0; + + const observer3_updates = []; + await new Promise((resolve, reject) => { + const observer3 = new ComputePressureObserver( + update => { + observer3_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.75], cpuSpeedThresholds: [0.25]}); + t.add_cleanup(() => observer3.stop()); + observer3.observe().catch(reject); + }); + + assert_equals( + observer1_updates.length, 0, + 'observer2.observe() should have stopped observer1; the two observers ' + + 'have different quantization schemes'); + + // observer3 uses a different quantization scheme than observer2. So, + // observer3.observe() should stop observer2. + assert_equals( + observer2_updates.length, 0, + 'observer3.observe() should have stopped observer2; the two observers ' + + 'have different quantization schemes'); + + assert_equals(observer3_updates.length, 1); + assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875], + 'cpuUtilization quantization'); + assert_in_array(observer3_updates[0].cpuSpeed, [0.125, 0.625], + 'cpuSpeed quantization'); + +}, 'ComputePressureObserver with a new quantization schema stops all ' + + 'other active observers'); diff --git a/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js b/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js new file mode 100644 index 00000000000000..e0429b2d04fb6d --- /dev/null +++ b/compute-pressure/compute_pressure_different_quantizations_across_iframes.tentative.https.window.js @@ -0,0 +1,87 @@ +'use strict'; + +promise_test(async t => { + const observer1_updates = []; + const observer1 = new ComputePressureObserver( + update => { observer1_updates.push(update); }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer1.stop()); + // Ensure that observer1's quantization scheme gets registered as the origin's + // scheme before observer2 starts. + await observer1.observe(); + + // iframe numbers are aligned with observer numbers. The first observer is in + // the main frame, so there is no iframe1. + const iframe2 = document.createElement('iframe'); + document.body.appendChild(iframe2); + + const observer2_updates = []; + await new Promise((resolve, reject) => { + const observer2 = new iframe2.contentWindow.ComputePressureObserver( + update => { + observer2_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.25], cpuSpeedThresholds: [0.75]}); + t.add_cleanup(() => observer2.stop()); + observer2.observe().catch(reject); + }); + + // observer2 uses a different quantization scheme than observer1. After + // observer2.observe() completes, observer1 should no longer be active. + // + // The check below assumes that observer2.observe() completes before the + // browser dispatches any update for observer1. This assumption is highly + // likely to be true, because there shold be a 1-second delay between + // observer1.observe() and the first update that observer1 would receive. + assert_equals( + observer1_updates.length, 0, + 'observer2.observe() should have stopped observer1; the two observers ' + + 'have different quantization schemes'); + + assert_equals(observer2_updates.length, 1); + assert_in_array(observer2_updates[0].cpuUtilization, [0.125, 0.625], + 'cpuUtilization quantization'); + assert_in_array(observer2_updates[0].cpuSpeed, [0.375, 0.875], + 'cpuSpeed quantization'); + + // Go through one more update cycle so any (incorrect) update for observer1 + // makes it through the IPC queues. + observer1_updates.length = 0; + observer2_updates.length = 0; + + const iframe3 = document.createElement('iframe'); + document.body.appendChild(iframe3); + + const observer3_updates = []; + await new Promise((resolve, reject) => { + const observer3 = new iframe3.contentWindow.ComputePressureObserver( + update => { + observer3_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.75], cpuSpeedThresholds: [0.25]}); + t.add_cleanup(() => observer3.stop()); + observer3.observe().catch(reject); + }); + + assert_equals( + observer1_updates.length, 0, + 'observer2.observe() should have stopped observer1; the two observers ' + + 'have different quantization schemes'); + + // observer3 uses a different quantization scheme than observer2. So, + // observer3.observe() should stop observer2. + assert_equals( + observer2_updates.length, 0, + 'observer3.observe() should have stopped observer2; the two observers ' + + 'have different quantization schemes'); + + assert_equals(observer3_updates.length, 1); + assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875], + 'cpuUtilization quantization'); + assert_in_array(observer3_updates[0].cpuSpeed, [0.125, 0.625], + 'cpuSpeed quantization'); + +}, 'ComputePressureObserver with a new quantization schema stops all ' + + 'other active observers'); diff --git a/compute-pressure/compute_pressure_multiple.tentative.https.window.js b/compute-pressure/compute_pressure_multiple.tentative.https.window.js new file mode 100644 index 00000000000000..d1650cb873765e --- /dev/null +++ b/compute-pressure/compute_pressure_multiple.tentative.https.window.js @@ -0,0 +1,34 @@ +'use strict'; + +promise_test(async t => { + const update1_promise = new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const update2_promise = new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const update3_promise = new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const [update1, update2, update3] = + await Promise.all([update1_promise, update2_promise, update3_promise]); + + for (const update of [update1, update2, update3]) { + assert_in_array(update.cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + assert_in_array(update.cpuSpeed, [0.25, 0.75], 'cpuSpeed quantization'); + } +}, 'Three ComputePressureObserver instances with the same quantization ' + + 'schema receive updates'); diff --git a/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js b/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js new file mode 100644 index 00000000000000..5a020ad8a0cc55 --- /dev/null +++ b/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js @@ -0,0 +1,42 @@ +'use strict'; + +promise_test(async t => { + const update1_promise = new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + // iframe numbers are aligned with observer numbers. The first observer is in + // the main frame, so there is no iframe1. + const iframe2 = document.createElement('iframe'); + document.body.appendChild(iframe2); + + const update2_promise = new Promise((resolve, reject) => { + const observer = new iframe2.contentWindow.ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const iframe3 = document.createElement('iframe'); + document.body.appendChild(iframe3); + + const update3_promise = new Promise((resolve, reject) => { + const observer = new iframe3.contentWindow.ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + const [update1, update2, update3] = + await Promise.all([update1_promise, update2_promise, update3_promise]); + + for (const update of [update1, update2, update3]) { + assert_in_array(update.cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + assert_in_array(update.cpuSpeed, [0.25, 0.75], 'cpuSpeed quantization'); + } +}, 'Three ComputePressureObserver instances in different iframes, but with ' + + 'the same quantization schema, receive updates'); diff --git a/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js b/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js new file mode 100644 index 00000000000000..773512f4be5cda --- /dev/null +++ b/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js @@ -0,0 +1,27 @@ +'use strict'; + +promise_test(async t => { + // The quantization thresholds and the quantized values that they lead to can + // be represented exactly in floating-point, so === comparison works. + + const update = await new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + observer.observe().catch(reject); + observer.observe().catch(reject); + }); + + assert_equals(typeof update.cpuUtilization, 'number'); + assert_greater_than_equal(update.cpuUtilization, 0.0, 'cpuUtilization range'); + assert_less_than_equal(update.cpuUtilization, 1.0, 'cpuUtilization range'); + assert_in_array(update.cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + + assert_equals(typeof update.cpuSpeed, 'number'); + assert_greater_than_equal(update.cpuSpeed, 0.0, 'cpuSpeed range'); + assert_less_than_equal(update.cpuSpeed, 1.0, 'cpuUSpeed range'); + assert_in_array(update.cpuSpeed, [0.25, 0.75], 'cpuSpeed quantization'); +}, 'ComputePressureObserver.observe() is idempotent'); + diff --git a/compute-pressure/compute_pressure_stop.tentative.https.window.js b/compute-pressure/compute_pressure_stop.tentative.https.window.js new file mode 100644 index 00000000000000..5dbd50574692a9 --- /dev/null +++ b/compute-pressure/compute_pressure_stop.tentative.https.window.js @@ -0,0 +1,58 @@ +'use strict'; + +promise_test(async t => { + const observer1_updates = []; + const observer1 = new ComputePressureObserver( + update => { observer1_updates.push(update); }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer1.stop()); + // Ensure that observer1's schema gets registered before observer2 starts. + await observer1.observe(); + observer1.stop(); + + const observer2_updates = []; + await new Promise((resolve, reject) => { + const observer2 = new ComputePressureObserver( + update => { + observer2_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer2.stop()); + observer2.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer2_updates.length, 1); + assert_in_array(observer2_updates[0].cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + assert_in_array(observer2_updates[0].cpuSpeed, [0.25, 0.75], + 'cpuSpeed quantization'); + + // Go through one more update cycle so any (incorrect) update for observer1 + // makes it through the IPC queues. + + const observer3_updates = []; + await new Promise((resolve, reject) => { + const observer3 = new ComputePressureObserver( + update => { + observer3_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.75], cpuSpeedThresholds: [0.25]}); + t.add_cleanup(() => observer3.stop()); + observer3.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer3_updates.length, 1); + assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875], + 'cpuUtilization quantization'); + assert_in_array(observer3_updates[0].cpuSpeed, [0.125, 0.625], + 'cpuSpeed quantization'); + +}, 'Stopped ComputePressureObservers do not receive updates'); diff --git a/compute-pressure/compute_pressure_stop_idempotent.tentative.https.window.js b/compute-pressure/compute_pressure_stop_idempotent.tentative.https.window.js new file mode 100644 index 00000000000000..785c55be4dc0cc --- /dev/null +++ b/compute-pressure/compute_pressure_stop_idempotent.tentative.https.window.js @@ -0,0 +1,59 @@ +'use strict'; + +promise_test(async t => { + const observer1_updates = []; + const observer1 = new ComputePressureObserver( + update => { observer1_updates.push(update); }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer1.stop()); + // Ensure that observer1's schema gets registered before observer2 starts. + observer1.observe(); + observer1.stop(); + observer1.stop(); + + const observer2_updates = []; + await new Promise((resolve, reject) => { + const observer2 = new ComputePressureObserver( + update => { + observer2_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer2.stop()); + observer2.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer2_updates.length, 1); + assert_in_array(observer2_updates[0].cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + assert_in_array(observer2_updates[0].cpuSpeed, [0.25, 0.75], + 'cpuSpeed quantization'); + + // Go through one more update cycle so any (incorrect) update for observer1 + // makes it through the IPC queues. + + const observer3_updates = []; + await new Promise((resolve, reject) => { + const observer3 = new ComputePressureObserver( + update => { + observer3_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.75], cpuSpeedThresholds: [0.25]}); + t.add_cleanup(() => observer3.stop()); + observer3.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer3_updates.length, 1); + assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875], + 'cpuUtilization quantization'); + assert_in_array(observer3_updates[0].cpuSpeed, [0.125, 0.625], + 'cpuSpeed quantization'); + +}, 'Stopped ComputePressureObservers do not receive updates'); diff --git a/compute-pressure/compute_pressure_stop_immediately.tentative.https.window.js b/compute-pressure/compute_pressure_stop_immediately.tentative.https.window.js new file mode 100644 index 00000000000000..0d9929c47a9cbe --- /dev/null +++ b/compute-pressure/compute_pressure_stop_immediately.tentative.https.window.js @@ -0,0 +1,58 @@ +'use strict'; + +promise_test(async t => { + const observer1_updates = []; + const observer1 = new ComputePressureObserver( + update => { observer1_updates.push(update); }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer1.stop()); + // Ensure that observer1's schema gets registered before observer2 starts. + observer1.observe(); + observer1.stop(); + + const observer2_updates = []; + await new Promise((resolve, reject) => { + const observer2 = new ComputePressureObserver( + update => { + observer2_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.5], cpuSpeedThresholds: [0.5]}); + t.add_cleanup(() => observer2.stop()); + observer2.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer2_updates.length, 1); + assert_in_array(observer2_updates[0].cpuUtilization, [0.25, 0.75], + 'cpuUtilization quantization'); + assert_in_array(observer2_updates[0].cpuSpeed, [0.25, 0.75], + 'cpuSpeed quantization'); + + // Go through one more update cycle so any (incorrect) update for observer1 + // makes it through the IPC queues. + + const observer3_updates = []; + await new Promise((resolve, reject) => { + const observer3 = new ComputePressureObserver( + update => { + observer3_updates.push(update); + resolve(); + }, + {cpuUtilizationThresholds: [0.75], cpuSpeedThresholds: [0.25]}); + t.add_cleanup(() => observer3.stop()); + observer3.observe().catch(reject); + }); + + assert_equals(observer1_updates.length, 0, + 'stopped observers should not receive callbacks'); + + assert_equals(observer3_updates.length, 1); + assert_in_array(observer3_updates[0].cpuUtilization, [0.375, 0.875], + 'cpuUtilization quantization'); + assert_in_array(observer3_updates[0].cpuSpeed, [0.125, 0.625], + 'cpuSpeed quantization'); + +}, 'Stopped ComputePressureObservers do not receive updates'); diff --git a/compute-pressure/compute_pressure_values.tenative.https.window.js b/compute-pressure/compute_pressure_values.tenative.https.window.js new file mode 100644 index 00000000000000..837fa9d62df580 --- /dev/null +++ b/compute-pressure/compute_pressure_values.tenative.https.window.js @@ -0,0 +1,18 @@ +'use strict'; + +promise_test(async t => { + // The quantization thresholds and the quantized values that they lead to can + // be represented exactly in floating-point, so === comparison works. + + const update = await new Promise((resolve, reject) => { + const observer = new ComputePressureObserver( + resolve, + {cpuUtilizationThresholds: [0.25], cpuSpeedThresholds: [0.75]}); + t.add_cleanup(() => observer.stop()); + observer.observe().catch(reject); + }); + + assert_in_array(update.cpuUtilization, [0.125, 0.625], + 'cpuUtilization quantization'); + assert_in_array(update.cpuSpeed, [0.375, 0.875], 'cpuSpeed quantization'); +}, 'ComputePressureObserver quantizes utilization and speed separately');