Skip to content

archive perf test #17522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: compatible
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
833886c
add archive node tests to suite
dkijania Mar 13, 2025
bc113a8
eport performance result file
dkijania Jul 11, 2025
1b440fc
enahnce benchmark app with new performance test
dkijania Jul 11, 2025
47592bd
add CI part to execute test and upload data
dkijania Jul 11, 2025
04d15eb
expand dirtyWhen filter
dkijania Jul 11, 2025
9eab44e
fixed duplicated debian components
dkijania Jul 15, 2025
a86f27e
added changelog
dkijania Jul 15, 2025
4394144
fix caching part
dkijania Jul 16, 2025
b500f87
fix local path to archive.perf test
dkijania Jul 16, 2025
b6a4ae2
remove extra args
dkijania Jul 16, 2025
1284a92
set input file in extra args
dkijania Jul 16, 2025
a782f68
dhall lints
dkijania Jul 17, 2025
b5305a4
fix benchmark name
dkijania Jul 17, 2025
a108fd0
use structuted log insted of crude parsing
dkijania Jul 18, 2025
d5bd110
use structured log instead of crude regex
dkijania Jul 21, 2025
d33d879
migrate to scopes
dkijania Jul 21, 2025
362e449
fmt
dkijania Jul 21, 2025
25333da
Revert "fmt"
dkijania Jul 22, 2025
96e4ebb
add docs and use Yojson.Safe.Util.to_float
dkijania Jul 22, 2025
6ff5ee4
remove extra args from arguments
dkijania Jul 22, 2025
0e0bd6c
remove trailing and leading quotas
dkijania Jul 22, 2025
94ed96d
extending no of tries when syncing with daemon
dkijania Jul 24, 2025
74808f0
changing approach in logging perf metrics. Introduced new function fo…
dkijania Jul 24, 2025
a5ce4e2
revert incease number of retries
dkijania Jul 25, 2025
1f91d12
optimize avg calculation
dkijania Jul 25, 2025
bff267c
propagate logger instead of creating it each time
dkijania Jul 25, 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
5 changes: 5 additions & 0 deletions buildkite/scripts/bench/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ MAINLINE_BRANCHES="-m develop -m compatible -m master -m dkijania/bench_for_ledg
while [[ "$#" -gt 0 ]]; do case $1 in
heap-usage) BENCHMARK="heap-usage"; ;;
mina-base) BENCHMARK="mina-base"; ;;
archive)
BENCHMARK="archive";
EXTRA_ARGS="--no-run ${EXTRA_ARGS}"

;;
ledger-export)
BENCHMARK="ledger-export"
EXTRA_ARGS="--genesis-ledger-path ./genesis_ledgers/devnet.json"
Expand Down
2 changes: 1 addition & 1 deletion buildkite/src/Command/ArchiveNodeTest.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ in { step =
, buildFlags = BuildFlags.Type.Instrumented
}
)
"./scripts/tests/archive-node-test.sh && buildkite/scripts/upload-partial-coverage-data.sh ${key}"
"./scripts/tests/archive-node-test.sh && buildkite/scripts/upload-partial-coverage-data.sh ${key} && ls -al && ./buildkite/scripts/cache/manager.sh write archive.perf archive-node-test"
]
, label = "Archive: Node Test"
, key = key
Expand Down
43 changes: 43 additions & 0 deletions buildkite/src/Command/Bench/Archive.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
let BenchBase = ../../Command/Bench/Base.dhall

let SelectFiles = ../../Lib/SelectFiles.dhall

let Pipeline = ../../Pipeline/Dsl.dhall

let PipelineScope = ../../Pipeline/Scope.dhall

let Cmd = ../../Lib/Cmds.dhall

let makeArchiveBench =
\(name : Text)
-> \(scope : List PipelineScope.Type)
-> Pipeline.build
( BenchBase.pipeline
BenchBase.Spec::{
, additionalDirtyWhen =
[ SelectFiles.strictlyStart
(SelectFiles.contains "src/test/archive")
, SelectFiles.exactly
"buildkite/src/Jobs/Bench/ArchiveStable"
"dhall"
, SelectFiles.exactly
"buildkite/src/Jobs/Bench/ArchiveUnstable"
"dhall"
]
, path = "Bench"
, name = name
, label = "Archive"
, key = "archive-perf"
, bench = "archive"
, dependsOn =
[ { name = "ArchiveNodeTest", key = "archive-node-test" } ]
, preCommands =
[ Cmd.run
"./buildkite/scripts/cache/manager.sh read archive-node-test/archive.perf ."
]
, scope = scope
, extraArgs = "--input-file archive.perf"
}
)

