packages feed

tracy-profiler-0.1.2.1: README.md

# tracy-profiler

Haskell bindings for [Tracy frame profiler](https://github.com/wolfpld/tracy).

## Setup

### Installing

You can install the prebuilt package from your distribution if it has one:

```sh
sudo apt install libtracy-dev tracy-capture tracy-profiler
```

Or you can download and build one yourself and point your project to it:

```yaml
# stack.yaml
extra-lib-dirs:
- upstream/_build/library
extra-include-dirs:
- upstream/tracy/public/tracy
```

You can use the provided Makefile that will do the thing:
```sh
make all # fetch and build stuff
make test # run the example
_build/profiler/tracy-profiler & disown # launch the profiler GUI
```

This way you can customize configuration.
Make sure you update package flags to match.

Either way, you have to ensure that `tracy-capture`/`tracy-profiler` is built with the same version.
Otherwise it will connect and immediately refuse to record anything.

### Flags

The flags must match whatever the library has been built with.

By default all the instrumentation wrappers do nothing.
That means you don't have to `ifdef` your code to remove the wrappers when they're not needed.

You have to set the `enable` flag in your project for the data to be collected.

```yaml
flags:
  tracy-profiler:
    enable: true
    # manual_lifetime: false
    # fibers: false
```

## Instrumentation

Use the functions from `System.Tracy` and `System.Tracy.Zone` to collect data:

```haskell
{-# LANGUAGE MagicHash #-}         -- "static strings"#
{-# LANGUAGE OverloadedLabels #-}  -- #fuchsia colors
{-# LANGUAGE OverloadedStrings #-} -- "yes"

module Main where

import qualified System.Tracy as Tracy
import qualified Data.Text as Text

main :: IO ()
main = Tracy.withProfiler $ do
  Tracy.waitConnected_       -- wait for the tracy-capture to connect
  Tracy.withSrcLoc "main.nowhereInParticular" #f0fa do
    Tracy.messageL "hi there"# -- static strings require no copying to be logged
    mapM_ runFrame [0..600]

runFrame :: Int -> IO ()
runFrame ix = Tracy.withSrcLoc "runFrame" #fcc do
  Tracy.frameMark_
  let factorial = product [1 .. toInteger ix]
  let !digits = length (show factorial)
  Tracy.message . Text.pack $
    -- runtime strings will require some memcpy'ng around, use sparingly on hot paths
    "!" <> show ix <> " has " <> show digits <> " digits"
  Tracy.plotInt "digits"# digits
```

## Collecting and viewing

Start `tracy-capture` before running the test to avoid empty areas where nothing happens:

```sh
tracy-capture -fo output.tracy &
```

Run the code, then upload the collected data to [the viewer](https://tracy.nereid.pl/).

You'll see something like this:

![screenshot](https://raw.githubusercontent.com/haskell-game/tracy-profiler/refs/heads/main/readme.png)

> Are those are GC pauses we're looking at? 🤔

## RTFM

You really should go read the official [manual](https://github.com/wolfpld/tracy/blob/master/manual/tracy.md).

Yes, BEFORE you run into corrupted memory, surprising grouppings, or otherwise botched profiling runs.