rust

Rustの自作ライブラリのチューニング(をしている)

テーブルを綺麗に表示するだけの自作ライブラリ「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

現在もチューニングを続けているのであった…