in { makeArchiveBench = makeArchiveBench }
8 changes: 5 additions & 3 deletions buildkite/src/Command/Bench/Base.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ let Spec =
, yellowThreshold : Double
, redThreshold : Double
, preCommands : List Cmd.Type
, extraArgs : Text
, scope : List PipelineScope.Type
}
, default =
Expand All @@ -55,6 +56,7 @@ let Spec =
, yellowThreshold = 0.1
, redThreshold = 0.2
, preCommands = [] : List Cmd.Type
, extraArgs = ""
}
}

Expand All @@ -70,9 +72,9 @@ let command
# [ "BRANCH=\\\${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-BUILDKITE_BRANCH}"
]
)
"./buildkite/scripts/bench/run.sh ${spec.bench} --red-threshold ${Double/show
spec.redThreshold} --yellow-threshold ${Double/show
spec.yellowThreshold}"
"EXTRA_ARGS=\"${spec.extraArgs}\" ./buildkite/scripts/bench/run.sh ${spec.bench} --red-threshold ${Double/show
spec.redThreshold} --yellow-threshold ${Double/show
spec.yellowThreshold}"
, label = "Perf: ${spec.label}"
, key = spec.key
, target = spec.size
Expand Down
7 changes: 7 additions & 0 deletions buildkite/src/Jobs/Bench/ArchiveStable.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let ArchiveBench = ../../Command/Bench/Archive.dhall

let PipelineScope = ../../Pipeline/Scope.dhall

in ArchiveBench.makeArchiveBench
"ArchiveStable"
PipelineScope.AllButPullRequest
7 changes: 7 additions & 0 deletions buildkite/src/Jobs/Bench/ArchiveUnstable.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let ArchiveBench = ../../Command/Bench/Archive.dhall

let PipelineScope = ../../Pipeline/Scope.dhall

in ArchiveBench.makeArchiveBench
"ArchiveUnstable"
PipelineScope.PullRequestOnly
4 changes: 2 additions & 2 deletions buildkite/src/Jobs/Test/ArchiveNodeTest.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ let Artifacts = ../../Constants/Artifacts.dhall

let Dockers = ../../Constants/DockerVersions.dhall

let buildFlags = ../../Constants/BuildFlags.dhall
let BuildFlags = ../../Constants/BuildFlags.dhall

let dependsOn =
Dockers.dependsOn
Dockers.DepsSpec::{
, buildFlags = BuildFlags.Type.Instrumented
, artifact = Artifacts.Type.FunctionalTestSuite
, buildFlags = buildFlags.Type.Instrumented
}

in Pipeline.build
Expand Down
1 change: 1 addition & 0 deletions changes/17522.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Enhanced precomputed_blocks test with performance metrics gathering. Added CI job which also upload it to influx db and once we fill out 10 historical values every measurement will be checked for regression.
18 changes: 13 additions & 5 deletions scripts/benchmarks/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
upload_bench.add_argument("--benchmark", type=BenchmarkType, help="benchmark to upload")

test_bench = subparsers.add_parser('test', help="Performs entire cycle of operations from run till upload")
test_bench.add_argument("--no-run", help="skip running benchmark", action='store_true')
test_bench.add_argument("--benchmark", type=BenchmarkType, help="benchmark to test")
test_bench.add_argument("--tmpfile", help="temporary location of result file", default="/tmp/bench.tmp")
test_bench.add_argument("--input-file", help="input file with raw benchmark", default="input.json")
Expand Down Expand Up @@ -89,6 +90,8 @@ def select_benchmark(kind):
return MinaBaseBenchmark()
elif kind == BenchmarkType.zkapp:
return ZkappLimitsBenchmark()
elif kind == BenchmarkType.archive:
return ArchiveBenchmark()
elif kind == BenchmarkType.heap_usage:
return HeapUsageBenchmark()
elif kind == BenchmarkType.snark:
Expand Down Expand Up @@ -136,11 +139,16 @@ def select_benchmark(kind):
bench.upload(args.infile)

