-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix/lock-async-circuits
- Loading branch information
Showing
198 changed files
with
5,422 additions
and
5,105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
name: Benchmark o1js | ||
on: | ||
push: | ||
branches: | ||
- main | ||
- berkeley | ||
- develop | ||
pull_request: | ||
workflow_dispatch: {} | ||
|
||
jobs: | ||
benchmarks: | ||
timeout-minutes: 30 | ||
strategy: | ||
fail-fast: true | ||
matrix: | ||
node: [20] | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
- name: Setup Node.JS ${{ matrix.node }} | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node }} | ||
- name: Build o1js and execute benchmarks on ${{ matrix.os }} and Node.JS ${{ matrix.node }} | ||
env: | ||
GIT_BRANCH: ${{ github.head_ref || github.ref_name }} | ||
INFLUXDB_URL: ${{ secrets.INFLUXDB_URL }} | ||
INFLUXDB_ORG: ${{ secrets.INFLUXDB_ORG }} | ||
INFLUXDB_BUCKET: ${{ secrets.INFLUXDB_BUCKET }} | ||
INFLUXDB_TOKEN: ${{ secrets.INFLUXDB_TOKEN }} | ||
METRICS_SOURCE_ENVIRONMENT: 'o1js GitHub Actions' | ||
METRICS_BASE_BRANCH_FOR_COMPARISON: 'main' | ||
run: | | ||
git submodule update --init --recursive | ||
npm ci | ||
npm run build | ||
echo 'Running o1js benchmarks.' | ||
node --enable-source-maps --stack-trace-limit=1000 src/build/run.js benchmark/runners/with-cloud-history.ts --bundle >>benchmarks.log 2>&1 | ||
cat benchmarks.log >> $GITHUB_STEP_SUMMARY | ||
shell: bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/** | ||
* ECDSA benchmark | ||
*/ | ||
|
||
import { Provable } from 'o1js'; | ||
import { | ||
Bytes32, | ||
Ecdsa, | ||
Secp256k1, | ||
keccakAndEcdsa, | ||
} from '../../src/examples/crypto/ecdsa/ecdsa.js'; | ||
import { benchmark } from '../benchmark.js'; | ||
|
||
let privateKey = Secp256k1.Scalar.random(); | ||
let publicKey = Secp256k1.generator.scale(privateKey); | ||
let message = Bytes32.fromString("what's up"); | ||
let signature = Ecdsa.sign(message.toBytes(), privateKey.toBigInt()); | ||
|
||
const EcdsaBenchmark = benchmark( | ||
'ecdsa', | ||
async (tic, toc) => { | ||
tic('build constraint system'); | ||
await keccakAndEcdsa.analyzeMethods(); | ||
toc(); | ||
|
||
tic('witness generation'); | ||
await Provable.runAndCheck(async () => { | ||
let message_ = Provable.witness(Bytes32.provable, () => message); | ||
let signature_ = Provable.witness(Ecdsa.provable, () => signature); | ||
let publicKey_ = Provable.witness(Secp256k1.provable, () => publicKey); | ||
await keccakAndEcdsa.rawMethods.verifyEcdsa( | ||
message_, | ||
signature_, | ||
publicKey_ | ||
); | ||
}); | ||
toc(); | ||
}, | ||
// two warmups to ensure full caching | ||
{ numberOfWarmups: 2, numberOfRuns: 5 } | ||
); | ||
|
||
export default EcdsaBenchmark; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* Simple benchmarks runner | ||
* Exercises benchmarks and logs the results | ||
* | ||
* Run with | ||
* ``` | ||
* ./run benchmark/runners/simple.ts --bundle | ||
* ``` | ||
*/ | ||
|
||
import { logResult } from '../benchmark.js'; | ||
import EcdsaBenchmark from '../benchmarks/ecdsa.js'; | ||
|
||
// Run all benchmarks | ||
const results = [...(await EcdsaBenchmark.run())]; | ||
|
||
// Process and log results | ||
for (const result of results) { | ||
logResult(result); | ||
console.log('\n'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* Benchmarks runner with historical data preservation in cloud storage (InfluxDB) | ||
* | ||
* Run with | ||
* ``` | ||
* ./run benchmark/runners/with-cloud-history.ts --bundle | ||
* ``` | ||
*/ | ||
|
||
import { logResult } from '../benchmark.js'; | ||
import EcdsaBenchmark from '../benchmarks/ecdsa.js'; | ||
import { | ||
readPreviousResultFromInfluxDb, | ||
writeResultToInfluxDb, | ||
} from '../utils/influxdb-utils.js'; | ||
|
||
// Run all benchmarks | ||
const results = [...(await EcdsaBenchmark.run())]; | ||
|
||
// Process and log results | ||
for (const result of results) { | ||
const previousResult = await readPreviousResultFromInfluxDb(result); | ||
logResult(result, previousResult); | ||
writeResultToInfluxDb(result); | ||
console.log('\n'); | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/** | ||
* InfluxDB utils | ||
*/ | ||
|
||
import { InfluxDB, Point } from '@influxdata/influxdb-client'; | ||
import os from 'node:os'; | ||
import { BenchmarkResult, calculateBounds } from '../benchmark.js'; | ||
|
||
const INFLUXDB_CLIENT_OPTIONS = { | ||
url: process.env.INFLUXDB_URL, | ||
token: process.env.INFLUXDB_TOKEN, | ||
org: process.env.INFLUXDB_ORG, | ||
bucket: process.env.INFLUXDB_BUCKET, | ||
}; | ||
const INFLUXDB_COMMON_POINT_TAGS = { | ||
sourceEnvironment: process.env.METRICS_SOURCE_ENVIRONMENT ?? 'local', | ||
operatingSystem: `${os.type()} ${os.release()} ${os.arch()}`, | ||
hardware: `${os.cpus()[0].model}, ${os.cpus().length} cores, ${( | ||
os.totalmem() / Math.pow(1024, 3) | ||
).toFixed(2)}Gb of RAM`, | ||
gitBranch: process.env.GIT_BRANCH ?? 'unknown', | ||
}; | ||
const influxDbClient = setupInfluxDbClient(); | ||
|
||
function setupInfluxDbClient(): InfluxDB | undefined { | ||
const { url, token } = INFLUXDB_CLIENT_OPTIONS; | ||
if (url === undefined || token === undefined) { | ||
return undefined; | ||
} | ||
return new InfluxDB({ url, token }); | ||
} | ||
|
||
export function writeResultToInfluxDb(result: BenchmarkResult): void { | ||
const { org, bucket } = INFLUXDB_CLIENT_OPTIONS; | ||
if (influxDbClient && org && bucket) { | ||
console.log('Writing result to InfluxDB.'); | ||
const influxDbWriteClient = influxDbClient.getWriteApi(org, bucket, 'ms'); | ||
try { | ||
const sampleName = result.label.split('-')[1].trim(); | ||
const { upperBound, lowerBound } = calculateBounds(result); | ||
const point = new Point(`${result.label} - ${result.size} samples`) | ||
.tag('benchmarkName', result.label.trim()) | ||
.tag('sampledTimes', result.size.toString()) | ||
.floatField('mean', result.mean) | ||
.floatField('variance', result.variance) | ||
.floatField(`${sampleName} - upperBound`, upperBound) | ||
.floatField(`${sampleName} - lowerBound`, lowerBound) | ||
.intField('size', result.size); | ||
for (const [key, value] of Object.entries(INFLUXDB_COMMON_POINT_TAGS)) { | ||
point.tag(key, value.trim()); | ||
} | ||
influxDbWriteClient.writePoint(point); | ||
} catch (e) { | ||
console.error('Error writing to InfluxDB: ', e); | ||
} finally { | ||
influxDbWriteClient.close(); | ||
} | ||
} else { | ||
console.info('Skipping writing to InfluxDB: client is not configured.'); | ||
} | ||
} | ||
|
||
export function readPreviousResultFromInfluxDb( | ||
result: BenchmarkResult | ||
): Promise<BenchmarkResult | undefined> { | ||
return new Promise((resolve) => { | ||
const { org, bucket } = INFLUXDB_CLIENT_OPTIONS; | ||
if (!influxDbClient || !org || !bucket) { | ||
resolve(undefined); | ||
return; | ||
} | ||
console.log('Querying InfluxDB for previous results.'); | ||
const influxDbPointTags = INFLUXDB_COMMON_POINT_TAGS; | ||
const influxDbQueryClient = influxDbClient.getQueryApi(org); | ||
const baseBranchForComparison = | ||
process.env.METRICS_BASE_BRANCH_FOR_COMPARISON ?? 'main'; | ||
const fluxQuery = ` | ||
from(bucket: "${bucket}") | ||
|> range(start: -90d) | ||
|> filter(fn: (r) => r.benchmarkName == "${result.label}") | ||
|> filter(fn: (r) => r.gitBranch == "${baseBranchForComparison}") | ||
|> filter(fn: (r) => r.sampledTimes == "${result.size}") | ||
|> filter(fn: (r) => r.sourceEnvironment == "${influxDbPointTags.sourceEnvironment}") | ||
|> filter(fn: (r) => r.operatingSystem == "${influxDbPointTags.operatingSystem}") | ||
|> filter(fn: (r) => r.hardware == "${influxDbPointTags.hardware}") | ||
|> toFloat() | ||
|> group() | ||
|> pivot( | ||
rowKey:["_measurement"], | ||
columnKey: ["_field"], | ||
valueColumn: "_value" | ||
) | ||
|> sort(desc: true) | ||
|> limit(n:1) | ||
`; | ||
try { | ||
let previousResult: BenchmarkResult | undefined = undefined; | ||
influxDbQueryClient.queryRows(fluxQuery, { | ||
next(row, tableMeta) { | ||
const tableObject = tableMeta.toObject(row); | ||
if ( | ||
!previousResult && | ||
tableObject._measurement && | ||
tableObject.mean && | ||
tableObject.variance && | ||
tableObject.size | ||
) { | ||
const measurement = tableObject._measurement; | ||
previousResult = { | ||
label: measurement | ||
.substring(0, measurement.lastIndexOf('-')) | ||
.trim(), | ||
mean: parseFloat(tableObject.mean), | ||
variance: parseFloat(tableObject.variance), | ||
size: parseInt(tableObject.size, 10), | ||
}; | ||
} | ||
}, | ||
error(e) { | ||
console.error('Error querying InfluxDB: ', e); | ||
resolve(undefined); | ||
}, | ||
complete() { | ||
resolve(previousResult); | ||
}, | ||
}); | ||
} catch (e) { | ||
console.error('Error querying InfluxDB: ', e); | ||
resolve(undefined); | ||
} | ||
}); | ||
} |
Oops, something went wrong.