Recently, I tried to profile some memory and resource usage. As I often find with profiling, I struggled a little bit to get set up. This post outlines profiling a GHC binary, including special considerations for Docker.

Resources on profiling

https://mpickering.github.io/ghc-docs/build-html/users_guide/profiling.html

Compilation

Compile your program as stack build --profile.

Running

Run your program as stack exec --profile $program -- +RTS -p -hm -RTS

See also https://mpickering.github.io/ghc-docs/build-html/users_guide/profiling.html#retainer-profiling for information on retainer profiling.

Viewing profile data

You can view .prof data directly with a text editor. However, you will need the hp2ps utility (available with any installation of ghc and/or ghc-prof) to view a graph of your program’s memory usage: hp2ps -c $program.hp You can open the graph called $program.ps in Preview on a Mac, or you can Google for PostScript rendering applications.

Since the .prof file is not written while a binary is running, it can be difficult to gather statistics for anything service related. Below is a script that can be used to ensure your service stays up while you can gather incremental performance statistics. Thanks to Rick Owens for the skeleton script.

#!/bin/bash
# runs $program - to get profiling information, `ps ax | grep $program` and `kill -2 $pid`
while true
do
    $program +RTS -p -hm -RTS
    sleep 3
    mv $program.hp $program.hp.keep
    mv $program.prof $program.prof.keep
done

Creating a Docker image

If running in Docker, the steps to create a Docker image are a bit more involved.

Your Docker container may need the following packages, which can be installed via apt-get: ghc, ghc-prof.

Change your Dockerfile ENTRYPOINT to be the script above (in viewing profile data). You will need to COPY this script to your container.

Running a Docker image and extracting data

Once your Docker image is created and deployed, in order to collect profiling data you can run the following commands.

docker exec -it $container /bin/bash
ps ax | grep $program # get the pid
kill -2 $pid # -2 aka SIGINT aka CTRL-C
exit
docker cp $container:$path/$program.hp.keep $program.hp
docker cp $container:$path/$program.prof.keep $program.prof
tar -cvzf $program.tar.gz $program.hp $program.prof

Once the data is copied, extract it and refer to viewing profile data.