テーブルを綺麗に表示するだけの自作ライブラリ「pretable」で、
出力する部分が遅かったのでパフォーマンスチューニングを行っていまうす。
そこでやった点をまとめています。
(こうするべきっていうのがあったら教えてほしいです)
(ドキュメントもそのうち書きます)
上から順に行っている為、時間はどんどん早くなっています。
計測のやり方は10万行分のデータをStringとして出力する関数だけの時間を計測しています。
(--release
は使っていないです)
table.output();
文字列結合よりformat!のほうが早い
変更前: 1.9s
変更後: 1.6s
Self::repeat(" ", start) + v + &Self::repeat(" ", end)
format!("{}{}{}", Self::repeat(" ", start), v, Self::repeat(" ", end))
文字列結合よりformat!のほうが早い2
これは考えなくてもわかる気がした。(Javaとかでそうだから)
変更前: 1.6s
変更後: 1.3s
for _ in 0..count {
v += s;
}
for _ in 0..count {
v = format!("{}{}", v, s);
}
Vecの初期化
数が多いと影響してきそう
変更前: 1.36s
変更後: 1.35s
Vec::new()
Vec::with_capacity(n)
単純な文字列作成
もっといいやり方があるかもしれない
変更前: 1.35s
変更後: 1.14s
fn repeat(s: &str, count: usize) -> String {
let mut v = String::new();
for _ in 0..count {
v = format!("{}{}", v, s);
}
v
}
fn repeat(s: &str, count: usize) -> String {
let b = s.as_bytes()[0];
String::from_utf8(vec![b; count]).unwrap()
}
上記の関数の引数をstrからu8に変更
変更前: 1.14s
変更後: 1.13s
fn repeat(s: u8, count: usize) -> String {
String::from_utf8(vec![s; count]).unwrap()
}
Vecの初期化(別の箇所)
10万回呼ばれる箇所
変更前: 1.13s
変更後: 1.11s
Vecのiter()のunwrap()を使わないようにする
絶対入るってわかっている箇所ならインデックス使ったほうがはやい
変更前: 1.11s
変更後: 1.09s
let mut l = value_len_vec.iter();
*l.next().unwrap();
let mut n = 0;
let mut inc = || {
n += 1;
n - 1
};
value_len_vec[inc()];
Vecのjoinをconcatに
join早くしたいと思って調べたら存在した
変更前: 1.09s
変更後: 1.08s
result.join("")
result.concat()
String::from_utf8をString::from_utf8_uncheckedに
unwrap()は遅いと思って調べたら存在した
変更前: 1.08s
変更後: 1.06s
String::from_utf8(vec![s; count]).unwrap()
unsafe {
String::from_utf8_unchecked(vec![s; count])
}
Stringの生成を抑える
outputの高速化 by vain0x · Pull Request #2 · ryota-sakamoto/pretable
vain0xさん
すごいなるほどなあと思った。
変更前: 1.06s
変更後: 0.68s