Initial Commit
This commit is contained in:
71
packages/devtools/tooling/profiler/src/sampler/sampler.md
Normal file
71
packages/devtools/tooling/profiler/src/sampler/sampler.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# sampler
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`Sampler` collects periodic snapshots of runtime metrics (memory usage by default, plus caller-supplied custom metrics). The timer source is injected through a `TimersLike` so tests can advance virtual time deterministically and so non-`setInterval` runtimes (Workers, Deno, embedded JS) can plug in their own scheduler. Sample storage is capped via FIFO eviction so long-running collectors don't leak memory.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod-validated options (`intervalMs > 0`, optional positive `maxSamples`, optional `captureMemory`).
|
||||
- Injectable `Clock`, `TimersLike`, and `MemoryProbe` — the defaults read `Date.now`, `setTimeout`/`clearTimeout`, and `process.memoryUsage`/`performance.memory` respectively.
|
||||
- `start()` / `stop()` are idempotent — double-`start` and double-`stop` are no-ops.
|
||||
- `takeSample(customMetrics?)` records a single sample on demand; same code path used by the scheduled tick.
|
||||
- `getSamples()` / `getSamplesInRange(start, end)` / `clear()` for retrieval and reset.
|
||||
- `events: EventBus<SamplerEventMap>` emits `sampler:start`, `sampler:stop`, `sampler:sample`.
|
||||
- Telemetry: `profiler_samples_total` counter incremented on every sample.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { Sampler } from "@suaveplan/profiler";
|
||||
|
||||
const sampler = new Sampler({ intervalMs: 1000 });
|
||||
sampler.start();
|
||||
// ...
|
||||
sampler.stop();
|
||||
console.log(sampler.getSamples());
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { Sampler } from "@suaveplan/profiler";
|
||||
import type { TimersLike } from "@suaveplan/types";
|
||||
|
||||
const queue: Array<{ cb: () => void; handle: number }> = [];
|
||||
let next = 1;
|
||||
const fakeTimers: TimersLike = {
|
||||
setTimer(cb) {
|
||||
const handle = next++;
|
||||
queue.push({ cb, handle });
|
||||
return handle;
|
||||
},
|
||||
clearTimer() {},
|
||||
};
|
||||
|
||||
let clockT = 0;
|
||||
const sampler = new Sampler({
|
||||
intervalMs: 10,
|
||||
timers: fakeTimers,
|
||||
clock: () => clockT,
|
||||
memoryProbe: () => 4096,
|
||||
});
|
||||
sampler.start();
|
||||
clockT = 10;
|
||||
queue.shift()?.cb();
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class Sampler` — `new Sampler(options: SamplerOptions)`.
|
||||
- `interface SamplerOptions extends SamplerConfig { clock?, timers?, memoryProbe? }`.
|
||||
- Methods: `start`, `stop`, `takeSample`, `getSamples`, `getSamplesInRange`, `isRunning`, `clear`.
|
||||
- Errors: throws `ProfilerError` with `PROFILER.INVALID_OPTIONS` when options fail Zod validation.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The scheduler uses a self-rescheduling `setTimer` rather than `setInterval` because `TimersLike` only models one-shot timers. Each tick checks `this.running` before taking a sample, which lets a stop() that runs between callback dispatch and execution avoid emitting a stale sample. FIFO eviction uses `splice(0, n)` so the oldest samples drop out when `maxSamples` is exceeded.
|
||||
Reference in New Issue
Block a user