Skip to content

Commit

Permalink
dev: profile prisma engines in OSX with valgrind (prisma#3815)
Browse files Browse the repository at this point in the history
  • Loading branch information
Miguel Fernández authored Mar 29, 2023
1 parent 64c8eb0 commit f46cb6b
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ datamodel_v2.prisma
dev_datamodel.prisma
.tmp/
/target/
/target-alternatives/
/result

dmmf.json
Expand Down
4 changes: 4 additions & 0 deletions Brewfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
brew "docker"
brew "protobuf"
brew "direnv"
brew "rustup-init"
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ strip = "symbols"
lto = "fat"
codegen-units = 1
opt-level = 's' # Optimize for size.

[profile.profiling]
inherits = "release"
debug = true
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ LIBRARY_EXT := $(shell \

default: build

#####################
# Boostrap commands #
#####################

bootstrap-darwin:
script/bootstrap-darwin

##################
# Build commands #
##################
Expand Down
26 changes: 26 additions & 0 deletions script/.profile/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
ARG RUST_VERSION
FROM rust:$RUST_VERSION-buster
RUN printf "deb http://ftp.de.debian.org/debian buster main" >> /etc/apt/sources.list
RUN apt update
RUN apt-get install -y git valgrind

# Symlink caches
RUN mkdir -p /.cargo/registry \
/.cargo/git \
/.cargo/.package-cache
RUN rm -rf /usr/local/cargo/git \
/usr/local/cargo/registry \
/usr/local/cargo/.package-cache \
/usr/local/cargo/.crates.toml \
/usr/local/cargo/.crates2.json
RUN ln -s /.cargo/git /usr/local/cargo
RUN ln -s /.cargo/registry /usr/local/cargo
RUN ln -s /.cargo/.package-cache /usr/local/cargo
RUN ln -s /.cargo/.crates.toml /usr/local/cargo
RUN ln -s /.cargo/.crates2.json /usr/local/cargo

# Set env
ENV PATH="${PATH}:/rustrepo/script/.profile/bin"
ENV VALGRIND_LIB=/usr/lib/aarch64-linux-gnu/valgrind/
ENV VALID_TOOLS="memcheck cachegrind callgrind helgrind drd massif sgcheck memcheck-dhat"
ENV CARGO_TARGET_DIR=target-alternatives
3 changes: 3 additions & 0 deletions script/.profile/bin/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#/bin/bash
echo "==> Building examples to profile..."
cd /rustrepo && cargo build --profile=profiling --examples
3 changes: 3 additions & 0 deletions script/.profile/bin/build-and-run
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#/bin/bash
echo "==> Running: build && run-valgrind $@"
build && run-valgrind $@
23 changes: 23 additions & 0 deletions script/.profile/bin/run-valgrind
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
VALID_TOOLS=" memcheck cachegrind callgrind helgrind drd massif sgcheck dhat "
EXAMPLES_DIR="/rustrepo/target-alternatives/profiling/examples"
VALID_EXAMPLES=$(find $EXAMPLES_DIR -type f -perm -u=x -printf "%f\n")
DEFAULT_EXAMPLE=$(echo "${VALID_EXAMPLES}" | head -n1)
EXAMPLE=${2:-${DEFAULT_EXAMPLE}}
TOOL=$1
ARGS=${*:3}

if [ -z "$2" ] || ! [[ " ${VALID_TOOLS} " == *" $TOOL "* ]] || [ ! -f "$EXAMPLES_DIR/$EXAMPLE" ]; then
echo ""
echo "❌ Failed to run command: $*"
echo ""
echo " Usage: $0 tool example"
echo " Valid tools: ${VALID_TOOLS}. See https://valgrind.org/docs/manual/manual.html"
echo " Valid examples: ${VALID_EXAMPLES}"
echo " Example: $0 massif ${DEFAULT_EXAMPLE}"
exit 1
else
CMD="valgrind $ARGS --tool=$TOOL $EXAMPLES_DIR/$EXAMPLE"
echo "==> Running valgrind: $CMD"
exec $CMD
fi
73 changes: 73 additions & 0 deletions script/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
## Scripts to rule them all.

Inspired by https://github.com/github/scripts-to-rule-them-all

> If your scripts are normalized by name across all of your projects, your contributors only need to know the pattern, not a deep knowledge of the application. This means they can jump into a project and make contributions without first learning how to bootstrap the project or how to get its tests to run.
This scripts can also be run with make. Following the convention: `script/$TARGET` -> `make $TARGET`. For instance, make bootstrap-darwin will run `script/bootstrap-darwin`

If instead you are a user of the [nix](https://nixos.org/manual/nix/stable/) package manager, you might find interesting packages and in the [nix](../nix/) directory.

### The scripts

#### script/bootstrap-darwin

[`script/bootstrap-darwin`](bootstrap-darwin) is used for fulfilling dependencies of the project and ensure it builds correctly.

The goal is to make sure all required dependencies are installed, and the workspace builds.

#### script/profile

[`script/profile`](profile) allows to run Valgrind profiling over any example in the primsa-engines
repository, using a linux docker image as a bride.

Example. Let´s say we want to use [`massif`](https://valgrind.org/docs/manual/ms-manual.html) to profile heap allocations, same will apply to other tools:

```sh
> ~/GitHub/prisma/prisma-engines
❯ script/profile massif schema_builder_build_odoo
==> Profiling docker image (prisma-engines-profile:1.68.0.31f76) exists, using it
==> Running command: docker run -it -v /Users/miguel/GitHub/prisma/prisma-engines:/rustrepo -v /Users/miguel/.cargo:/.cargo -w /rustrepo prisma-engines-profile:1.68.0.31f76 bash -C build-and-run massif schema_builder_build_odoo
==> Running: build && run-valgrind massif schema_builder_build_odoo
==> Building examples to profile...
Finished profiling [optimized + debuginfo] target(s) in 15.08s
warning: the following packages contain code that will be rejected by a future version of Rust: connection-string v0.1.13
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 33`
==11== Massif, a heap profiler
==11== Copyright (C) 2003-2017, and GNU GPL'd, by Nicholas Nethercote
==11== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==11== Command: /rustrepo/target-alternatives/profiling/examples/schema_builder_build_odoo
==11==
Elapsed: 5.78s
==11==
```
The massif output file was generated in the own repository folder, which was mounted in the docker image
```sh
❯ git status
Untracked files:
massif.out.11
```
Then use [`script/profile-shell`](profile-shell) to view the results using `ms-print` as the [docs](https://valgrind.org/docs/manual/ms-manual.html) suggest:
```
```sh
❯ script/profile-shell ms_print /rustrepo/massif.out.11 |tail -n10
->01.42% (2,305,284B) 0x151446: <alloc::string::String as core::clone::Clone>::clone (alloc.rs:95)
->01.42% (2,305,284B) in 42 places, all below massif's threshold (1.00%)

--------------------------------------------------------------------------------
n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B)
--------------------------------------------------------------------------------
51 2,400,085,093 140,932,776 124,442,047 16,490,729 0
52 2,423,804,986 94,167,552 83,189,217 10,978,335 0
53 2,447,524,833 47,307,048 41,851,522 5,455,526 0
54 2,471,244,705 4,387,240 4,122,973 264,267 0
```

#### script/profile-shell

[`script/profile-shell`](profile-shell). Use it to run arbitrary commands on the docker profiling image. See the example provided in [`script/profile`](profile)
21 changes: 21 additions & 0 deletions script/bootstrap-darwin
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# script/bootstrap-darwin: Resolve all dependencies that the application requires to
set -e
cd "$(dirname "$0")/.."

if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then
brew bundle check >/dev/null 2>&1 || {
echo "==> Installing Homebrew dependencies…"
brew bundle
}
fi

echo "==> Checking for default rust installation"
rustc --version
rustup default stable > /dev/null

echo "==> Building the prisma-engines workspace"
if cargo build --workspace --all-targets; then
echo "==> You are all set!"
fi
7 changes: 7 additions & 0 deletions script/profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

# script/profile: Profile any example in the repository using valgrind tools like DHAT and Massif.

set -e
cd "$(dirname "$0")"
./profile-shell "bash -C build-and-run $*"
15 changes: 15 additions & 0 deletions script/profile-shell
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# script/profile_shell: Run any command on the profile image, where rust and valgrind are installed
# By default it will run the bash shell

set -e
cd "$(dirname "$0")/.."

rust_version=$(rustc --version | cut -d ' ' -f 2)
CMD="docker build -t prisma-engines-profile:latest --build-arg RUST_VERSION=$rust_version -f script/.profile/Dockerfile ."
echo "==> Running command: $CMD"
eval "$CMD"
CMD="docker run -it -v $PWD:/rustrepo -v $HOME/.cargo:/.cargo -w /rustrepo prisma-engines-profile:latest $*"
echo "==> Running command: $CMD"
exec $CMD

0 comments on commit f46cb6b

Please sign in to comment.