pocket_watch

Package Version Hex Docs

pocket_watch is a lightweight rapid benchmarking library.

If you have a function or two that are taking longer than expected to run, you can quickly measure their execution time using this library!

Well it’s fast most of the time, but sometimes it gets really slow.

Try one of the summary functions, which collect execution times over multiple runs and give you aggregate stats. You can even run a function multiple times each time it’s called, and simply return the first value collected without interrupting your normal control flow!

Cool. Can I trace the execution time of every function called in my application throughout its lifecycle, along with memory usage and cache-miss rates?

Whoa there buckaroo– this is a pocket watch, not a profiler!

If you need more control, more precision, or a deeper integration into your runtime, I suggest looking into Erlang– or JavaScript-specific profiling tools.

gleam add pocket_watch@2

Examples

Simple:

import pocket_watch

pub fn main() {
  use <- pocket_watch.simple("with `use`")

  a_long()
  |> long
  |> very_slow
  |> pipeline
}
// pocket_watch [with `use`]: took 42.0s

Without use:

import pocket_watch

pub fn main() {
  let fun = fn() { a_slow_function("with", "arguments") }

  pocket_watch.simple("without `use`", fun)
}
// pocket_watch [without `use`]: took 800ms

With a custom callback:

import simplifile
import pocket_watch

fn log_time(label, elapsed) {
  simplifile.append(
    to: "./log.txt",
    contents: label <> ": took " <> elapsed <> "\n",
  )
}

pub fn main() {
  use <- pocket_watch.callback(log_time("logged function", _))

  another_very()
  slow_block_of_code()
}
// in ./log.txt:
// logged function: took 6.9m

Run a function multiple times and aggregate the results:

import pocket_watch

pub fn main() {
  use <- pocket_watch.summary_simple("simple summary", runs: 100, warmup: 0)

  function_thats_usually_fast_but_occasionally_really_slow()
}
// pocket_watch [simple summary]: min: 210.0ns, max: 100.02ms, median: 6.0ms, mean: 12.77ms
//                                warmup: 0/0.0ns, total post-warmup: 100/1.28s

Aggregate with a custom callback:

import pocket_watch/summary

pub fn main() {
  use <- summary.callback(
    runs: 10_000,
    warmup: 100,
    with: summary.label("sprint", summary.show_rates),
  )

  function_that_gets_faster_over_time()
}
// pocket_watch [sprint]: warmup: 6.6/s, post-warmup: 13.63/s

Collect a summary to work with directly:

import pocket_watch/summary.{Summary}

pub fn main() { 
  let Summary(
    values:, // List of return values from each run
    times:, // List of times from each run
    runs:, // Number of runs
    warmup_runs:, // Number of warmup runs
    warmup:, // Warmup time elapsed
    total:, // Total (post-warmup) time elapsed
    min:, // Fastest run time
    max:, // Slowest run time
    median:, // Median run time
    mean:, // Mean/average run time
  ) = summary.collect(runs: 100, warmup: 0, time: yet_another_function)
}

Further documentation can be found at https://hexdocs.pm/pocket_watch.

Development

gleam run   # Run the project
gleam test  # Run the tests
Search Document