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.