diff --git a/.github/workflows/pip-halidoscope.yml b/.github/workflows/pip-halidoscope.yml new file mode 100644 index 000000000000..30bd9ccc513d --- /dev/null +++ b/.github/workflows/pip-halidoscope.yml @@ -0,0 +1,109 @@ +name: Build Halidoscope wheels + +on: + workflow_dispatch: + pull_request: + paths: + - 'tools/halidoscope/**' + - '.github/workflows/pip-halidoscope.yml' + push: + branches: [ main ] + paths: + - 'tools/halidoscope/**' + - '.github/workflows/pip-halidoscope.yml' + +concurrency: + group: '${{ github.workflow }}-${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' + cancel-in-progress: true + +permissions: + contents: read + +# Halidoscope is a companion CLI/GUI packaged independently of Halide's own +# Python wheels (halide, halide-bin, halide-runtime): it doesn't depend on +# them, and this workflow doesn't participate in pip.yml's publish job. Its +# version is kept in sync with Halide's release version via tbump (see +# tool.tbump.file entries for tools/halidoscope/src-tauri/Cargo.toml et al. +# in the top-level pyproject.toml), not via a per-commit dynamic version. +jobs: + build: + name: Build wheel for ${{ matrix.platform_tag }} + + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + platform_tag: manylinux_x86_64 + - os: windows-latest + platform_tag: win_amd64 + - os: macos-15-intel + platform_tag: macosx_x86_64 + - os: macos-15 + platform_tag: macosx_arm64 + + steps: + - uses: actions/checkout@v7 + + - name: Install Tauri's Linux system dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + patchelf \ + build-essential \ + libxdo-dev \ + libssl-dev \ + libsoup-3.0-dev \ + xvfb + + - uses: dtolnay/rust-toolchain@stable + + - uses: pnpm/action-setup@v4 + with: + version: 11 + package_json_file: tools/halidoscope/package.json + + - uses: actions/setup-node@v5 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: tools/halidoscope/pnpm-lock.yaml + + - uses: astral-sh/setup-uv@v7 + + - name: Build frontend + working-directory: tools/halidoscope + run: | + pnpm install --frozen-lockfile + pnpm build + + - name: Build wheel + working-directory: tools/halidoscope + run: uvx maturin build --release --out wheelhouse + + - name: Smoke-test wheel + working-directory: tools/halidoscope + shell: bash + run: | + uv venv .smoke-test-venv + uv pip install --python .smoke-test-venv --no-index --find-links wheelhouse halidoscope + if [[ "${{ runner.os }}" == "Windows" ]]; then + ./.smoke-test-venv/Scripts/halidoscope --version + elif [[ "${{ runner.os }}" == "Linux" ]]; then + # tauri::Builder::run() initializes tao's GTK-backed event loop + # before dispatching to any CLI subcommand, so even `--version` + # needs a display on Linux. + xvfb-run -a ./.smoke-test-venv/bin/halidoscope --version + else + ./.smoke-test-venv/bin/halidoscope --version + fi + + - uses: actions/upload-artifact@v7 + with: + name: wheels-halidoscope-${{ matrix.platform_tag }} + path: tools/halidoscope/wheelhouse/*.whl diff --git a/pyproject.toml b/pyproject.toml index 7a259de5cc88..1f3e82390958 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -130,6 +130,18 @@ src = "vcpkg.json" [[tool.tbump.file]] src = "apps/vcpkg.json" +[[tool.tbump.file]] +src = "tools/halidoscope/src-tauri/Cargo.toml" +search = 'version = "{current_version}"' + +[[tool.tbump.file]] +src = "tools/halidoscope/src-tauri/tauri.conf.json" +search = '"version": "{current_version}"' + +[[tool.tbump.file]] +src = "tools/halidoscope/package.json" +search = '"version": "{current_version}"' + [[tool.tbump.file]] src = "src/runtime/HalideRuntime.h" version_template = "{major}" diff --git a/tools/halidoscope/README.md b/tools/halidoscope/README.md index b0f61dc0e2f4..2968392c4c83 100644 --- a/tools/halidoscope/README.md +++ b/tools/halidoscope/README.md @@ -15,6 +15,26 @@ You'll need a few prerequisites to get everything working. 4. [PNPM](https://pnpm.io/), a space-efficient package manager for the JavaScript ecosystem. +## Installing Halidoscope + +The easiest way to get `halidoscope` on your `PATH` is via pip: + +```bash +pip install halidoscope +``` + +This installs a prebuilt binary wheel containing both the GUI and the CLI. Note +that pip cannot install the system webview Halidoscope's GUI renders into +(WebKitGTK on Linux, WebView2 on Windows, WKWebView on macOS), so +[Tauri's system dependencies](https://v2.tauri.app/start/prerequisites/#system-dependencies) +must be present on Linux; macOS and Windows ship a compatible webview out of the +box. Currently, `halidoscope` initializes its windowing toolkit unconditionally +on startup, so on Linux this applies even to the non-interactive CLI subcommands +(`list`, `stats`, `dot`, `snapshot`) -- running any of them on a Linux host with +no display attached (e.g., a headless CI runner or container) additionally +requires a virtual display such as +[Xvfb](https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml). + ## Building Halidoscope To get a production build locally, run the following two commands: @@ -32,6 +52,25 @@ symlink this executable to any directory on your `PATH`. On Unix systems: ln -sf tools/halidoscope/src-tauri/target/release/halidoscope /some/dir/on/your/path/halidoscope ``` +### Building the pip package locally + +Halidoscope's wheel is built with [maturin](https://www.maturin.rs/), which +compiles `src-tauri`'s `halidoscope` binary and packages it directly (no Python +extension module involved). The frontend must be built first, since the binary +embeds `dist/` at compile time: + +```bash +pnpm install +pnpm build +pip install maturin +maturin build --release +``` + +`pyproject.toml` enables the `tauri/custom-protocol` Cargo feature for this +build. Without it, the compiled binary always tries to load its UI from Tauri's +dev server instead of the files embedded from `dist/`, so the resulting wheel's +GUI can't launch outside of `pnpm tauri dev`. + ## Using Halidoscope ### Calling Halidoscope from a Halide program @@ -83,14 +122,14 @@ Halidoscope directly from the command line to launch the GUI. To work with a pre-recorded trace, simply specify the path to a Halide trace binary file via the `--trace` flag. -```bash +```text halidoscope --trace ``` If you'd also like to visualize a pre-recorded profile JSON file, pass the path to that file via the `--profile` flag. Note that `--trace` is always required. -```bash +```text halidoscope --trace --profile ``` @@ -103,7 +142,7 @@ your Halide pipeline. List the `Func`s in a trace, along with their dimensionality. -```bash +```text halidoscope list --trace [--json] ``` @@ -115,7 +154,7 @@ halidoscope list --trace [--json] Print statistics (minimum/maximum coordinates, minimum/maximum value, maximum store/load counts, and thread count) for one or all `Func`s in a trace. -```bash +```text halidoscope stats --trace [--func ] [--json] ``` @@ -129,7 +168,7 @@ halidoscope stats --trace [--func ] [--json] Generate a [Graphviz DOT](https://graphviz.org/doc/info/lang.html) representation of the pipeline's dataflow graph. -```bash +```text halidoscope dot --trace [destination] ``` @@ -142,7 +181,7 @@ halidoscope dot --trace [destination] Snapshot a `Func`'s values at a given packet index for a given render mode, writing the underlying data to a JSON file. -```bash +```text halidoscope snapshot --trace --func [--packet-index ] [--mode ] ``` @@ -162,6 +201,9 @@ commands. ```bash pnpm install +``` + +```text pnpm tauri dev -- -- --trace [--profile ] ``` diff --git a/tools/halidoscope/package.json b/tools/halidoscope/package.json index e39f90d415a4..7587ef315533 100644 --- a/tools/halidoscope/package.json +++ b/tools/halidoscope/package.json @@ -1,7 +1,7 @@ { "name": "halidoscope", "private": true, - "version": "0.1.0", + "version": "22.0.0", "type": "module", "scripts": { "dev": "vite", diff --git a/tools/halidoscope/pyproject.toml b/tools/halidoscope/pyproject.toml new file mode 100644 index 000000000000..bc24fbef93ff --- /dev/null +++ b/tools/halidoscope/pyproject.toml @@ -0,0 +1,42 @@ +[build-system] +requires = ["maturin>=1.9,<2"] +build-backend = "maturin" + +[project] +name = "halidoscope" +authors = [{ name = "Parker Ziegler", email = "pziegler@adobe.com" }] +maintainers = [ + { name = "The Halide team", email = "halide-dev@lists.csail.mit.edu" }, +] +description = "An interactive GUI and CLI for working with Halide traces." +license = "MIT" +readme = "README.md" +requires-python = ">=3.10" +dynamic = ["version"] +keywords = ["halide", "trace", "profiling", "visualization", "gui"] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Natural Language :: English", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Programming Language :: Rust", + "Topic :: Scientific/Engineering :: Visualization", + "Topic :: Software Development :: Debuggers", +] + +[project.urls] +Homepage = "https://halide-lang.org" +Documentation = "https://github.com/halide/Halide/blob/main/tools/halidoscope/README.md" +Issues = "https://github.com/halide/Halide/issues" +Repository = "https://github.com/halide/Halide.git" + +[tool.maturin] +manifest-path = "src-tauri/Cargo.toml" +bindings = "bin" +strip = true +# Without this, the release binary falls back to loading the frontend from +# devUrl instead of embedding `dist/` -- see tauri/custom-protocol in +# src-tauri's Cargo.toml dependency graph. +features = ["tauri/custom-protocol"] diff --git a/tools/halidoscope/src-tauri/Cargo.lock b/tools/halidoscope/src-tauri/Cargo.lock index 61a4ba92f546..fcebe0cbeaab 100644 --- a/tools/halidoscope/src-tauri/Cargo.lock +++ b/tools/halidoscope/src-tauri/Cargo.lock @@ -1603,7 +1603,7 @@ dependencies = [ [[package]] name = "halidoscope" -version = "0.1.0" +version = "22.0.0" dependencies = [ "bindgen", "colorous", diff --git a/tools/halidoscope/src-tauri/Cargo.toml b/tools/halidoscope/src-tauri/Cargo.toml index fa4d693220cc..14b39418d787 100644 --- a/tools/halidoscope/src-tauri/Cargo.toml +++ b/tools/halidoscope/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "halidoscope" -version = "0.1.0" +version = "22.0.0" description = "An interactive visualizer for Halide traces." authors = ["Parker Ziegler "] edition = "2021" diff --git a/tools/halidoscope/src-tauri/tauri.conf.json b/tools/halidoscope/src-tauri/tauri.conf.json index 34025e8d645b..c1cc8c8e3b08 100644 --- a/tools/halidoscope/src-tauri/tauri.conf.json +++ b/tools/halidoscope/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Halidoscope", - "version": "0.1.0", + "version": "22.0.0", "identifier": "com.halide.halidoscope", "build": { "beforeDevCommand": "pnpm dev",