AtCoderのマラソンコンテストに際して、Rustコードのプロファイルを cargo-profiler を使用して取ろうとしたのですが、
NOTE: This subcommand can only be used on Linux machines.
とある通りLinuxにしか対応していなかったので、Docker経由で使用しました。
その手順を書きます。
手順
Dockerイメージのビルド
$ docker build -t cargo-profiler .
コマンドを、下記の Dockerfile を設置したディレクトリで実行する。
# cf. https://github.com/rust-lang/docker-rust/blob/a035f6fa1f14754bab8f34376c386fafc831b652/1.49.0/buster/Dockerfile
FROM buildpack-deps:buster
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH \
RUST_VERSION=1.49.0
RUN set -eux; \
dpkgArch="$(dpkg --print-architecture)"; \
case "${dpkgArch##*-}" in \
amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='ed7773edaf1d289656bdec2aacad12413b38ad0193fff54b2231f5140a4b07c5' ;; \
armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='7a7b9d246ad63358705d8d4a7d5c2ef1adfec24525d1d5c44a7739e1b867e84d' ;; \
arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='f80a0a792b3ab905ab4919474daf4d3f60e574fc6987e69bfba2fd877241a8de' ;; \
i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='4473c18286aa1831683a772706d9a5c98b87a61cc014d38063e00a63a480afef' ;; \
*) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
esac; \
url="https://static.rust-lang.org/rustup/archive/1.23.1/${rustArch}/rustup-init"; \
wget "$url"; \
echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
chmod +x rustup-init; \
./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \
rm rustup-init; \
chmod -R a+w $RUSTUP_HOME; \
rustup --version; \
cargo --version; \
rustc --version;
RUN apt-get update \
&& apt-get install -y valgrind
RUN cargo install cargo-profiler \
&& chmod -R a+w $CARGO_HOME
(このファイルは、https://github.com/rust-lang/docker-rust/blob/a035f6fa1f14754bab8f34376c386fafc831b652/1.49.0/buster/Dockerfile の末尾に
RUN apt-get update \
&& apt-get install -y valgrind
RUN cargo install cargo-profiler \
&& chmod -R a+w $CARGO_HOME
を書き加えたものになります。
AtCoderのジャッジサーバのバージョンに合わせて、Rust v1.49.0を使っています。)
cargoプロジェクトのビルド
$ docker run --rm --user "$(id -u)":"$(id -g)" \
-v /your/cargo/project/path:/workspace \
-w /workspace cargo-profiler \
cargo build --release
(/your/cargo/project/path
には、プロファイル対象のcargoプロジェクトのルートディレクトリを記載してください。)
プロファイル実行
$ docker run --rm --user "$(id -u)":"$(id -g)" \
-v /your/cargo/project/path:/workspace \
-w /workspace cargo-profiler \
cargo profiler callgrind --bin target/release/a -n 5
(target/release/a
部分は実行ファイルパスを入れてください。)
以下のような結果が得られます。
Profiling a with callgrind...
Total Instructions...7,131,502,099
1,228,544,445 (17.2%) ???:a::State
-----------------------------------------------------------------------
1,067,368,888 (15.0%) malloc.c:_int_free'2
-----------------------------------------------------------------------
1,017,529,165 (14.3%) ???:<alloc::vec
-----------------------------------------------------------------------
675,019,392 (9.5%) ???:a::State
-----------------------------------------------------------------------
462,097,916 (6.5%) malloc.c:_int_malloc'2
-----------------------------------------------------------------------
callgrind
の他に、cachegrind
というコマンドもあるようです(私は使ったことないです)。
余談
- Macでも使えたという記事も見つけたのですが、私の環境下では動きませんでした。OSバージョンとかによるんですかね?1
-
macos-profiler という MacOS 向けの
Rustプロファイラもありましたが、私は動かせませんでした。最終コミットが'19年5月だったので、私の環境だと非対応って話な気がしてます。 -
標準入力が渡せないっぽいので、競プロ用途だとちょっと手間2だったりします。私は
cargo-profiler
を使うときだけ、コードを入力をファイルから読み込むように書き換えて使っています。