Profiling
Profiling of generated Rust code
The runrust
script has a --flamegraph
flag for generating flamegraphs of
the execution time. This gives an overview of the execution time broken down by vertices of the
call graph. While this does not perfectly reflect the number of IR gates
generated by particular functions, it shows where the execution time goes.
This setup has been tested on Ubuntu only (setup instructions below).
Usage
With appropriate setup the usage should be as simple as:
$ ./runrust --flamegraph \
docs/M27-electric-vehicle/ev-inf-mod.zksc \
docs/M27-electric-vehicle/pentagon_inputs/public.json \
docs/M27-electric-vehicle/pentagon_inputs/{instance,witness}_darpa_pentagon.json \
-c docs/M27-electric-vehicle/ev-inf-mod.ccc -o opublic > /dev/null
This call generates file src/Rust/flamegraph.svg
that can be viewed with all
modern browsers. Under linux, profile data are gathered with perf
and the data
are written to src/Rust/perf.data
.
This file can be further transformed and used by other tools like
Firefox profiler. Make sure to have rustfilt
installed. The following line also shortens generated functions names to strip
the internal crate name and unique suffix:
perf script -i src/Rust/perf.data | sed -E 's/zkscc_rust::generated::(.*)_u[[:digit:]]*/\1/g' | rustfilt > zkscc_rust.perf
The file zkscc_rust.perf
can be directly loaded into the profile log viewer.
Installing dependencies (Ubuntu)
Install perf
and other possible dependencies. Also modify the
kernel.perf_event_paranoid
setting to make sure that perf
does not have to
be run as root:
sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r`
sudo sysctl -w kernel.kptr_restrict=0
sudo sysctl -w kernel.perf_event_paranoid=-1
To make these changes persist reboots, add a file /etc/sysctl.d/50-perf.conf
with the following contents:
kernel.kptr_restrict=0
kernel.perf_event_paranoid=-1
Make sure that cargo install directory (usually ~/.cargo/bin
) is found in $PATH
. Install cargo-flamegraph as user:
cargo install flamegraph
Installing rustfilt
is not necessary but it will help demangle function names
to a more readable form:
cargo install rustfilt
Troubleshooting
It's so slow!
The overhead should be less than twice in time.
The issue might be that perf
shipped with Ubuntu can be very slow. The solution is to install perf
shipped with kernel that is linked against libbfd. We start by installing various dependencies that might be used by perf
:
sudo apt install \
flex \
bison \
libelf-dev \
libaudit-dev \
libdw-dev \
libunwind-dev \
python2-dev \
binutils-dev \
libnuma-dev \
libgtk2.0-dev \
libbfd-dev \
libelf1 \
libperl-dev \
libnuma-dev \
libslang2 libslang2-dev \
libunwind8 libunwind8-dev \
binutils-multiarch-dev \
elfutils \
libiberty-dev
The following commands to install perf
to ~/.local/bin
is for my particular kernel version; substitute your own.
sudo apt install linux-source
cd <some working directory>
cp /usr/src/linux-source-5.15.0/linux-source-5.15.0.tar.bz2 .
tar xvfj linux-source-5.15.0.tar.bz2
cd linux-source-5.15.0/tools/perf
make prefix=$HOME/.local install-bin
Profiling the frontend Haskell code
The simplest way to install the ZK-SecreC compiler frontend with profiling enabled is to invoke stack with appropriate profiling flag:
$ stack install --profile
By default, this installs ZK-SecreC compiler frontend with profiling enabled to ~/.local/bin
directory. Make sure that this directory is found in PATH
environment variable.
In order to make the compiler produce profiling output, appropriate flags must be
passed to the Haskell run time system (RTS). For example, to obtain regular
profiling output we must add flag +RTS -p
to the original command line call.
After calling
$ zkscc <regular options> +RTS -p
profiling output will be written to a human readable file zkscc.prof
.
Heap profiling output is produced with flag -h
:
$ zkscc <regular options> +RTS -h
This produces a file zkscc.hp
that must be converted to .ps
format using
hp2ps
utility (should be bundled with GHC).
Much more details about profiling Haskell programs with GHC can be found in the documentation of GHC.