|
| 1 | +# Profiling Test Performance |
| 2 | + |
| 3 | +When you run Vitest it reports multiple time metrics of your tests: |
| 4 | + |
| 5 | +> ```bash |
| 6 | +> RUN v2.1.1 /x/vitest/examples/profiling |
| 7 | +> |
| 8 | +> ✓ test/prime-number.test.ts (1) 4517ms |
| 9 | +> ✓ generate prime number 4517ms |
| 10 | +> |
| 11 | +> Test Files 1 passed (1) |
| 12 | +> Tests 1 passed (1) |
| 13 | +> Start at 09:32:53 |
| 14 | +> Duration 4.80s (transform 44ms, setup 0ms, collect 35ms, tests 4.52s, environment 0ms, prepare 81ms) |
| 15 | +> # Time metrics ^^ |
| 16 | +> ``` |
| 17 | +
|
| 18 | +- Transform: How much time was spent transforming the files. See [File Transform](#file-transform). |
| 19 | +- Setup: Time spent for running the [`setupFiles`](/config/#setupfiles) files. |
| 20 | +- Collect: Time spent for colleting all tests in the test files. This includes the time it took to import all file dependencies. |
| 21 | +- Tests: Time spent for actually running the test cases. |
| 22 | +- Environment: Time spent for setting up the test environment, for example JSDOM. |
| 23 | +- Prepare: Time Vitest uses to prepare the test runner. |
| 24 | +
|
| 25 | +## Test runner |
| 26 | +
|
| 27 | +In cases where your test execution time is high, you can generate a profile of the test runner. See NodeJS documentation for following options: |
| 28 | +
|
| 29 | +- [`--cpu-prof`](https://nodejs.org/api/cli.html#--cpu-prof) |
| 30 | +- [`--heap-prof`](https://nodejs.org/api/cli.html#--heap-prof) |
| 31 | +- [`--prof`](https://nodejs.org/api/cli.html#--prof) |
| 32 | +
|
| 33 | +:::warning |
| 34 | +The `--prof` option does not work with `pool: 'threads'` due to `node:worker_threads` limitations. |
| 35 | +::: |
| 36 | +
|
| 37 | +To pass these options to Vitest's test runner, define `poolOptions.<pool>.execArgv` in your Vitest configuration: |
| 38 | +
|
| 39 | +::: code-group |
| 40 | +```ts [Forks] |
| 41 | +import { defineConfig } from 'vitest/config' |
| 42 | +
|
| 43 | +export default defineConfig({ |
| 44 | + test: { |
| 45 | + pool: 'forks', |
| 46 | + poolOptions: { |
| 47 | + forks: { |
| 48 | + execArgv: [ |
| 49 | + '--cpu-prof', |
| 50 | + '--cpu-prof-dir=test-runner-profile', |
| 51 | + '--heap-prof', |
| 52 | + '--heap-prof-dir=test-runner-profile' |
| 53 | + ], |
| 54 | +
|
| 55 | + // To generate a single profile |
| 56 | + singleFork: true, |
| 57 | + }, |
| 58 | + }, |
| 59 | + }, |
| 60 | +}) |
| 61 | +``` |
| 62 | +```ts [Threads] |
| 63 | +import { defineConfig } from 'vitest/config' |
| 64 | +
|
| 65 | +export default defineConfig({ |
| 66 | + test: { |
| 67 | + pool: 'threads', |
| 68 | + poolOptions: { |
| 69 | + threads: { |
| 70 | + execArgv: [ |
| 71 | + '--cpu-prof', |
| 72 | + '--cpu-prof-dir=test-runner-profile', |
| 73 | + '--heap-prof', |
| 74 | + '--heap-prof-dir=test-runner-profile' |
| 75 | + ], |
| 76 | +
|
| 77 | + // To generate a single profile |
| 78 | + singleThread: true, |
| 79 | + }, |
| 80 | + }, |
| 81 | + }, |
| 82 | +}) |
| 83 | +``` |
| 84 | +::: |
| 85 | +
|
| 86 | +After the tests have run there should be a `test-runner-profile/*.cpuprofile` and `test-runner-profile/*.heapprofile` files generated. See [Inspecting profiling records](#inspecting-profiling-records) for instructions how to analyze these files. |
| 87 | +
|
| 88 | +See [Profiling | Examples](https://github.com/vitest-dev/vitest/tree/main/examples/profiling) for example. |
| 89 | +
|
| 90 | +## Main thread |
| 91 | +
|
| 92 | +Profiling main thread is useful for debugging Vitest's Vite usage and [`globalSetup`](/config/#globalsetup) files. |
| 93 | +This is also where your Vite plugins are running. |
| 94 | +
|
| 95 | +:::tip |
| 96 | +See [Performance | Vite](https://vitejs.dev/guide/performance.html) for more tips about Vite specific profiling. |
| 97 | +::: |
| 98 | +
|
| 99 | +To do this you'll need to pass arguments to the Node process that runs Vitest. |
| 100 | +
|
| 101 | +```bash |
| 102 | +$ node --cpu-prof --cpu-prof-dir=main-profile ./node_modules/vitest/vitest.mjs --run |
| 103 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ |
| 104 | +# NodeJS arguments Vitest arguments |
| 105 | +``` |
| 106 | +
|
| 107 | +After the tests have run there should be a `main-profile/*.cpuprofile` file generated. See [Inspecting profiling records](#inspecting-profiling-records) for instructions how to analyze these files. |
| 108 | +
|
| 109 | +## File transform |
| 110 | +
|
| 111 | +In cases where your test transform and collection time is high, you can use `DEBUG=vite-node:*` environment variable to see which files are being transformed and executed by `vite-node`. |
| 112 | +
|
| 113 | +```bash |
| 114 | +$ DEBUG=vite-node:* vitest --run |
| 115 | +
|
| 116 | + RUN v2.1.1 /x/vitest/examples/profiling |
| 117 | +
|
| 118 | + vite-node:server:request /x/vitest/examples/profiling/global-setup.ts +0ms |
| 119 | + vite-node:client:execute /x/vitest/examples/profiling/global-setup.ts +0ms |
| 120 | + vite-node:server:request /x/vitest/examples/profiling/test/prime-number.test.ts +45ms |
| 121 | + vite-node:client:execute /x/vitest/examples/profiling/test/prime-number.test.ts +26ms |
| 122 | + vite-node:server:request /src/prime-number.ts +9ms |
| 123 | + vite-node:client:execute /x/vitest/examples/profiling/src/prime-number.ts +9ms |
| 124 | + vite-node:server:request /src/unnecessary-file.ts +6ms |
| 125 | + vite-node:client:execute /x/vitest/examples/profiling/src/unnecessary-file.ts +4ms |
| 126 | +... |
| 127 | +``` |
| 128 | +
|
| 129 | +This profiling strategy is a good way to identify unnecessary transforms caused by [barrel files](https://vitejs.dev/guide/performance.html#avoid-barrel-files). |
| 130 | +If these logs contain files that should not be loaded when your test is run, you might have barrel files that are importing files unnecessarily. |
| 131 | +
|
| 132 | +You can also use [Vitest UI](/guide/ui) to debug slowness caused by barrel file. |
| 133 | +The example below shows how importing files without barrel file reduces amount of transformed files by ~85%. |
| 134 | +
|
| 135 | +::: code-group |
| 136 | +``` [File tree] |
| 137 | +├── src |
| 138 | +│ └── utils |
| 139 | +│ ├── currency.ts |
| 140 | +│ ├── formatters.ts <-- File to test |
| 141 | +│ ├── index.ts |
| 142 | +│ ├── location.ts |
| 143 | +│ ├── math.ts |
| 144 | +│ ├── time.ts |
| 145 | +│ └── users.ts |
| 146 | +├── test |
| 147 | +│ └── formatters.test.ts |
| 148 | +└── vitest.config.ts |
| 149 | +``` |
| 150 | +```ts [example.test.ts] |
| 151 | +import { expect, test } from 'vitest' |
| 152 | +import { formatter } from '../src/utils' // [!code --] |
| 153 | +import { formatter } from '../src/utils/formatters' // [!code ++] |
| 154 | +
|
| 155 | +test('formatter works', () => { |
| 156 | + expect(formatter).not.toThrow() |
| 157 | +}) |
| 158 | +``` |
| 159 | +::: |
| 160 | +
|
| 161 | +<img src="/module-graph-barrel-file.png" alt="Vitest UI demonstrating barrel file issues" /> |
| 162 | +
|
| 163 | +To see how files are transformed, you can use `VITE_NODE_DEBUG_DUMP` environment variable to write transformed files in the file system: |
| 164 | +
|
| 165 | +```bash |
| 166 | +$ VITE_NODE_DEBUG_DUMP=true vitest --run |
| 167 | +
|
| 168 | +[vite-node] [debug] dump modules to /x/examples/profiling/.vite-node/dump |
| 169 | +
|
| 170 | + RUN v2.1.1 /x/vitest/examples/profiling |
| 171 | +... |
| 172 | +
|
| 173 | +$ ls .vite-node/dump/ |
| 174 | +_x_examples_profiling_global-setup_ts-1292904907.js |
| 175 | +_x_examples_profiling_test_prime-number_test_ts-1413378098.js |
| 176 | +_src_prime-number_ts-525172412.js |
| 177 | +``` |
| 178 | +
|
| 179 | +## Inspecting profiling records |
| 180 | +
|
| 181 | +You can inspect the contents of `*.cpuprofile` and `*.heapprofile` with various tools. See list below for examples. |
| 182 | +
|
| 183 | +- [Speedscope](https://www.speedscope.app/) |
| 184 | +- [Profile Node.js performance with the Performance panel | developer.chrome.com](https://developer.chrome.com/docs/devtools/performance/nodejs#analyze) |
| 185 | +- [Memory panel overview | developer.chrome.com](https://developer.chrome.com/docs/devtools/memory-problems/heap-snapshots#view_snapshots) |
0 commit comments