summaryrefslogtreecommitdiffstats
path: root/tools/profiler/tests/xpcshell/test_feature_fileioall.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /tools/profiler/tests/xpcshell/test_feature_fileioall.js
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/profiler/tests/xpcshell/test_feature_fileioall.js')
-rw-r--r--tools/profiler/tests/xpcshell/test_feature_fileioall.js171
1 files changed, 171 insertions, 0 deletions
diff --git a/tools/profiler/tests/xpcshell/test_feature_fileioall.js b/tools/profiler/tests/xpcshell/test_feature_fileioall.js
new file mode 100644
index 0000000000..97d55988d6
--- /dev/null
+++ b/tools/profiler/tests/xpcshell/test_feature_fileioall.js
@@ -0,0 +1,171 @@
+/* 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/. */
+
+// This is only needed for getting a temp file location, which IOUtils
+// cannot currently do.
+const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
+
+add_task(async () => {
+ if (!AppConstants.MOZ_GECKO_PROFILER) {
+ return;
+ }
+ info(
+ "Test that off-main thread fileio is captured for a profiled thread, " +
+ "and that it will be sent to the main thread."
+ );
+ const filename = "test_marker_fileio";
+ const profile = await startProfilerAndTriggerFileIO({
+ features: ["fileioall"],
+ threadsFilter: ["GeckoMain", "BackgroundThreadPool"],
+ filename,
+ });
+
+ const threads = getThreads(profile);
+ const mainThread = threads.find(thread => thread.name === "GeckoMain");
+ const mainThreadFileIO = getInflatedFileIOMarkers(mainThread, filename);
+ let backgroundThread;
+ let backgroundThreadFileIO;
+ for (const thread of threads) {
+ // Check for FileIO in any of the background threads.
+ if (thread.name.startsWith("BackgroundThreadPool")) {
+ const markers = getInflatedFileIOMarkers(thread, filename);
+ if (markers.length > 0) {
+ backgroundThread = thread;
+ backgroundThreadFileIO = markers;
+ break;
+ }
+ }
+ }
+
+ info("Check all of the main thread FileIO markers.");
+ checkInflatedFileIOMarkers(mainThreadFileIO, filename);
+ for (const { data, name } of mainThreadFileIO) {
+ equal(
+ name,
+ "FileIO (non-main thread)",
+ "The markers from off main thread are labeled as such."
+ );
+ equal(
+ data.threadId,
+ backgroundThread.tid,
+ "The main thread FileIO markers were all sent from the background thread."
+ );
+ }
+
+ info("Check all of the background thread FileIO markers.");
+ checkInflatedFileIOMarkers(backgroundThreadFileIO, filename);
+ for (const { data, name } of backgroundThreadFileIO) {
+ equal(
+ name,
+ "FileIO",
+ "The markers on the thread where they were generated just say FileIO"
+ );
+ equal(
+ data.threadId,
+ undefined,
+ "The background thread FileIO correctly excludes the threadId."
+ );
+ }
+});
+
+add_task(async () => {
+ if (!AppConstants.MOZ_GECKO_PROFILER) {
+ return;
+ }
+ info(
+ "Test that off-main thread fileio is captured for a thread that is not profiled, " +
+ "and that it will be sent to the main thread."
+ );
+ const filename = "test_marker_fileio";
+ const profile = await startProfilerAndTriggerFileIO({
+ features: ["fileioall"],
+ threadsFilter: ["GeckoMain"],
+ filename,
+ });
+
+ const threads = getThreads(profile);
+ const mainThread = threads.find(thread => thread.name === "GeckoMain");
+ const mainThreadFileIO = getInflatedFileIOMarkers(mainThread, filename);
+
+ info("Check all of the main thread FileIO markers.");
+ checkInflatedFileIOMarkers(mainThreadFileIO, filename);
+ for (const { data, name } of mainThreadFileIO) {
+ equal(
+ name,
+ "FileIO (non-profiled thread)",
+ "The markers from off main thread are labeled as such."
+ );
+ equal(typeof data.threadId, "number", "A thread ID is captured.");
+ }
+});
+
+/**
+ * @typedef {Object} TestConfig
+ * @prop {Array} features The list of profiler features
+ * @prop {string[]} threadsFilter The list of threads to profile
+ * @prop {string} filename A filename to trigger a write operation
+ */
+
+/**
+ * Start the profiler and get FileIO markers.
+ * @param {TestConfig}
+ * @returns {Profile}
+ */
+async function startProfilerAndTriggerFileIO({
+ features,
+ threadsFilter,
+ filename,
+}) {
+ const entries = 10000;
+ const interval = 10;
+ Services.profiler.StartProfiler(entries, interval, features, threadsFilter);
+
+ const tmpDir = OS.Constants.Path.tmpDir;
+ const path = OS.Path.join(tmpDir, filename);
+
+ info(`Using a temporary file to test FileIO: ${path}`);
+
+ if (fileExists(path)) {
+ console.warn(
+ "This test is triggering FileIO by writing to a file. However, the test found an " +
+ "existing file at the location it was trying to write to. This could happen " +
+ "because a previous run of the test failed to clean up after itself. This test " +
+ " will now clean up that file before running the test again."
+ );
+ await removeFile(path);
+ }
+
+ info("Write to the file, but do so using a background thread.");
+
+ // IOUtils handles file operations using a background thread.
+ await IOUtils.write(path, new TextEncoder().encode("Test data."));
+ const exists = await fileExists(path);
+ ok(exists, `Created temporary file at: ${path}`);
+
+ info("Remove the file");
+ await removeFile(path);
+
+ // Pause the profiler as we don't need to collect more samples as we retrieve
+ // and serialize the profile.
+ Services.profiler.Pause();
+
+ const profile = await Services.profiler.getProfileDataAsync();
+ Services.profiler.StopProfiler();
+ return profile;
+}
+
+async function fileExists(file) {
+ try {
+ let { type } = await IOUtils.stat(file);
+ return type === "regular";
+ } catch (_error) {
+ return false;
+ }
+}
+
+async function removeFile(file) {
+ await IOUtils.remove(file);
+ const exists = await fileExists(file);
+ ok(!exists, `Removed temporary file: ${file}`);
+}