Chore: better stat tracking

This commit is contained in:
SukkaW
2026-09-02 15:23:12 +08:00
parent 3c5c5ac4bd
commit 3e03018bbe
28 changed files with 933 additions and 187 deletions

View File

@@ -1,3 +1,4 @@
import { SpanCategory } from '../../trace';
import type { Span } from '../../trace';
import { HostnameSmolTrie } from 'hntrie/smol';
import { not, nullthrow } from 'foxts/guard';
@@ -68,10 +69,15 @@ export class FileOutput {
return this;
};
protected readonly span: Span;
/**
* The `RuleOutput#id` span is only opened by write(): between construction and
* write() this object merely accumulates sources, and that time already belongs
* to the sibling spans doing the downloading / reading.
*/
protected readonly parentSpan: Span;
constructor($span: Span, protected readonly id: string) {
this.span = $span.traceChild('RuleOutput#' + id);
this.parentSpan = $span;
}
protected title: string | null = null;
@@ -463,10 +469,12 @@ export class FileOutput {
}
write(): Promise<unknown> {
return this.span.traceChildAsync('write all', async (childSpan) => {
await childSpan.traceChildAsync('done', () => this.done());
return this.parentSpan.traceChildAsync('RuleOutput#' + this.id, async (childSpan) => {
// pendingPromise is the (untraced) reading + parsing of every source added
// via addFromRuleset / addFromDomainset, so this is waiting on fs + compute
await childSpan.traceChildAsync('done', () => this.done(), SpanCategory.Wait);
const domains = childSpan.traceChildSync('dump domain trie', () => this.dumpDomains());
const domains = childSpan.traceChildSync('dump domain trie', () => this.dumpDomains(), SpanCategory.Compute);
const title = nullthrow(this.title, 'Missing title');
const descriptions = nullthrow(this.description, 'Missing description');
@@ -505,7 +513,7 @@ export class FileOutput {
);
}
childSpan.traceChildSync('write to strategies', () => this.writeToStrategies(domains));
childSpan.traceChildSync('write to strategies', () => this.writeToStrategies(domains), SpanCategory.Compute);
return childSpan.traceChildAsync('output to disk', (childSpan) => {
const promises: Array<Promise<void>> = [];
@@ -521,7 +529,8 @@ export class FileOutput {
isMainThread
? strategy.output(childSpan, title, descriptions, this.date, filePath)
: strategy.outputInWorker(childSpan, title, descriptions, this.date, filePath)
))
// self time here is banner + content hash; compare / writing are traced as children
), SpanCategory.Compute)
);
}

View File

@@ -1,4 +1,4 @@
import { workerJob } from '../../trace';
import { SpanCategory, workerJob } from '../../trace';
import type { RawSpan, WorkerJobResult } from '../../trace';
import { resolveStrategyOutputPath, reviveStrategy, writeDataToStrategies } from './strategy-write-data';
import type { OutputWorkerPayload } from './strategy-write-data';
@@ -15,7 +15,7 @@ export function writeOutput(rawSpan: RawSpan | undefined, payload: OutputWorkerP
return workerJob(rawSpan, (span) => {
const strategies = payload.strategies.map(reviveStrategy);
span.traceChildSync('write to strategies', () => writeDataToStrategies(payload.data, strategies));
span.traceChildSync('write to strategies', () => writeDataToStrategies(payload.data, strategies), SpanCategory.Compute);
const date = new Date(payload.dateMs);
@@ -29,7 +29,9 @@ export function writeOutput(rawSpan: RawSpan | undefined, payload: OutputWorkerP
// eslint-disable-next-line no-await-in-loop -- see above
await childSpan.traceChildAsync(
'write ' + strategy.name,
(strategySpan) => strategy.outputInWorker(strategySpan, payload.title, payload.description, date, filePath)
(strategySpan) => strategy.outputInWorker(strategySpan, payload.title, payload.description, date, filePath),
// self time here is banner + content hash; compare / writing are traced as children
SpanCategory.Compute
);
}
});