Rust umożliwia parametryzacje optymalizacji Release poprzez odpowiednie wpisy w Cargo.toml oraz config.toml
Takimi wpisami są w Cargo.toml np:
[profile.release] opt-level = 3 debug = false lto = "fat" panic = "abort"
gdzie:
opt-level
– ozacza poziom optymalizacji LLVM, odpowiednik-Ox
debug
– oznacza czy mają być metadane debug czy nie, nie wpływa na wydajność ale na rozmiarlto
– sposób linkowania bibloteki,fat
daje nam większe możliwości optymalizacji naszego kodu i inlinowaniapanic
– w przypadku wersjiabort
oznacza, że program nie używa cacha do obsługi błędów, więc działa jaknoexcept
w C++ przez co działa szybciej
W pliku $PROJECT_HOME/.cargo/config.toml
Można dodać taki wpis:
[target.x86_64-unknown-linux-gnu] linker = "clang" rustflags = "--emit=llvm-ir"
gdzie flaga --emit
kompiluje nam do LLVM instruction
przez co kompilator LLVM
może lepiej zoptymalizować nasz kod
Mamy jeszcze do dyspozycji optymalizacje kodu poprzez profilowanie, coś jak JIT
w JVM
A więc co musimy zrobić, żeby uruchomić aplikację w najbardziej wydajnej wersji?
Na początek instalujemy LLVM
w wersji 11+, opis dla Debian/Ubuntu: https://apt.llvm.org/
Następnie w pliku: $PROJECT_HOME/.cargo/config.toml
modyfikujemy wpis na:
rustflags = "--emit=llvm-ir -Cprofile-generate=/tmp/profdata"
Następnie kompilujemy w wersji release i przechodzimy wielokrotnie ścieżki programu, operacje które są głównie wykonywane podczas działania programu. Jak już skończymy, możemy zakończyć program i wykonać:
llvm-profdata merge -output=/tmp/profdata/rustc-llvm.profdata /tmp/profdata/*.profraw
Czyli połączyć nasze pliki profilu w jeden duży plik profilowy z działania aplikacji
Ostatnim krokiem jest zmiana w pliku: $PROJECT_HOME/.cargo/config.toml
rustflags = "--emit=llvm-ir -Cprofile-use=/tmp/profdata/rustc-llvm.profdata"
oraz kompiacja. Czyli LLVM optymalizuje nam kod pod operacje które wcześniej wykonaliśmy, aplikacja działa szybciej 🙂
Niestety przy każdej zmianie trzeb te operacje powtarzać jeśli chcemy mieć najwydajniejszą wersje naszej aplikacji
Test mojej wersji vertx:
vertx-rust (this link opens in a new window) by kathog (this link opens in a new window)
Simple Rust version of vertx tcp eventbus, tcp server using zookeeper cluster manager
Bez optymalizacji:
[nerull@anvil vertx-rust]$ wrk -d 10s -t 5 -c 500 http://127.0.0.1:9091/ Running 10s test @ http://127.0.0.1:9091/ 5 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.23ms 1.30ms 38.75ms 74.01% Req/Sec 44.90k 2.71k 56.82k 74.20% 2236733 requests in 10.07s, 258.11MB read Requests/sec: 222083.80 Transfer/sec: 25.63MB [nerull@anvil vertx-rust]$
A teraz efekt po optymalizacji:
[nerull@anvil vertx-rust]$ wrk -d 10s -t 5 -c 500 http://127.0.0.1:9091/ Running 10s test @ http://127.0.0.1:9091/ 5 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.00ms 1.28ms 24.46ms 78.23% Req/Sec 49.76k 4.99k 86.04k 77.20% 2479491 requests in 10.04s, 286.12MB read Requests/sec: 246883.21 Transfer/sec: 28.49MB [nerull@anvil vertx-rust]$
Jak widać wzrost jest na poziomie ~11%