Commit ca277a62947 for nodejs

commit ca277a62947bd9313acbfd3acd7b0a2f5f1e0a31
Author: Chengzhong Wu <legendecas@gmail.com>
Date:   Fri Oct 23 18:01:33 2026 -0400

    build,test: setup perfetto tests on windows build

    Signed-off-by: Chengzhong Wu <cwu631@bloomberg.net>
    PR-URL: https://github.com/nodejs/node/pull/66731
    Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
    Reviewed-By: Filip Skokan <panva.ip@gmail.com>

diff --git a/.gitignore b/.gitignore
index 9ba14770743..84c35fbdd94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,7 @@ tools/*/*.i.tmp

 # === Rules for tools/perfetto ===
 /tools/perfetto/trace_processor_shell
+/tools/perfetto/trace_processor_shell.exe

 # === Rules for test artifacts ===
 /*.tap
diff --git a/Makefile b/Makefile
index a4de0b2d683..361fed3df4c 100644
--- a/Makefile
+++ b/Makefile
@@ -349,7 +349,7 @@ TRACE_PROCESSOR_SHELL_DEPS = deps/perfetto/VERSION
 endif

 $(TRACE_PROCESSOR_SHELL_PATH): $(TRACE_PROCESSOR_SHELL_DEPS)
-	@tools/perfetto/get_trace_processor $@
+	@$(PYTHON) tools/perfetto/get_trace_processor.py $@

 .PHONY: test
 # This does not run tests of third-party libraries inside deps.
diff --git a/test/common/trace_events.js b/test/common/trace_events.js
index 67fc0919350..cbb5dbdcc60 100644
--- a/test/common/trace_events.js
+++ b/test/common/trace_events.js
@@ -4,7 +4,8 @@
 // binary format.
 // This depends on perfetto's `trace_processor_shell` converts to pftrace format
 // to JSON format. Run `make tools/perfetto/trace_processor_shell` to download
-// it, or point `TRACE_PROCESSOR_SHELL_PATH` at an existing build of it.
+// it (`vcbuild test` does so on Windows), or point `TRACE_PROCESSOR_SHELL_PATH`
+// at an existing build of it.

 const assert = require('assert');
 const { spawnSync } = require('child_process');
@@ -14,7 +15,8 @@ const common = require('./');

 const traceProcessor = path.resolve(
   __dirname, '..', '..',
-  process.env.TRACE_PROCESSOR_SHELL_PATH || 'tools/perfetto/trace_processor_shell');
+  process.env.TRACE_PROCESSOR_SHELL_PATH ||
+    `tools/perfetto/trace_processor_shell${common.isWindows ? '.exe' : ''}`);

 // The JSON form of a trace runs about three times the size of the trace it was
 // converted from, and the traces these tests produce are a few hundred KiB at
@@ -29,7 +31,7 @@ const defaultTraceFileName = `node_trace.1.${traceFileExt}`;
 function checkTraceProcessor() {
   if (common.hasPerfetto && !fs.existsSync(traceProcessor)) {
     assert.fail('trace_processor_shell is missing, ' +
-                'run `make tools/perfetto/trace_processor_shell` to download it');
+                'run `python3 tools/perfetto/get_trace_processor.py` to download it');
   }
 }

diff --git a/test/trace_events/README.md b/test/trace_events/README.md
index 756dd9aeba6..6b78efd220b 100644
--- a/test/trace_events/README.md
+++ b/test/trace_events/README.md
@@ -2,10 +2,12 @@

 When the `node` binary is built with configure flag `--with-perfetto`,
 the tests in this folder depends on `tools/perfetto/trace_processor_shell`,
-which is downloaded with `tools/perfetto/get_trace_processor` via
+which is downloaded with `tools/perfetto/get_trace_processor.py` via
 `make tools/perfetto/trace_processor_shell`, to convert Perfetto binary trace
-files to JSON format. Set `TRACE_PROCESSOR_SHELL_PATH` to use an existing build
-of the tool instead of downloading a release.
+files to JSON format. On Windows, `vcbuild.bat` downloads
+`tools/perfetto/trace_processor_shell.exe` with the same script before running
+the tests. Set `TRACE_PROCESSOR_SHELL_PATH` to use an existing build of the
+tool instead of downloading a release.

 Refer to <https://perfetto.dev/docs/reference/trace-processor-cli>
 for help of the `trace_processor_shell` CLI.
diff --git a/tools/perfetto/get_trace_processor b/tools/perfetto/get_trace_processor
deleted file mode 100755
index f00fee8b21e..00000000000
--- a/tools/perfetto/get_trace_processor
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/sh
-# Downloads perfetto's trace_processor_shell, matching the SDK version vendored
-# in deps/perfetto. The trace events tests read back the binary traces that
-# perfetto builds write through this tool.
-set -e
-
-script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
-version=$(cat "$script_dir/../../deps/perfetto/VERSION")
-trace_processor="${1:-$script_dir/trace_processor_shell}"
-
-# Perfetto names its release archives <os>-<arch>, which does not match uname.
-case "$(uname -s)" in
-  Darwin) os=mac ;;
-  Linux) os=linux ;;
-  *) echo "No perfetto release for $(uname -s)" >&2; exit 1 ;;
-esac
-
-case "$(uname -m)" in
-  x86_64 | amd64) arch=amd64 ;;
-  arm64 | aarch64) arch=arm64 ;;
-  *) echo "No perfetto release for $(uname -m)" >&2; exit 1 ;;
-esac
-
-url="https://github.com/google/perfetto/releases/download/v$version/$os-$arch.zip"
-archive=$(mktemp)
-
-rm -f "$trace_processor"
-echo "Downloading $url"
-curl -sSfL -o "$archive" "$url"
-unzip -q -j -o "$archive" '*/trace_processor_shell' -d "$script_dir"
-rm -f "$archive"
-chmod +x "$trace_processor"
-# The archive carries the release's own mtime. Make decides whether the tool is
-# current by comparing it against deps/perfetto/VERSION, so it has to come out
-# newer than the version file it was downloaded for.
-touch "$trace_processor"
diff --git a/tools/perfetto/get_trace_processor.py b/tools/perfetto/get_trace_processor.py
new file mode 100755
index 00000000000..ed519922b19
--- /dev/null
+++ b/tools/perfetto/get_trace_processor.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+# Downloads perfetto's trace_processor_shell, matching the SDK version vendored
+# in deps/perfetto. The trace events tests read back the binary traces that
+# perfetto builds write through this tool.
+
+import io
+import os
+import platform
+import sys
+import urllib.request
+import zipfile
+
+script_dir = os.path.dirname(os.path.abspath(__file__))
+version_file = os.path.join(script_dir, '..', '..', 'deps', 'perfetto', 'VERSION')
+is_windows = platform.system() == 'Windows'
+
+# Perfetto names its release archives <os>-<arch>, which does not match what
+# platform reports.
+OS_NAMES = {'Darwin': 'mac', 'Linux': 'linux'}
+ARCH_NAMES = {'x86_64': 'amd64', 'arm64': 'arm64', 'aarch64': 'arm64'}
+
+
+def release_name():
+  # Perfetto releases only an x64 build for Windows. Windows on arm64 runs it
+  # under emulation.
+  if is_windows:
+    return 'windows-amd64'
+
+  os_name = OS_NAMES.get(platform.system())
+  arch = ARCH_NAMES.get(platform.machine())
+  if os_name is None or arch is None:
+    sys.exit(f'No perfetto release for {platform.system()} {platform.machine()}')
+  return f'{os_name}-{arch}'
+
+
+def main():
+  exe = 'trace_processor_shell.exe' if is_windows else 'trace_processor_shell'
+  trace_processor = sys.argv[1] if len(sys.argv) > 1 else os.path.join(script_dir, exe)
+
+  # The tool is current when it is newer than the version file it was
+  # downloaded for, so a version bump re-downloads it.
+  if (os.path.exists(trace_processor) and
+      os.path.getmtime(trace_processor) > os.path.getmtime(version_file)):
+    return
+
+  with open(version_file) as f:
+    version = f.read().strip()
+  name = release_name()
+  url = f'https://github.com/google/perfetto/releases/download/v{version}/{name}.zip'
+
+  print(f'Downloading {url}')
+  with urllib.request.urlopen(url) as response:
+    archive = zipfile.ZipFile(io.BytesIO(response.read()))
+  print(f'Extracting {name}/{exe} to {trace_processor}')
+  with open(trace_processor, 'wb') as dst:
+    dst.write(archive.read(f'{name}/{exe}'))
+  os.chmod(trace_processor, 0o755)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/vcbuild.bat b/vcbuild.bat
index 8b8c393133c..2e7a569ef73 100644
--- a/vcbuild.bat
+++ b/vcbuild.bat
@@ -85,6 +85,7 @@ set compile_commands=
 set cfg=
 set v8temporal=
 set v8windbg=
+set with_perfetto=
 set exit_code=0

 :next-arg
@@ -116,6 +117,7 @@ if /i "%1"=="pgo-generate"  set pgo_generate=1&goto arg-ok
 if /i "%1"=="pgo-use"       set pgo_use=1&goto arg-ok
 if /i "%1"=="v8temporal"    set v8temporal=1&goto arg-ok
 if /i "%1"=="v8windbg"      set v8windbg=1&goto arg-ok
+if /i "%1"=="with-perfetto" set with_perfetto=1&goto arg-ok
 if /i "%1"=="licensertf"    set licensertf=1&goto arg-ok
 if /i "%1"=="test"          set test_args=%test_args% %common_test_suites%&set lint_cpp=1&set lint_js=1&set lint_md=1&goto arg-ok
 if /i "%1"=="test-ci-native" set test_args=%test_args% %test_ci_args% -p tap --logfile test.tap %CI_NATIVE_SUITES% %CI_DOC%&set build_addons=1&set build_js_native_api_tests=1&set build_node_api_tests=1&set build_ffi_tests=1&set cctest_args=%cctest_args% --gtest_output=xml:cctest.junit.xml&goto arg-ok
@@ -272,6 +274,7 @@ if defined compile_commands set configure_flags=%configure_flags% -C
 if defined cfg              set configure_flags=%configure_flags% --control-flow-guard
 if defined v8temporal       set configure_flags=%configure_flags% --v8-enable-temporal-support
 if defined v8windbg         set configure_flags=%configure_flags% --enable-v8windbg
+if defined with_perfetto    set configure_flags=%configure_flags% --with-perfetto

 if "%target_arch%"=="x86" (
   echo "32-bit Windows builds are not supported anymore."
@@ -826,6 +829,13 @@ echo running 'cctest %cctest_args%'
 "%config%\cctest" %cctest_args%
 if %errorlevel% neq 0 set exit_code=%errorlevel%
 :run-test-py
+@rem Download trace_processor_shell for perfetto builds.
+if defined TRACE_PROCESSOR_SHELL_PATH goto run-test-py-start
+findstr /r /c:"v8_use_perfetto.: 1," config.gypi >nul 2>&1
+if errorlevel 1 goto run-test-py-start
+python tools\perfetto\get_trace_processor.py
+if errorlevel 1 exit /b 1
+:run-test-py-start
 echo running 'python tools\test.py %test_args%'
 python tools\test.py %test_args%
 if %errorlevel% neq 0 set exit_code=%errorlevel%