Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a22d435
assumeutxo benchmarking patch
josibake Nov 5, 2024
84c08e6
add shell.nix
willcl-ark Nov 8, 2024
0e10d89
add uv for python
willcl-ark Nov 8, 2024
87f028e
add justfile
willcl-ark Nov 8, 2024
0dca141
add benchmarking ci workflows
willcl-ark Nov 8, 2024
0ceefb0
Show mainnet results first
andrewtoth Dec 3, 2024
e29d241
isolate benchmark and perf to cores
willcl-ark Dec 18, 2024
68e47f9
use nix 24.11 in shell.nix
willcl-ark Dec 29, 2024
92df3f7
add util-linux for taskset
willcl-ark Dec 29, 2024
0c362c8
remove unneeded install nix action
willcl-ark Dec 31, 2024
d158c68
use ccache with persistent dir
willcl-ark Dec 31, 2024
05e3182
use isolated cores for build
willcl-ark Jan 6, 2025
89063f9
signet 170000 & main 860000
l0rinc Dec 22, 2024
731d866
add speedups to PR comment
l0rinc Dec 22, 2024
e3a387a
try using gh instead of actions
l0rinc Dec 22, 2024
f2b075f
Widen the flames to 80% of the page width
l0rinc Dec 22, 2024
1d60a8d
Turn off unused options during build
l0rinc Dec 22, 2024
d5e17c6
add dbcache parameter, turn off console printing and add a network wi…
l0rinc Dec 22, 2024
60c9fb4
fixup publish job
willcl-ark Jan 6, 2025
38411e3
fixup typo in bench script
willcl-ark Jan 6, 2025
95b388b
Add parser & plotter for time, block height & cache size
l0rinc Jan 2, 2025
26071da
streamline ci
willcl-ark Jan 6, 2025
85774fe
streamline shell.nix
willcl-ark Jan 7, 2025
2155824
use max datadir on large run
willcl-ark Jan 7, 2025
76a5ae8
add local signet command
willcl-ark Jan 7, 2025
1d834ad
use flamegraph-rs
willcl-ark Jan 7, 2025
f3e9c30
perf frequency 99
willcl-ark Jan 6, 2025
56ff641
Don't show output in hyperfine
l0rinc Jan 7, 2025
c5b1ec9
Disable remaining unnecessary cmake modules
l0rinc Jan 7, 2025
4db595f
move flamegraph properly
willcl-ark Jan 7, 2025
d83a827
TODO speed up feedback-loop temporarily
l0rinc Jan 7, 2025
25d4d0f
801000 -> 841000
l0rinc Jan 7, 2025
d13b665
Increase plot resolution & Coins Cache Size vs Time
l0rinc Jan 7, 2025
73cdf70
Add leveldb, bench, validation and coindb debug log
l0rinc Jan 7, 2025
06dcefb
Publish all pngs
l0rinc Jan 7, 2025
f4963af
Rename `master` back to `main`
l0rinc Jan 7, 2025
256c854
Fix posted URL
l0rinc Jan 8, 2025
051a06c
Restore signet & main block counts
l0rinc Jan 8, 2025
5622ea6
fix flame viewport height
willcl-ark Jan 8, 2025
5800b66
Compile with debug symbols
l0rinc Jan 8, 2025
833ef1a
Reduce flame font size
l0rinc Jan 8, 2025
c9193b7
Increase signet to 220k
l0rinc Jan 8, 2025
59218d7
Revert: Reduce flame font size
l0rinc Jan 8, 2025
128abd9
m_coinstip_cache_size_bytes
l0rinc Jan 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
364 changes: 89 additions & 275 deletions .github/workflows/ci.yml

Large diffs are not rendered by default.

293 changes: 293 additions & 0 deletions .github/workflows/publish-results.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
name: Publish Results
on:
workflow_run:
workflows: ["CI"]
types: [completed]
jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
permissions:
actions: read
contents: write
checks: read
env:
NETWORKS: "mainnet-default,mainnet-large,signet"
outputs:
speedups: ${{ steps.organize.outputs.speedups }}
pr-number: ${{ steps.organize.outputs.pr-number }}
steps:
- uses: actions/checkout@v4
with:
ref: gh-pages
- name: Download artifacts
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh run download ${{ github.event.workflow_run.id }} --repo ${{ github.repository }}

