# Tasks & targets

Blackbench comes with tasks and targets. Tasks represent a specific task Black has do
during formatting, and come with a specific template. Targets are the actual files Black
(or more specifically the task's template / code which calls the relevant Black APIs) is
run against to gauge performance. Together they create benchmarks that are ran using
[pyperf](https://pypi.org/project/pyperf).

Why not just ship ready-to-go benchmark scripts instead? Well, there's a few issues with
that: running static benchmarks limits the available configuration. Want to benchmark
Black with the magic trailing comma disabled? You'd have to edit each benchmark which is
annoying. And even if providing scripts for all of the different possible configurations
was possible, they would be annoying to maintain.

Benchmarks ran by blackbench are named using the task and target they are based off. For
example a benchmark using the `parse` task and the `strings-list` target would be named
`parse-strings-list`. Oh and benchmarks based off micro targets are called also
microbenchmarks (since the goal of checking the performance of a specific area
transfers).

Below are details about the tasks and targets that ship with blackbench:

## Tasks

- `fmt`: standard Black formatting behaviour although safety checks will **always** be
  run
- `fmt-fast`: like `fmt` but using `--fast` so safety checks are disabled
- `parse`: only do blib2to3 parsing

(labels/format-task-danger)=

```{important}
The `fmt` task forces safety checks to run (by adding trailing newlines) or else it could
skew the data in a nasty way. Normally safety checks only run if changes are made so there's
a possibility one version of Black will have to do more work over the other one you're
comparing against, totally throwing off the results for any sort of comparisons.
```

## Targets

Targets are a bit more complex since there's two types: normal and micro. Normal targets
represent real-world code (and aim to do a decent job to representing real-world use
cases and performance). Micro targets are typically smaller and are focused on one area
of black formatting (and mostly exist to measure performance in a specific area, like
string processing).

**Normal targets:**

- `black/*`: source code files from {pypi}`Black` 21.6b0 (9 targets)
- `flit/*` & `filt_core/*`: source code files from {pypi}`Flit` 3.2.0 (3 targets)

**Micro targets:**

- `dict-literal`: a long dictionary literal
- `comments`: code that uses a lot of (maybe special) comments
- `list-literal`: a long list literal
- `nested`: nested functions, literals, if statements ... all the nested!
- `strings-list`: a list containing 100s of sometimes comma separated strings

(labels/task-compatibility)=

## Compatibility

While it would be great if blackbench could support all versions of Black, this is
difficult if not impossible since tasks use internal components of Black's
implementation. This provides a benchmarking speedup and is also unavoidable for lower
level tasks like `parse`. Due to this, each task imposes restrictions to what version of
Black their benchmarks can be run under:

- `fmt`, `fmt-fast`, and `parse`: >= 19.3b0

## Useful commands

Blackbench does have a few commands that interact directly with tasks and targets:

`blackbench dump ${name}`

: Dumps the source code for a specific task or target.

  ```console
  dev@example:~$ blackbench dump fmt-fast
  from pathlib import Path

  import pyperf

  import black

  runner = pyperf.Runner()
  code = Path(r"{target}").read_text(encoding="utf8")


  def format_func(code):
      try:
          black.format_file_contents(code, fast=True, mode=black.FileMode({mode}))
      except black.NothingChanged:
          pass


  runner.bench_func("{name}", format_func, code)
  ```

`blackbench info`

: Lists all of the built-in tasks and targets.

  ```console
  dev@example:~$ blackbench info
  Tasks:
    1. fmt - Standard Black run although safety checks will *always* run
    2. fmt-fast - Standard Black run but safety checks are *disabled*
    3. parse - Only do blib2to3 parsing

  Normal targets:
    1. black/__init__ [1132 lines] - Black source code from 21.6b0
    2. black/brackets [334 lines] - Black source code from 21.6b0
    3. black/comments [272 lines] - Black source code from 21.6b0
    4. black/linegen [985 lines] - Black source code from 21.6b0
    5. black/lines [734 lines] - Black source code from 21.6b0
    6. black/mode [123 lines] - Black source code from 21.6b0
    7. black/nodes [843 lines] - Black source code from 21.6b0
    8. black/output [84 lines] - Black source code from 21.6b0
     9. black/strings [216 lines] - Black source code from 21.6b0
    10. flit/install [415 lines] - Flit source code from 3.2.0
    11. flit/sdist [216 lines] - Flit source code from 3.2.0
    12. flit_core/config [630 lines] - Flit source code from 3.2.0

  Micro targets:
    1. dict-literal [150 lines] - A long dictionary literal
    2. comments [97 lines] - Code that uses a lot of (maybe special) comments
    3. list-literal [150 lines] - A long list literal
    4. nested [41 lines] - Nested functions, literals, if statements ... all the nested!
    5. strings-list [52 lines] - A list containing 100s of sometimes comma separated strings
  ```