if args.cmd == "test":
output = bench.run(path=args.path)
if args.no_run:
print("Skipping running benchmark")
output = Path(args.input_file).read_text()
else:
output = bench.run(path=args.path)

files = bench.parse(output,
args.tmpfile,
influxdb=True,
branch=args.branch)
args.tmpfile,
influxdb=True,
branch=args.branch)

[
bench.compare(file, args.yellow_threshold, args.red_threshold)
Expand All @@ -151,4 +159,4 @@ def select_benchmark(kind):

if args.branch in mainline_branches:
for file in files:
bench.upload(file)
bench.upload(file)
67 changes: 67 additions & 0 deletions scripts/benchmarks/lib/bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ class BenchmarkType(Enum):
zkapp = 'zkapp'
ledger_export = 'ledger-export'
ledger_apply = 'ledger-apply'
archive = 'archive'

def __str__(self):
return self.value
Expand Down Expand Up @@ -444,6 +445,72 @@ def parse(self, content, output_filename, influxdb, branch):

return [output_filename]

class ArchiveBenchmark(Benchmark):
"""
Concrete implementation of Benchmark for archive benchmark.
It requires input json file with benchmark data in format
{
"final_time":"0.4000" # In ms
, "preparation_steps_mean": "0.432"
}
"""

name = MeasurementColumn("Name", 0)
time = FieldColumn("time", 1, "ms")
category = TagColumn("category", 2)
branch = TagColumn("gitbranch", 3)

def __init__(self):
Benchmark.__init__(self, BenchmarkType.archive)

def run(self, path=None):
pass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realize it's very confusing that run is empty here. I'll take a closer look after I come back

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. this script is badly designed and initially was meant to support only few benchmarks with the same flow. In this case we ran already benchmark by running archive node test and this job is only to parse results and sent. However, the design of benchmarks app require every benchmark to be executed by benchmark app. here is more detailed explanation:

https://o1-labs.slack.com/archives/C07EYM9GR1U/p1742910001734869?thread_ts=1742907476.503919&cid=C07EYM9GR1U

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, please document the info in this method, then :)


def fields(self):
return [
self.time
]

def name_header(self):
return self.name

def branch_header(self):
return self.branch

def default_path(self):
return ""

def headers(self):
return [
ArchiveBenchmark.name, ArchiveBenchmark.time,
ArchiveBenchmark.category, ArchiveBenchmark.branch
]

# format of input file:
# [{"operation":"Zkapp_account_update.add","avg_time_ms":4.994700819672131}
# ,{"operation":"Zkapp_account_update_body.add","avg_time_ms":3.1188038147138974}
# , ...
# ]
def parse(self, content, output_filename, influxdb, branch):

operation = "operation"
avg_time_ms = "avg_time_ms"

data = json.loads(content)

with open(output_filename, 'w') as csvfile:
if influxdb:
csvfile.write(
self.headers_to_influx(self.headers()) + "\n")
for item in data:
operation_name = item[operation]
avg_time = item[avg_time_ms]
csvwriter = csv.writer(csvfile)
csvwriter.writerow((operation_name, avg_time, "archive", branch))

return [output_filename]


