Skip to content

Commit 19c1fe3

Browse files
authored
CLI Options (#446)
* Added command line options for output, headers, and templates * Fixed options to conform to standard cli * Added weight-gen cli * fixed dependencies
1 parent f9248c7 commit 19c1fe3

File tree

5 files changed

+245
-108
lines changed

5 files changed

+245
-108
lines changed

bencher/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ version = "0.1.0"
77
authors = ["Laminar Developers <hello@laminar.one>"]
88
edition = "2018"
99

10+
[[bin]]
11+
path = "src/bin.rs"
12+
name = "codegen"
13+
1014
[dependencies]
1115
linregress = { version = "0.4.0", optional = true }
1216
handlebars = {version = "3.5.2", optional = true }
1317
serde = { features = ['derive'], optional = true, version = "1.0.119" }
18+
serde_json = "1.0"
1419
codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false }
1520
sp-core = { version = "3.0.0", default-features = false }
1621
sp-std = { version = "3.0.0", default-features = false }

bencher/src/handler.rs

Lines changed: 12 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,21 @@
11
use crate::BenchResult;
2+
use serde::{Serialize, Deserialize};
23
use codec::Decode;
34
use linregress::{FormulaRegressionBuilder, RegressionDataBuilder};
4-
use serde::Serialize;
5+
use std::io::Write;
56

6-
#[derive(Serialize, Default, Debug, Clone)]
7+
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
78
struct BenchData {
89
pub name: String,
910
pub base_weight: u64,
1011
pub base_reads: u32,
1112
pub base_writes: u32,
1213
}
1314