- name: Extract artifacts
run: |
for network in ${NETWORKS//,/ }; do
if [ -d "result-${network}" ]; then
mkdir -p "${network}-results"
mv "result-${network}/results.json" "${network}-results/"
fi

if [ -d "flamegraph-${network}" ]; then
mkdir -p "${network}-flamegraph"
mv "flamegraph-${network}"/* "${network}-flamegraph/"
fi

if [ -d "run-metadata-${network}" ]; then
mkdir -p "${network}-metadata"
mv "run-metadata-${network}"/* "${network}-metadata/"
fi

if [ -d "pngs-${network}" ]; then
mkdir -p "${network}-plots"
mv "pngs-${network}"/*.png "${network}-plots/"
fi
done
- name: Organize results
id: organize
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const networks = process.env.NETWORKS.split(',');
let prNumber = 'main';
let runId;

// First, extract metadata and get PR number
for (const network of networks) {
if (fs.existsSync(`${network}-metadata/github.json`)) {
const metadata = JSON.parse(fs.readFileSync(`${network}-metadata/github.json`, 'utf8'));
prNumber = metadata.event.pull_request?.number || prNumber;
runId = metadata.run_id;
}
}

if (!runId) {
console.error('No valid metadata found for any network');
process.exit(1);
}

// Create directory structure
const resultDir = `results/pr-${prNumber}/${runId}`;
fs.mkdirSync(resultDir, { recursive: true });

// Now copy metadata files
for (const network of networks) {
if (fs.existsSync(`${network}-metadata/github.json`)) {
const metadataDir = `${resultDir}/${network}-metadata`;
fs.mkdirSync(metadataDir, { recursive: true });
fs.copyFileSync(`${network}-metadata/github.json`, `${metadataDir}/github.json`);
}
}

// Process each network's results
const combinedResults = {
results: [],
speedups: {}
};

for (const network of networks) {
if (fs.existsSync(`${network}-results`)) {
const networkResults = JSON.parse(fs.readFileSync(`${network}-results/results.json`, 'utf8'));
let baseMean, headMean;

// Add network name to each result and collect means
networkResults.results.forEach(result => {
result.network = network;
combinedResults.results.push(result);
if (result.command.includes('base')) {
baseMean = result.mean;
} else if (result.command.includes('head')) {
headMean = result.mean;
}
});

// Calculate speedup if we have both measurements
if (baseMean && headMean) {
const speedup = baseMean > 0 ? ((baseMean - headMean) / baseMean * 100).toFixed(1) : 'N/A';
combinedResults.speedups[network] = speedup;
}

// Move flamegraphs
if (fs.existsSync(`${network}-flamegraph`)) {
fs.readdirSync(`${network}-flamegraph`).forEach(file => {
const sourceFile = `${network}-flamegraph/${file}`;
const targetFile = `${resultDir}/${network}-${file}`;
fs.copyFileSync(sourceFile, targetFile);
});
}

// Move plots
if (fs.existsSync(`${network}-plots`)) {
const targetPlotsDir = `${resultDir}/${network}-plots`;
fs.mkdirSync(targetPlotsDir, { recursive: true });
fs.readdirSync(`${network}-plots`).forEach(plot => {
const sourcePlot = `${network}-plots/${plot}`;
const targetPlot = `${targetPlotsDir}/${plot}`;
fs.copyFileSync(sourcePlot, targetPlot);
});
}
}
}

// Write combined results
fs.writeFileSync(`${resultDir}/results.json`, JSON.stringify(combinedResults, null, 2));

// Create index.html for this run
const indexHtml = `<!DOCTYPE html>
<html>
<head>
<title>Benchmark Results</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 p-8">
<div class="w-4/5 mx-auto">
<h1 class="text-3xl font-bold mb-8">Benchmark Results</h1>
<div class="bg-white rounded-lg shadow p-6 mb-8">
<h2 class="text-xl font-semibold mb-4">PR #${prNumber} - Run ${runId}</h2>
${networks.map(network => `
<div class="mb-8">
<h3 class="text-lg font-semibold mb-4 capitalize">
${network} Results
${combinedResults.speedups[network] ?
`<span class="text-sm font-normal ml-2">(${combinedResults.speedups[network]}% speedup)</span>`
: ''}
</h3>
<div class="overflow-x-auto">
${combinedResults.results
.filter(result => result.network === network)
.map(result => {
const commitShortId = result.parameters.commit.slice(0, 8);
const flameGraphFile = `${network}-${result.parameters.commit}-flamegraph.svg`;
const flameGraphPath = `${resultDir}/${network}-${result.parameters.commit}-flamegraph.svg`;

// Query PNG files dynamically
const plotDir = `${resultDir}/${network}-plots`;
const plots = fs.existsSync(plotDir)
? fs.readdirSync(plotDir)
.map(plot => `<img src="${network}-plots/${plot}" alt="${plot}" class="mb-4 max-w-full h-auto">`)
.join('')
: '';

return `
<table class="min-w-full table-auto mb-4">
<thead>
<tr class="bg-gray-50">
<th class="px-4 py-2">Branch</th>
<th class="px-4 py-2">Command</th>
<th class="px-4 py-2">Mean (s)</th>
<th class="px-4 py-2">Std Dev</th>
<th class="px-4 py-2">User (s)</th>
<th class="px-4 py-2">System (s)</th>
</tr>
</thead>
<tbody>
<tr class="border-t">
<td class="px-4 py-2 font-mono text-sm">
<a href="https://github.com/bitcoin-dev-tools/benchcoin/commit/${commitShortId}">${commitShortId}</a>
</td>
<td class="px-4 py-2 font-mono text-sm">${result.command}</td>
<td class="px-4 py-2 text-right">${result.mean.toFixed(3)}</td>
<td class="px-4 py-2 text-right">${result.stddev?.toFixed(3) || 'N/A'}</td>
<td class="px-4 py-2 text-right">${result.user.toFixed(3)}</td>
<td class="px-4 py-2 text-right">${result.system.toFixed(3)}</td>
</tr>
</tbody>
</table>
${fs.existsSync(flameGraphPath) ? `
<object data="${flameGraphFile}" type="image/svg+xml" width="100%" style="height: 100%;" class="mb-4"></object>
` : ''}
${plots}
`;
}).join('')}
</div>
</div>
`).join('')}
</div>
</div>
</body>
</html>`;

fs.writeFileSync(`${resultDir}/index.html`, indexHtml);

// Update main index.html
const prs = fs.readdirSync('results')
.filter(dir => dir.startsWith('pr-'))
.map(dir => ({
pr: dir.replace('pr-', ''),
runs: fs.readdirSync(`results/${dir}`)
}));

const mainIndexHtml = `<!DOCTYPE html>
<html>
<head>
<title>Bitcoin Benchmark Results</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100 p-8">
<div class="w-4/5 mx-auto">
<h1 class="text-3xl font-bold mb-8">Bitcoin Benchmark Results</h1>
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-xl font-semibold mb-4">Available Results</h2>
<ul class="space-y-2">
${prs.map(({pr, runs}) => `
<li class="font-semibold">PR #${pr}
<ul class="ml-8 space-y-1">
${runs.map(run => `
<li><a href="results/pr-${pr}/${run}/index.html" class="text-blue-600 hover:underline">Run ${run}</a></li>
`).join('')}
</ul>
</li>
`).join('')}
</ul>
</div>
</div>
</body>
</html>`;

fs.writeFileSync('index.html', mainIndexHtml);

// Set outputs for use in PR comment
const resultUrl = `https://${context.repo.owner}.github.io/${context.repo.name}/results/pr-${prNumber}/${runId}/index.html`;
const speedupString = Object.entries(combinedResults.speedups)
.map(([network, speedup]) => `${network}: ${speedup}%`)
.join(', ');

core.setOutput('result-url', resultUrl);
core.setOutput('speedups', speedupString);
core.setOutput('pr-number', prNumber);
return { url: resultUrl, speedups: speedupString };
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: results
- name: Commit and push to gh-pages
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add results/ index.html
git commit -m "Update benchmark results from run ${{ github.event.workflow_run.id }}"
git push origin gh-pages
comment-pr:
needs: build
runs-on: ubuntu-latest
permissions:
pull-requests: write
actions: read
steps:
- name: Comment on PR
if: ${{ needs.build.outputs.pr-number != 'main' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment ${{ needs.build.outputs.pr-number }} \
--repo ${{ github.repository }} \
--body "📊 Benchmark results for this run (${{ github.event.workflow_run.id }}) will be available at: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/results/pr-${{ needs.build.outputs.pr-number }}/${{ github.event.workflow_run.id }}/index.html after the github pages \"build and deployment\" action has completed.
🚀 Speedups: ${{ needs.build.outputs.speedups }}"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ test/lint/test_runner/target/
/guix-build-*

/ci/scratch/
utxo-signet-160000.dat
Loading