diff --git a/.gitignore b/.gitignore index 2a878492247b..0ace1468feb8 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 31d7d911c987..fa69a81be8f6 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/deps/perfetto/perfetto.gyp b/deps/perfetto/perfetto.gyp index 083d0b386dd2..4dc03e867041 100644 --- a/deps/perfetto/perfetto.gyp +++ b/deps/perfetto/perfetto.gyp @@ -18,6 +18,11 @@ 'sources': [ '<@(perfetto_sdk_sources)', ], + 'conditions': [ + ['OS=="win"', { + 'defines': [ 'WIN32_LEAN_AND_MEAN' ], + }], + ], }, ] } diff --git a/node.gyp b/node.gyp index a626477c3805..7de0d5384d97 100644 --- a/node.gyp +++ b/node.gyp @@ -962,6 +962,10 @@ 'dependencies': [ 'deps/perfetto/perfetto.gyp:perfetto_sdk', ], + # node_internals.h includes perfetto.h. + 'export_dependent_settings': [ + 'deps/perfetto/perfetto.gyp:perfetto_sdk', + ], }], ], }, { @@ -1122,6 +1126,9 @@ 'dependencies': [ 'node_base', ], + 'export_dependent_settings': [ + 'node_base', + ], 'defines': [ 'NODE_ARCH="<(target_arch)"', diff --git a/test/common/trace_events.js b/test/common/trace_events.js index 67fc09193502..cbb5dbdcc60a 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 756dd9aeba63..6b78efd220b8 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 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 f00fee8b21e7..000000000000 --- 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 -, 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 000000000000..3bafc4dab345 --- /dev/null +++ b/tools/perfetto/get_trace_processor.py @@ -0,0 +1,67 @@ +#!/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 os +import platform +import shutil +import stat +import sys +import tempfile +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 -, which does not match what +# platform reports. +OS_NAMES = {'Darwin': 'mac', 'Linux': 'linux', 'Windows': 'windows'} +ARCH_NAMES = {'x86_64': 'amd64', 'amd64': 'amd64', 'arm64': 'arm64', 'aarch64': 'arm64'} + + +def release_name(): + os_name = OS_NAMES.get(platform.system()) + arch = ARCH_NAMES.get(platform.machine().lower()) + if os_name is None or arch is None: + sys.exit(f'No perfetto release for {platform.system()} {platform.machine()}') + # Perfetto releases only an x64 build for Windows. Windows on arm64 runs it + # under emulation. + if is_windows: + arch = 'amd64' + 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 tempfile.TemporaryFile() as archive: + with urllib.request.urlopen(url) as response: + shutil.copyfileobj(response, archive) + with zipfile.ZipFile(archive) as zf, \ + zf.open(f'{name}/{exe}') as src, \ + open(trace_processor, 'wb') as dst: + shutil.copyfileobj(src, dst) + + if not is_windows: + mode = os.stat(trace_processor).st_mode + os.chmod(trace_processor, mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + + +if __name__ == '__main__': + main() diff --git a/vcbuild.bat b/vcbuild.bat index d1a6d8fb7f30..bb79066b2b76 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." @@ -814,6 +817,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%