@@ -20,6 +20,7 @@ use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider};
2020use sc_client_db:: DbHash ;
2121use sc_service:: Configuration ;
2222use sp_blockchain:: HeaderBackend ;
23+ use sp_core:: storage:: StorageKey ;
2324use sp_database:: { ColumnId , Database } ;
2425use sp_runtime:: traits:: { Block as BlockT , HashFor } ;
2526use sp_state_machine:: Storage ;
@@ -29,7 +30,8 @@ use clap::{Args, Parser};
2930use log:: info;
3031use rand:: prelude:: * ;
3132use serde:: Serialize ;
32- use std:: { fmt:: Debug , sync:: Arc } ;
33+ use sp_runtime:: generic:: BlockId ;
34+ use std:: { fmt:: Debug , path:: PathBuf , sync:: Arc } ;
3335
3436use super :: { record:: StatSelect , template:: TemplateData } ;
3537
@@ -58,8 +60,8 @@ pub struct StorageCmd {
5860pub struct StorageParams {
5961 /// Path to write the *weight* file to. Can be a file or directory.
6062 /// For substrate this should be `frame/support/src/weights`.
61- #[ clap( long, default_value = "." ) ]
62- pub weight_path : String ,
63+ #[ clap( long) ]
64+ pub weight_path : Option < PathBuf > ,
6365
6466 /// Select a specific metric to calculate the final weight output.
6567 #[ clap( long = "metric" , default_value = "average" ) ]
@@ -83,8 +85,19 @@ pub struct StorageParams {
8385 #[ clap( long) ]
8486 pub skip_write : bool ,
8587
88+ /// Specify the Handlebars template to use for outputting benchmark results.
89+ #[ clap( long) ]
90+ pub template_path : Option < PathBuf > ,
91+
92+ /// Path to write the raw 'read' results in JSON format to. Can be a file or directory.
93+ #[ clap( long) ]
94+ pub json_read_path : Option < PathBuf > ,
95+
96+ /// Path to write the raw 'write' results in JSON format to. Can be a file or directory.
97+ #[ clap( long) ]
98+ pub json_write_path : Option < PathBuf > ,
99+
86100 /// Rounds of warmups before measuring.
87- /// Only supported for `read` benchmarks.
88101 #[ clap( long, default_value = "1" ) ]
89102 pub warmups : u32 ,
90103
@@ -115,23 +128,32 @@ impl StorageCmd {
115128 {
116129 let mut template = TemplateData :: new ( & cfg, & self . params ) ;
117130
131+ let block_id = BlockId :: < Block > :: Number ( client. usage_info ( ) . chain . best_number ) ;
132+ template. set_block_number ( block_id. to_string ( ) ) ;
133+
118134 if !self . params . skip_read {
135+ self . bench_warmup ( & client) ?;
119136 let record = self . bench_read ( client. clone ( ) ) ?;
120- record. save_json ( & cfg, "read" ) ?;
137+ if let Some ( path) = & self . params . json_read_path {
138+ record. save_json ( & cfg, path, "read" ) ?;
139+ }
121140 let stats = record. calculate_stats ( ) ?;
122141 info ! ( "Time summary [ns]:\n {:?}\n Value size summary:\n {:?}" , stats. 0 , stats. 1 ) ;
123142 template. set_stats ( Some ( stats) , None ) ?;
124143 }
125144
126145 if !self . params . skip_write {
146+ self . bench_warmup ( & client) ?;
127147 let record = self . bench_write ( client, db, storage) ?;
128- record. save_json ( & cfg, "write" ) ?;
148+ if let Some ( path) = & self . params . json_write_path {
149+ record. save_json ( & cfg, path, "write" ) ?;
150+ }
129151 let stats = record. calculate_stats ( ) ?;
130152 info ! ( "Time summary [ns]:\n {:?}\n Value size summary:\n {:?}" , stats. 0 , stats. 1 ) ;
131153 template. set_stats ( None , Some ( stats) ) ?;
132154 }
133155
134- template. write ( & self . params . weight_path )
156+ template. write ( & self . params . weight_path , & self . params . template_path )
135157 }
136158
137159 /// Returns the specified state version.
@@ -149,6 +171,33 @@ impl StorageCmd {
149171 info ! ( "Using seed {}" , seed) ;
150172 StdRng :: seed_from_u64 ( seed)
151173 }
174+
175+ /// Run some rounds of the (read) benchmark as warmup.
176+ /// See `frame_benchmarking_cli::storage::read::bench_read` for detailed comments.
177+ fn bench_warmup < B , BA , C > ( & self , client : & Arc < C > ) -> Result < ( ) >
178+ where
179+ C : UsageProvider < B > + StorageProvider < B , BA > ,
180+ B : BlockT + Debug ,
181+ BA : ClientBackend < B > ,
182+ {
183+ let block = BlockId :: Number ( client. usage_info ( ) . chain . best_number ) ;
184+ let empty_prefix = StorageKey ( Vec :: new ( ) ) ;
185+ let mut keys = client. storage_keys ( & block, & empty_prefix) ?;
186+ let mut rng = Self :: setup_rng ( ) ;
187+ keys. shuffle ( & mut rng) ;
188+
189+ for i in 0 ..self . params . warmups {
190+ info ! ( "Warmup round {}/{}" , i + 1 , self . params. warmups) ;
191+ for key in keys. clone ( ) {
192+ let _ = client
193+ . storage ( & block, & key)
194+ . expect ( "Checked above to exist" )
195+ . ok_or ( "Value unexpectedly empty" ) ;
196+ }
197+ }
198+
199+ Ok ( ( ) )
200+ }
152201}
153202
154203// Boilerplate
0 commit comments