class ZkappLimitsBenchmark(Benchmark):
"""
ZkappLimit benchmark has it's own output which we need to handle separately. It is similar to:
Expand Down
25 changes: 9 additions & 16 deletions src/app/archive/lib/diff.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,10 @@ module Builder = struct
Some (index, account) )
in
let accounts_accessed_time = Time.now () in
[%log debug]
"Archive data generation for $state_hash: accounts-accessed took $time ms"
~metadata:
[ ("state_hash", Mina_base.State_hash.to_yojson state_hash)
; ( "time"
, `Float (Time.Span.to_ms (Time.diff accounts_accessed_time start)) )
] ;
Metrics.report_time ~logger ~label:"accounts-accessed"
~extra_metadata:
[ ("state_hash", Mina_base.State_hash.to_yojson state_hash) ]
(Time.diff accounts_accessed_time start) ;
let accounts_created =
let account_creation_fee =
precomputed_values.constraint_constants.account_creation_fee
Expand All @@ -125,15 +122,11 @@ module Builder = struct
(token_id, owner) )
in
let account_created_time = Time.now () in
[%log debug]
"Archive data generation for $state_hash: accounts-created took $time ms"
~metadata:
[ ("state_hash", Mina_base.State_hash.to_yojson state_hash)
; ( "time"
, `Float
(Time.Span.to_ms
(Time.diff account_created_time accounts_accessed_time) ) )
] ;
Metrics.report_time ~logger ~label:"accounts-created"
~extra_metadata:
[ ("state_hash", Mina_base.State_hash.to_yojson state_hash) ]
(Time.diff account_created_time accounts_accessed_time) ;

Transition_frontier.Breadcrumb_added
{ block =
With_hash.map ~f:Mina_block.read_all_proofs_from_disk block_with_hash
Expand Down
49 changes: 35 additions & 14 deletions src/app/archive/lib/metrics.ml
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
open Core_kernel
open Async

let time ~label f =
(** [report_time ~label ?extra_metadata elapsed] logs a performance metric with the given [label] and [elapsed] time.
- [label]: A string describing the metric being reported.
- [extra_metadata]: An optional list of additional metadata key-value pairs to include in the log (default: []).
- [elapsed]: The time span to report, as a [Time.Span.t].
The log entry will include the label, the elapsed time (in human-readable format and milliseconds), and any extra metadata provided.
*)
let report_time ~logger ~label ?(extra_metadata = []) elapsed =
[%log info] "%s took %s" label
(Time.Span.to_string_hum elapsed)
~metadata:
( [ ("is_perf_metric", `Bool true)
; ("label", `String label)
; ("elapsed", `Float (Time.Span.to_ms elapsed))
]
@ extra_metadata )

(** [time ~label f] measures the execution time of the monadic function [f], reports the elapsed time with the given [label], and returns the result of [f].
@param label A string label used to identify the timing report.
@param f A function of type unit -> 'a Deferred.t whose execution time will be measured.
@return The result of [f ()], after reporting the elapsed time.
*)
let time ~label ~logger f =
let start = Time.now () in
let%map x = f () in
let stop = Time.now () in
[%log' info (Logger.create ())]
"%s took %s" label
(Time.Span.to_string_hum (Time.diff stop start)) ;
let elapsed = Time.diff stop start in
report_time ~logger ~label elapsed ;
x

let default_missing_blocks_width = 2000
Expand All @@ -17,8 +38,8 @@ module Max_block_height = struct
Caqti_request.find Caqti_type.unit Caqti_type.int
"SELECT GREATEST(0, MAX(height)) FROM blocks"

let update (module Conn : Caqti_async.CONNECTION) metric_server =
time ~label:"max_block_height" (fun () ->
let update ~logger (module Conn : Caqti_async.CONNECTION) metric_server =
time ~label:"max_block_height" ~logger (fun () ->
let open Deferred.Result.Let_syntax in
let%map max_height = Conn.find query () in
Mina_metrics.(
Expand All @@ -40,10 +61,10 @@ module Missing_blocks = struct
|sql}
missing_blocks_width )

let update ~missing_blocks_width (module Conn : Caqti_async.CONNECTION)
metric_server =
let update ~logger ~missing_blocks_width
(module Conn : Caqti_async.CONNECTION) metric_server =
let open Deferred.Result.Let_syntax in
time ~label:"missing_blocks" (fun () ->
time ~label:"missing_blocks" ~logger (fun () ->
let%map missing_blocks = Conn.find (query missing_blocks_width) () in
Mina_metrics.(
Gauge.set
Expand All @@ -61,9 +82,9 @@ module Unparented_blocks = struct
WHERE parent_id IS NULL
|sql}

let update (module Conn : Caqti_async.CONNECTION) metric_server =
let update ~logger (module Conn : Caqti_async.CONNECTION) metric_server =
let open Deferred.Result.Let_syntax in
time ~label:"unparented_blocks" (fun () ->
time ~label:"unparented_blocks" ~logger (fun () ->
let%map unparented_block_count = Conn.find query () in
Mina_metrics.(
Gauge.set
Expand Down Expand Up @@ -93,7 +114,7 @@ let update ~logger ~missing_blocks_width pool metric_server =
Deferred.all_unit
(List.map
~f:(log_error ~logger pool metric_server)
[ Max_block_height.update
; Unparented_blocks.update
; Missing_blocks.update ~missing_blocks_width
[ Max_block_height.update ~logger
; Unparented_blocks.update ~logger
; Missing_blocks.update ~logger ~missing_blocks_width
] )
Loading