ghaperf

module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: MIT

README

ghaperf

Ask DeepWiki

ghaperf analyzes the performance of GitHub Actions workflows using GitHub API and raw job logs. Unlike other tools, it can detect bottlenecks inside composite actions by parsing job logs and extracting step-level timing data.

Why ghaperf?

  1. Existing tools can't detect bottlenecks inside steps. ghaperf solves this by analyzing actions logs.
  2. Many existing tools need metrics storage, so the setup is bothersome and it costs 💸. ghaperf doesn't need any storage, so it's easy to use and free

Key Features

  • Deep visibility into composite actions - Detect bottlenecks inside composite actions that other tools miss
  • No infrastructure needed - Just a CLI tool, no backend or metrics storage required
  • Multiple analysis modes - Analyze workflows, workflow runs, or individual jobs
  • Markdown reports - Generate shareable performance reports
  • Intelligent caching - Cache GitHub API responses for completed runs to speed up analysis
  • Flexible filtering - Filter and normalize job names using configuration files

Quick Start

  1. Install ghaperf
  2. Set your GitHub Access token to download action logs
  3. Run ghaperf
export GITHUB_TOKEN=xxx

# Analyze a workflow across multiple runs
ghaperf --repo aquaproj/aqua-registry --workflow test.yaml --count 10 --threshold 2s
Example Report
Example Report Output

This report was generated by ghaperf.

ghaperf versionv0.1.1
Created At2025-11-02T21:03:34+09:00
Threshold2s
Repositoryaquaproj/aqua-registry
The Number of Workflow Runs10
Workflow Nametest.yaml

Job: test / test / test (macos-13)