14-
#[derive(Serialize, Default, Debug, Clone)]
15-
struct TemplateData {
16-
pub header: String,
17-
pub benchmarks: Vec<BenchData>,
18-
}
19-
20-
// A Handlebars helper to add an underscore after every 3rd character,
21-
// i.e. a separator for large numbers.
22-
#[derive(Clone, Copy)]
23-
struct UnderscoreHelper;
24-
impl handlebars::HelperDef for UnderscoreHelper {
25-
fn call<'reg: 'rc, 'rc>(
26-
&self,
27-
h: &handlebars::Helper,
28-
_: &handlebars::Handlebars,
29-
_: &handlebars::Context,
30-
_rc: &mut handlebars::RenderContext,
31-
out: &mut dyn handlebars::Output,
32-
) -> handlebars::HelperResult {
33-
use handlebars::JsonRender;
34-
let param = h.param(0).unwrap();
35-
let underscore_param = underscore(param.value().render());
36-
out.write(&underscore_param)?;
37-
Ok(())
38-
}
39-
}
40-
41-
// Add an underscore after every 3rd character, i.e. a separator for large
42-
// numbers.
43-
fn underscore<Number>(i: Number) -> String
44-
where
45-
Number: std::string::ToString,
46-
{
47-
let mut s = String::new();
48-
let i_str = i.to_string();
49-
let a = i_str.chars().rev().enumerate();
50-
for (idx, val) in a {
51-
if idx != 0 && idx % 3 == 0 {
52-
s.insert(0, '_');
53-
}
54-
s.insert(0, val);
55-
}
56-
s
57-
}
58-
59-
// A helper to join a string of vectors.
60-
#[derive(Clone, Copy)]
61-
struct JoinHelper;
62-
impl handlebars::HelperDef for JoinHelper {
63-
fn call<'reg: 'rc, 'rc>(
64-
&self,
65-
h: &handlebars::Helper,
66-
_: &handlebars::Handlebars,
67-
_: &handlebars::Context,
68-
_rc: &mut handlebars::RenderContext,
69-
out: &mut dyn handlebars::Output,
70-
) -> handlebars::HelperResult {
71-
use handlebars::JsonRender;
72-
let param = h.param(0).unwrap();
73-
let value = param.value();
74-
let joined = if value.is_array() {
75-
value
76-
.as_array()
77-
.unwrap()
78-
.iter()
79-
.map(|v| v.render())
80-
.collect::<Vec<String>>()
81-
.join(" ")
82-
} else {
83-
value.render()
84-
};
85-
out.write(&joined)?;
86-
Ok(())
87-
}
88-
}
89-
90-
fn write(benchmarks: Vec<BenchData>) {
91-
// New Handlebars instance with helpers.
92-
let mut handlebars = handlebars::Handlebars::new();
93-
handlebars.register_helper("underscore", Box::new(UnderscoreHelper));
94-
handlebars.register_helper("join", Box::new(JoinHelper));
95-
// Don't HTML escape any characters.
96-
handlebars.register_escape_fn(|s| -> String { s.to_string() });
97-
98-
let hbs_data = TemplateData {
99-
header: "".to_string(), // TODO: header from provided file path
100-
benchmarks,
101-
};
102-
103-
const TEMPLATE: &str = include_str!("./template.hbs");
104-
// TODO: add option to provide custom template
105-
106-
// TODO: add option to change output file path
107-
let mut output_path = ::std::env::current_dir().unwrap();
108-
output_path.push("src/module_weights.rs");
109-
110-
let mut output_file = ::std::fs::File::create(output_path).unwrap();
111-
112-
handlebars
113-
.render_template_to_write(&TEMPLATE, &hbs_data, &mut output_file)
114-
.unwrap();
115-
}
116-
11715
/// Handle bench results
11816
pub fn handle(output: Vec<u8>) {
11917
let results = <Vec<BenchResult> as Decode>::decode(&mut &output[..]).unwrap();
120-
let data = results
18+
let data: Vec<BenchData> = results
12119
.into_iter()
12220
.map(|result| {
12321
let name = String::from_utf8_lossy(&result.method).to_string();
@@ -145,6 +43,12 @@ pub fn handle(output: Vec<u8>) {
14543
})
14644
.collect();
14745

148-
// TODO: check if should write weights file
149-
write(data);
46+
if let Ok(json) = serde_json::to_string(&data) {
47+
let stdout = ::std::io::stdout();
48+
let mut handle = stdout.lock();
49+
50+
handle.write_all(&json.as_bytes()).unwrap();
51+
} else {
52+
eprintln!("Could not write benchdata to JSON");
53+
}
15054
}

weight-gen/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "weight-gen"
3+
description = "CLI for generating weight from bencher output"
4+
license = "Apache-2.0"
5+
version = "0.1.0"
6+
authors = ["Laminar Developers <hello@laminar.one>"]
7+
edition = "2018"
8+
9+
[dependencies]
10+
serde = { features = ['derive'], optional = true, version = "1.0.119" }
11+
serde_json = "1.0"
12+
clap = "3.0.0-beta.2"
13+
handlebars = {version = "3.5.2", optional = true }
14+
15+
[features]
16+
default = ["std"]
17+
std = [
18+
"handlebars",
19+
"serde/std",
20+
]

weight-gen/src/main.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
use serde::{Serialize, Deserialize};
2+
use clap::{AppSettings, Clap};
3+
use std::io::Read;
4+
5+
#[derive(Clap)]
6+
#[clap(version = "01.0", author = "Laminar Developers <hello@laminar.one>")]
7+
#[clap(setting = AppSettings::ColoredHelp)]
8+
struct Opts {
9+
input: Option<String>,
10+
#[clap(short, long)]
11+
template: Option<String>,
12+
#[clap(short, long)]
13+
header: Option<String>,
14+
#[clap(short, long)]
15+
out: Option<String>,
16+
}
17+
18+
#[cfg(feature = "std")]
19+
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
20+
pub struct BenchData {
21+
pub name: String,
22+
pub base_weight: u64,
23+
pub base_reads: u32,
24+
pub base_writes: u32,
25+
}
26+
27+
#[derive(Serialize, Default, Debug, Clone)]
28+
struct TemplateData {
29+
pub header: String,
30+
pub benchmarks: Vec<BenchData>,
31+
}
32+
33+
// A Handlebars helper to add an underscore after every 3rd character,
34+
// i.e. a separator for large numbers.
35+
#[derive(Clone, Copy)]
36+
struct UnderscoreHelper;
37+
impl handlebars::HelperDef for UnderscoreHelper {
38+
fn call<'reg: 'rc, 'rc>(
39+
&self,
40+
h: &handlebars::Helper,
41+
_: &handlebars::Handlebars,
42+
_: &handlebars::Context,
43+
_rc: &mut handlebars::RenderContext,
44+
out: &mut dyn handlebars::Output,
45+
) -> handlebars::HelperResult {
46+
use handlebars::JsonRender;
47+
let param = h.param(0).unwrap();
48+
let underscore_param = underscore(param.value().render());
49+
out.write(&underscore_param)?;
50+
Ok(())
51+
}
52+
}
53+
54+
// Add an underscore after every 3rd character, i.e. a separator for large
55+
// numbers.
56+
fn underscore<Number>(i: Number) -> String
57+
where
58+
Number: std::string::ToString,
59+
{
60+
let mut s = String::new();
61+
let i_str = i.to_string();
62+
let a = i_str.chars().rev().enumerate();
63+
for (idx, val) in a {
64+
if idx != 0 && idx % 3 == 0 {
65+
s.insert(0, '_');
66+
}
67+
s.insert(0, val);
68+
}
69+
s
70+
}
71+
72+
// A helper to join a string of vectors.
73+
#[derive(Clone, Copy)]
74+
struct JoinHelper;
75+
impl handlebars::HelperDef for JoinHelper {
76+
fn call<'reg: 'rc, 'rc>(
77+
&self,
78+
h: &handlebars::Helper,
79+
_: &handlebars::Handlebars,
80+
_: &handlebars::Context,
81+
_rc: &mut handlebars::RenderContext,
82+
out: &mut dyn handlebars::Output,
83+
) -> handlebars::HelperResult {
84+
use handlebars::JsonRender;
85+
let param = h.param(0).unwrap();
86+
let value = param.value();
87+
let joined = if value.is_array() {
88+
value
89+
.as_array()
90+
.unwrap()
91+
.iter()
92+
.map(|v| v.render())
93+
.collect::<Vec<String>>()
94+
.join(" ")
95+
} else {
96+
value.render()
97+
};
98+
out.write(&joined)?;
99+
Ok(())
100+
}
101+
}
102+
103+
fn parse_stdio() -> Option<Vec<BenchData>> {
104+
let mut buffer = String::new();
105+
let stdin = std::io::stdin();
106+
let mut handle = stdin.lock();
107+
108+
handle.read_to_string(&mut buffer).unwrap();
109+
110+
let lines: Vec<&str> = buffer.split("\n").collect();
111+
for line in lines {
112+
let json = serde_json::from_str(line);
113+
114+
if let Ok(data) = json {
115+
return Some(data);
116+
}
117+
}
118+
119+
None
120+
}
121+
122+
fn main() {
123+
let opts: Opts = Opts::parse();
124+
125+
let benchmarks: Vec<BenchData> = {
126+
if let Some(data) = opts.input {
127+
serde_json::from_str(&data).expect("Could not parse JSON data")
128+
} else {
129+
parse_stdio().expect("Could not parse JSON data")
130+
}
131+
};
132+
133+
let mut handlebars = handlebars::Handlebars::new();
134+
handlebars.register_helper("underscore", Box::new(UnderscoreHelper));
135+
handlebars.register_helper("join", Box::new(JoinHelper));
136+
// Don't HTML escape any characters.
137+
handlebars.register_escape_fn(|s| -> String { s.to_string() });
138+
139+
// Use empty header if a header path is not given.
140+
let header = {
141+
if let Some(path) = opts.header {
142+
let header_string = ::std::fs::read_to_string(&path)
143+
.expect(&format!("Header file not found at {}", &path));
144+
145+
header_string
146+
} else {
147+
String::from("")
148+
}
149+
};
150+
151+
let hbs_data = TemplateData {
152+
header,
153+
benchmarks,
154+
};
155+
156+
const DEFAULT_TEMPLATE: &str = include_str!("./template.hbs");
157+
158+
// Use default template if template path is not given.
159+
let template = {
160+
if let Some(path) = opts.template {
161+
let template_string = ::std::fs::read_to_string(&path)
162+
.expect(&format!("Template file not found at {}", &path));
163+
164+
template_string
165+
} else {
166+
String::from(DEFAULT_TEMPLATE)
167+
}
168+
};
169+
170+
// Write benchmark to file or print to terminal if output path is not given.
171+
if let Some(path) = opts.out {
172+
let mut output_file = ::std::fs::File::create(&path)
173+
.expect(&format!("Could not create output file at {}", &path));
174+
175+
handlebars
176+
.render_template_to_write(&template, &hbs_data, &mut output_file)
177+
.unwrap();
178+
} else {
179+
let template_string = handlebars
180+
.render_template(&template, &hbs_data)
181+
.unwrap();
182+
183+
println!("{}", template_string);
184+
}
185+
}

weight-gen/src/template.hbs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{{header}}
2+
3+
#![allow(unused_parens)]
4+
#![allow(unused_imports)]
5+
#![allow(dead_code)]
6+
7+
use frame_support::{traits::Get, weights::Weight};
8+
use sp_std::marker::PhantomData;
9+
10+
pub struct ModuleWeights<T>(PhantomData<T>);
11+
impl<T: frame_system::Config> ModuleWeights<T> {
12+
{{~#each benchmarks as |benchmark|}}
13+
pub fn {{benchmark.name~}} () -> Weight {
14+
({{underscore benchmark.base_weight}} as Weight)
15+
{{~#if (ne benchmark.base_reads "0")}}
16+
.saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight))
17+
{{~/if}}
18+
{{~#if (ne benchmark.base_writes "0")}}
19+
.saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight))
20+
{{~/if}}
21+
}
22+
{{~/each}}
23+
}

0 commit comments

Comments
 (0)