Giter VIP home page Giter VIP logo

package-benchmark's Introduction

Swift address sanitizer Swift thread sanitizer codecov

Benchmark

Benchmark allows you to easily create sophisticated Swift performance benchmarks

Overview

Performance is a key feature for many apps and frameworks. Benchmark helps make it easy to measure and track many different metrics that affects performance, such as CPU usage, ARC traffic, memory/malloc usage and use of operating system resources such as threads and system calls, as well as completely custom metric counters.

Benchmark works on both macOS and Linux and supports several key workflows for performance measurements:

Benchmark provides a quick way for measuring and validating of performance metrics, while other more specialized tools such as Instruments, DTrace, Heaptrack, Leaks, Sample and more can be used for attributing performance problems or for finding root causes for any deviations found.

Benchmark is suitable for both smaller ad-hoc benchmarks focusing on execution time and more extensive benchmarks that care about several additional metrics such as memory allocations, syscalls, thread usage, context switches, ARC traffic, and more. Using Histogram it’s especially suitable for capturing latency statistics for large number of samples.

Documentation

Documentation on how to use Benchmark in your Swift package can be viewed online or inside Xcode using Build Documentation.

Additionally the command plugin provides help information if you run swift package benchmark help from the command line.

Adding dependencies and getting started

There are just a few steps required to get started benchmarking:

  1. Add a dependency to the Benchmark project
  2. Add benchmark executable targets with swift package benchmark init
  3. Add the snippet or code you want to benchmark
  4. Run swift package benchmark

The steps in some detail:

Step 1: Add a package dependency to Package.swift

To add the dependency on Benchmark, add the dependency to your package:

.package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0")),

Step 2: Add benchmark exectuable targets using benchmark init

The absolutely easiest way to add new benchmark executable targets to your project is by using:

swift package --allow-writing-to-package-directory benchmark init MyNewBenchmarkTarget

This will perform the following steps for you:

  • Create a Benchmarks/MyNewBenchmarkTarget directory
  • Create a Benchmarks/MyNewBenchmarkTarget/MyNewBenchmarkTarget.swift benchmark target with the required boilerplate
  • Add a new executable target for the benchmark to the end of your Package.swift file

The init command validates that the name you specify isn’t used by any existing target and will not overwrite any existing file with that name in the Benchmarks/ location.

After you’ve created the new target, you can directly run it with e.g.:

swift package benchmark --target MyNewBenchmarkTarget

Step 2 (optional approach): Add benchmark exectuable targets manually

Alternatively if you don't want the plugin to modify your project directory, you can do the same steps manually: Create an executable target in Package.swift for each benchmark suite you want to measure. The source for all benchmarks must reside in a directory named Benchmarks in the root of your swift package. The benchmark plugin uses this directory combined with the executable target information to automatically discover and run your benchmarks. For each executable target, include dependencies on both Benchmark (supporting framework) and BenchmarkPlugin (boilerplate generator) from package-benchmark. The following example shows an benchmark suite named My-Benchmark with the required dependency on Benchmark and the source files for the benchmark that reside in the directory Benchmarks/My-Benchmark:

.executableTarget(
      name: "My-Benchmark",
      dependencies: [
          .product(name: "Benchmark", package: "package-benchmark"),
      ],
      path: "Benchmarks/My-Benchmark",
      plugins: [
          .plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
      ]
),

Step 3: Writing benchmarks

There are documentation available as well as a a sample project using various aspects of this package in practice.

Sample benchmark code

import Benchmark

let benchmarks = {
    Benchmark("Minimal benchmark") { benchmark in
      // measure something here
    }

    Benchmark("All metrics, full concurrency, async",
              configuration: .init(metrics: BenchmarkMetric.all,
                                   maxDuration: .seconds(10)) { benchmark in
        let _ = await withTaskGroup(of: Void.self, returning: Void.self, body: { taskGroup in
            for _ in 0..<80  {
                taskGroup.addTask {
                    dummyCounter(defaultCounter()*1000)
                }
            }
            for await _ in taskGroup {
            }
        })
    }
}

Step 4: Running benchmarks

To execute all defined benchmarks, simply run:

swift package benchmark

Please see the documentation for more detail on all options.

Sample output benchmark run

image

Sample output benchmark grouped by metric

image

Sample output delta comparison

image

Sample output threshold deviation check

image

Sample usage of YouPlot

Install YouPlot

swift package benchmark run --filter InternalUTCClock-now --metric wallClock --format histogramPercentiles --path stdout --no-progress | uplot lineplot -H

image

JMH Visualization

Using jmh.morethan.io

image

image

Output

The default text output from Benchmark is oriented around the five-number summary percentiles, plus the last decile (p90) and the last percentile (p99) - it's thus a variation of a seven-figure summary with the focus on the 'bad' end of results (as those are what we typically care about addressing). We've found that focusing on percentiles rather than average or standard deviations, is more useful for a wider range of benchmark measurements and gives a deeper understanding of the results. Percentiles allows for a consistent way of expressing benchmark results of both throughput and latency measurements (which typically do not have a standardized distribution, being almost always multi-modal in nature). This multi-modal nature of the latency measurements leads to the common statistical measures of mean and standard deviation being potentially misleading.

API and file format stability

The API will be deemed stable as of 1.0.0 and follows semantical versioning for future releases.

The export file formats that are externally defined (e.g. JMH or HDR Histogram formats) will follow the upstream definitions if they change, but have been quite stable for several years.

The Histogram codable representation is not stable and may change if the Histogram implementation changes.

The benchmark internal baseline representation (stored in .benchmarkBaselines) is not stable and is not viewed as public API and may break over time.

For those wanting to save benchmark data over time, it's recommended to export data in e.g. HDR Histogram representations (percentiles, average, stddev etc) or simply post processing the histogramSamples format (which is raw data) to your desired representation.

PR:s for additional standardized formats are welcome, as the export formats are the intended stable interface for saving such data.

package-benchmark's People

Contributors

hassila avatar ordo-ci avatar heckj avatar freef4ll avatar dimlio avatar oryanhampton avatar axelandersson avatar github-actions[bot] avatar gnmoseke avatar kkebo avatar mahdibm avatar finestructure avatar clackary avatar

Stargazers

Tim Kersey avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.