Average Job Duration1m15s (11m11s/9)
Slowest Jobs8m25s, 24s, 23s
Slow steps
  1. 1m4s (8m31s/8): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 1m36s (7m58s/5): Run aqua i --test
    2. 16s (16s/1): Run rustup update
  2. 6s (48s/8): Set up job
    1. 6s (49s/8): GITHUB_TOKEN Permissions
  3. 4s (30s/8): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
  4. 4s (29s/8): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 3s (21s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then

Job: test / test / test (windows-latest, arm64)

Average Job Duration1m6s (10m59s/10)
Slowest Jobs6m19s, 41s, 39s
Slow steps
  1. 36s (5m57s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 5m4s (5m4s/1): Run aqua i --test
    2. 18s (18s/1): Run rustup update
    3. 2s (17s/8): Run aqua exec -- ci-info run | sed -E "s/^export //" >> "$GITHUB_ENV"
  2. 13s (2m10s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 11s (1m25s/8): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    2. 4s (36s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  3. 8s (1m23s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 2s (23s/10): Setting up auth
  4. 4s (38s/10): Set up job
    1. 4s (37s/10): GITHUB_TOKEN Permissions
  5. 2s (23s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 3s (18s/7): Run aqua i --test
    2. 6s (6s/1): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    3. 5s (5s/1): Checking out the ref

Job: test / test / test (windows-latest)

Average Job Duration1m4s (10m36s/10)
Slowest Jobs6m0s, 37s, 36s
Slow steps
  1. 34s (5m43s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 4m44s (4m44s/1): Run aqua i --test
    2. 20s (20s/1): Run rustup update
    3. 2s (17s/8): Run aqua exec -- ci-info run | sed -E "s/^export //" >> "$GITHUB_ENV"
    4. 2s (13s/6): Run if grep '- import:' aqua/test.yaml | sed 's| - import: ../(.*)/pkg.yaml|\1/registry.yaml|' | xargs cat | grep "type: cargo" > /dev/null 2>&1; then
  2. 13s (2m9s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 10s (1m22s/8): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    2. 5s (40s/8): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  3. 7s (1m12s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 2s (22s/10): Setting up auth
  4. 4s (39s/10): Set up job
    1. 4s (39s/10): GITHUB_TOKEN Permissions
  5. 2s (23s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
    1. 3s (18s/7): Run aqua i --test
    2. 5s (5s/1): Run $(if($env:AQUA_ROOT_DIR) {echo $env:AQUA_ROOT_DIR} else {echo "$HOME/AppData/Local/aquaproj-aqua/bin"}) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
    3. 5s (5s/1): Checking out the ref

Job: test / test / test (macos-14)

Average Job Duration34s (5m40s/10)
Slowest Jobs2m52s, 26s, 21s
Slow steps
  1. 19s (3m7s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 39s (2m37s/4): Run aqua i --test
    2. 10s (10s/1): Run rustup update
  2. 6s (55s/10): Set up job
    1. 5s (55s/10): GITHUB_TOKEN Permissions
  3. 3s (30s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
    1. 2s (24s/10): Run if [ "${SKIP_INSTALL_AQUA:-}" = true ] && command -v aqua >/dev/null; then
  4. 2s (21s/10): Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

Job: test / test / test (ubuntu-24.04)

Average Job Duration28s (4m42s/10)
Slowest Jobs2m46s, 18s, 15s
Slow steps
  1. 19s (3m5s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 32s (2m40s/5): Run aqua i --test
    2. 9s (9s/1): Run rustup update
  2. 3s (31s/10): Set up job
    1. 3s (32s/10): GITHUB_TOKEN Permissions

Job: test / test / test (ubuntu-24.04-arm)

Average Job Duration27s (4m32s/10)
Slowest Jobs2m30s, 16s, 16s
Slow steps
  1. 16s (2m43s/10): Run aquaproj/registry-action/test@68f10339de561d67f9acea40b91dc36aa5011ea8
    1. 22s (2m13s/6): Run aqua i --test
    2. 7s (7s/1): Run rustup update
  2. 3s (31s/10): Set up job
    1. 3s (31s/10): GITHUB_TOKEN Permissions
  3. 2s (24s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342

Job: test / lintnet / lintnet

Average Job Duration15s (2m34s/10)
Slowest Jobs19s, 18s, 18s
Slow steps
  1. 6s (59s/10): Run lintnet lint
    1. 8s (1m5s/8): Run lintnet lint
  2. 3s (30s/10): Run aquaproj/aqua-installer@ea518c135a02fc11ff8024364510c181a5c6b342
  3. 2s (22s/10): Post Run actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8

Job: test / ci-info / ci-info

Average Job Duration9s (1m33s/10)
Slowest Jobs12s, 12s, 10s
Slow steps
  1. 2s (22s/10): Run suzuki-shunsuke/ci-info-action/store@ceeb10dd50cd632db31e7eccf92cbbb6856f3191

Job: test / check-files / check-files

Average Job Duration5s (54s/10)
Slowest Jobs7s, 6s, 6s

The job has no slow steps

Job: test / path-filter

Average Job Duration4s (40s/10)
Slowest Jobs6s, 5s, 5s

The job has no slow steps

Job: status-check

Average Job Duration4s (7s/2)
Slowest Jobs3s, 4s

The job has no slow steps

Installation

See INSTALL.md for detailed installation instructions.

Usage

For complete usage documentation, see USAGE.md.

Prerequisites

A GitHub access token is required to download action logs. See GitHub Access Token for details.

export GITHUB_TOKEN=xxx
Analysis Modes
  1. Analyze multiple workflow runs (recommended for performance insights)
ghaperf \
  --repo suzuki-shunsuke/ghaperf \
  --workflow test.yaml \
  --count 10 \
  --threshold 2s

[!NOTE] Higher --count values provide better insights but take longer to process.

  1. Analyze a single workflow run
ghaperf \
  --repo "suzuki-shunsuke/tfaction" \
  --run-id "<workflow run id>"
  1. Analyze a specific job
ghaperf \
  --repo suzuki-shunsuke/tfaction \
  --job-id "<workflow job id>"
  1. Analyze a local log file
ghaperf --log-file path/to/job.log

See the example log file for format reference.

Configuration

Environment Variables
Variable Description Default
GHAPERF_LOG_LEVEL Log level: debug, info, warn, error info
GHAPERF_GITHUB_TOKEN GitHub access token -
GITHUB_TOKEN GitHub access token (alternative) -
GHAPERF_GHTKN Enable ghtkn integration false
GHAPERF_THRESHOLD Default threshold for slow steps/log groups 30s
GitHub Access Token

A GitHub access token is required to fetch workflow runs, jobs, and logs via the GitHub API.

[!WARNING] Even if repositories are public, an access token is required. This is a known issue of GitHub. https://github.com/orgs/community/discussions/24742

{
  "message": "Must have admin rights to Repository.",
  "documentation_url": "https://docs.github.com/rest/actions/workflow-jobs#download-job-logs-for-a-workflow-run",
  "status": "403"
}

The message says Must have admin rights to Repository., but actually we confirmed the message is wrong because non admin user can download logs.

Required Permissions:

  • Public repositories
  • Private repositories: Actions: Read permission

Setup:

# Option 1: Use GITHUB_TOKEN
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx

# Option 2: Use GHAPERF_GITHUB_TOKEN
export GHAPERF_GITHUB_TOKEN=ghp_xxxxxxxxxxxxx

# Option 3: Use ghtkn integration
export GHAPERF_GHTKN=true
Threshold

ghaperf reports steps and log groups that exceed the specified threshold:

Threshold Configuration:

  • Default: 30s
  • Set via --threshold flag or GHAPERF_THRESHOLD environment variable
  • Format: Go duration (e.g., 1s, 2m30s)
Configuration File

Use configuration files to filter jobs by job name and normalize job names. All settings are optional.

Scaffold the configuration file:

ghaperf --init # Generate ghaperf.yaml

Pass the configuration file:

ghperf --config <configuration file path> ...

e.g.

# Only analyze jobs matching these regular expressions
job_names:
  - "test / test / test .*"

# Exclude jobs matching these regular expressions
# excluded_job_names:
#   - "test / test / test .*"

# Normalize matrix job names for aggregation
job_name_mappings:
  "test / test / test .*": "test / test / test"

Available Fields:

  • job_names: List of regular expressions - only matching jobs are analyzed
  • excluded_job_names: List of regular expressions - matching jobs are excluded
  • job_name_mappings: Map of regular expressions to normalized names for matrix jobs and old job names

JSON Schema and Validation:

The configuration schema is available at json-schema/ghaperf.json.

Validate your configuration with ajv-cli:

ajv --spec=draft2020 -s json-schema/ghaperf.json -d ghaperf.yaml

IDE Support:

Enable auto-completion in your editor by adding this to your config file:

Latest version:

# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/ghaperf/main/json-schema/ghaperf.json

Or pin to a specific version:

# yaml-language-server: $schema=https://raw.githubusercontent.com/suzuki-shunsuke/ghaperf/v0.0.3/json-schema/ghaperf.json

Advanced Topics

Caching

ghaperf automatically caches API responses for completed workflow runs and jobs to improve performance on subsequent analyses.

Cache location: ${XDG_CACHE_HOME:-${HOME}/.cache}/ghaperf/

This speeds up repeated analyses and reduces API calls.

Group log lines

ref. Group log lines

By grouping log lines properly, you can analyze the performance using ghaperf more deeply. Especially, if a specific step (run step, JavaScript Action, or Docker Action) is doing various things and slow, you can analyze the bottlenecks inside the step by grouping log lines properly.

Important Notes

  1. Log availability timing: Job logs must be fully processed by GitHub. If a job just completed, the API may not have logs ready yet. Wait a few moments and retry.

  2. Log format changes: GitHub's log format is not officially documented. ghaperf parses logs based on observed patterns, which may break if GitHub changes the format unexpectedly.

  3. Log retention: GitHub retains workflow logs for 90 days by default. Analysis of older runs may fail if logs have been deleted.

While these tools are excellent for analyzing GitHub Actions performance, they don't provide step-level visibility into composite actions like ghaperf does. We don't aim to replace these tools with ghaperf. For this reason, it is not our intention to re-implement features already present in other tools, such as CIAnalyzer, in ghaperf. Rather, ghaperf preserves features that other tools are missing. Tools like CIAnalyzer are more suitable if you want to know how performance changes over the medium to long term. On the other hand, ghaperf is more suitable if you want to investigate current performance bottlenecks in more detail.

Directories

Path Synopsis
cmd
gen-jsonschema command
ghaperf command
pkg
cli
log
xdg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL