typescript-perf 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +5 -1
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +5 -0
- package/dist/detect.d.ts +2 -0
- package/dist/detect.js +36 -7
- package/dist/html.js +5 -2
- package/dist/markdown.js +24 -0
- package/dist/report.js +3 -1
- package/dist/ts7.d.ts +32 -1
- package/dist/ts7.js +70 -8
- package/dist/types.d.ts +2 -0
- package/docs/schema.md +2 -2
- package/package.json +1 -1
- package/schema/typescript-perf-v1.schema.json +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
All notable changes to typescript-perf. The JSON output follows its own schema version (`typescript-perf/v1`, see
|
|
4
4
|
[docs/schema.md](docs/schema.md)).
|
|
5
5
|
|
|
6
|
+
## [0.2.1] - 2026-11-15
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- `--tsc` and `--tsc7` given as `node_modules/.bin/tsc` reported the wrong version (for example "is 1.0.0"): the
|
|
11
|
+
symlink was not resolved, and the version was read from whatever package.json sat above `node_modules`. The version
|
|
12
|
+
now comes from the compiler itself (`tsc -v`), with the package.json of the real file as a fallback.
|
|
13
|
+
- `ts7` credited parallel checking with part of the speed-up even when it brought nothing (on a 2-CPU machine,
|
|
14
|
+
single-threaded was faster than the default). The split is now computed from the measurements: the parallelism
|
|
15
|
+
factor (single-threaded / default) is reported only when the run ranges do not overlap. Otherwise the summary says
|
|
16
|
+
that all of the gain comes from the native compiler, with the number of CPUs, and whether parallel checking is
|
|
17
|
+
neutral or slower. A `--checkers` value clearly faster than the default is reported with its time.
|
|
18
|
+
- `ts7` gave no warning when a condition's runs were widely spread (40.91% for the TypeScript 7 default on a busy
|
|
19
|
+
machine). Above a 10% spread (documented in the README), a warning names the condition, gives its spread and range,
|
|
20
|
+
and advises more runs than were made (`--runs 10`, or twice the runs already made) or closing other
|
|
21
|
+
applications. It appears in the summary, in `ts7.warnings` in the JSON, and
|
|
22
|
+
in the terminal, Markdown and HTML outputs.
|
|
23
|
+
- `ts7 --markdown` printed an empty comment. It now has a table per condition (check time median, min, max, spread,
|
|
24
|
+
total time, memory), the warnings, the summary, the tsconfig options to change and the new errors.
|
|
25
|
+
|
|
6
26
|
## [0.2.0] - 2026-11-14
|
|
7
27
|
|
|
8
28
|
First release meant for CI. The project was called `typecost` up to 0.1. It is now `typescript-perf`, with the commands `typescript-perf` and `tsperf`, the schema `typescript-perf/v1` and the config file `typescript-perf.config.ts`.
|
package/README.md
CHANGED
|
@@ -304,7 +304,7 @@ jobs:
|
|
|
304
304
|
- uses: actions/setup-node@v4
|
|
305
305
|
with: { node-version: 22, cache: npm }
|
|
306
306
|
- run: npm ci
|
|
307
|
-
- uses: MartinFerret/typescript-perf@v0.2.
|
|
307
|
+
- uses: MartinFerret/typescript-perf@v0.2.1
|
|
308
308
|
with:
|
|
309
309
|
fail-on: instantiations:5%
|
|
310
310
|
```
|
|
@@ -353,6 +353,10 @@ is 1% there. Check time depends on the runner, so give it a generous margin or l
|
|
|
353
353
|
|
|
354
354
|
- **Median, range and noise.** Each number is the median of N runs after a discarded warm-up run. The range is the
|
|
355
355
|
min and max over those runs. A difference counts only when it is larger than the range on both sides.
|
|
356
|
+
- **Noise warning.** The spread of a condition is (max − min) / median of its check times. Above **10%**, `ts7`
|
|
357
|
+
warns, naming the condition and its spread, in every output (terminal, JSON `ts7.warnings`, Markdown, HTML): its
|
|
358
|
+
median is then less reliable. Run more times (it suggests `--runs 10`, or twice the runs already made) and close
|
|
359
|
+
other applications.
|
|
356
360
|
- **Check time** comes from the compiler's own `--extendedDiagnostics`. TypeScript 5/6 print it in 10 ms steps. On
|
|
357
361
|
TypeScript 7 it is wall time while several checkers run in parallel, so trace times, summed over checkers, can be
|
|
358
362
|
larger than the check time.
|
package/dist/constants.d.ts
CHANGED
|
@@ -20,3 +20,8 @@ export declare const SPEED: {
|
|
|
20
20
|
readonly fastMs: 2000;
|
|
21
21
|
readonly slowMs: 10000;
|
|
22
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* Check-time spread (max − min, in percent of the median) above which a measured
|
|
25
|
+
* condition is flagged: its median is then less reliable. Documented in the README.
|
|
26
|
+
*/
|
|
27
|
+
export declare const NOISE_WARN_PCT = 10;
|
package/dist/constants.js
CHANGED
|
@@ -30,3 +30,8 @@ export const TS7_COUNTER_TOLERANCE_PCT = 1;
|
|
|
30
30
|
* start working around it (skipping CI checks, waiting on the editor).
|
|
31
31
|
*/
|
|
32
32
|
export const SPEED = { fastMs: 2000, slowMs: 10000 };
|
|
33
|
+
/**
|
|
34
|
+
* Check-time spread (max − min, in percent of the median) above which a measured
|
|
35
|
+
* condition is flagged: its median is then less reliable. Documented in the README.
|
|
36
|
+
*/
|
|
37
|
+
export const NOISE_WARN_PCT = 10;
|
package/dist/detect.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export declare function aliasedCompilers(cwd: string): {
|
|
|
11
11
|
}[];
|
|
12
12
|
/** Every installed compiler: the project's own, and a TypeScript 7 if one is installed next to it. */
|
|
13
13
|
export declare function findCompilers(cwd: string): CompilerInfo[];
|
|
14
|
+
/** "Version 7.0.2" from `tsc -v`, or undefined if the binary does not answer. */
|
|
15
|
+
export declare function versionFromCli(bin: string): string | undefined;
|
|
14
16
|
/** Flags this compiler supports, from its own `--help --all`. */
|
|
15
17
|
export declare function capabilities(c: CompilerInfo, cwd: string): Promise<CompilerCapabilities>;
|
|
16
18
|
/** Resolve the tsconfig to measure: --project, or tsconfig.json in cwd. */
|
package/dist/detect.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { parseHelpFlags } from "./parse.js";
|
|
6
|
-
import { run } from "./runner.js";
|
|
7
|
+
import { isNodeScript, run } from "./runner.js";
|
|
7
8
|
/** Find the TypeScript compiler the project itself uses, so we measure what the team actually runs. */
|
|
8
9
|
export function detectCompiler(cwd, explicitBin) {
|
|
9
10
|
if (explicitBin)
|
|
@@ -88,20 +89,48 @@ export function findCompilers(cwd) {
|
|
|
88
89
|
found.push(a.compiler);
|
|
89
90
|
return found;
|
|
90
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* A compiler given by path (--tsc, --tsc7). The version comes from the compiler
|
|
94
|
+
* itself (`tsc -v`). Only if that fails is it read from the package.json above
|
|
95
|
+
* the real file: node_modules/.bin/tsc is a symlink, and walking up from the
|
|
96
|
+
* link would find an unrelated package.json.
|
|
97
|
+
*/
|
|
91
98
|
function fromBin(bin) {
|
|
92
99
|
if (!existsSync(bin))
|
|
93
100
|
throw new Error(`Compiler not found: ${bin}`);
|
|
94
|
-
|
|
101
|
+
const real = realpathSync(bin);
|
|
102
|
+
const version = versionFromCli(real) ?? versionFromPackage(real) ?? "unknown";
|
|
103
|
+
return info(real, version, "explicit");
|
|
104
|
+
}
|
|
105
|
+
/** "Version 7.0.2" from `tsc -v`, or undefined if the binary does not answer. */
|
|
106
|
+
export function versionFromCli(bin) {
|
|
107
|
+
try {
|
|
108
|
+
const [cmd, args] = isNodeScript(bin) ? [process.execPath, [bin, "-v"]] : [bin, ["-v"]];
|
|
109
|
+
const out = execFileSync(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 30_000, env: { ...process.env, NO_COLOR: "1" } });
|
|
110
|
+
return out.match(/Version\s+(\d+\.\d+\.\d+[^\s]*)/)?.[1];
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Version of the nearest package.json above the (real) compiler file that names a compiler package. */
|
|
117
|
+
function versionFromPackage(realBin) {
|
|
118
|
+
let dir = path.dirname(realBin);
|
|
95
119
|
while (dir !== path.dirname(dir)) {
|
|
96
120
|
const p = path.join(dir, "package.json");
|
|
97
121
|
if (existsSync(p)) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
122
|
+
try {
|
|
123
|
+
const meta = JSON.parse(readFileSync(p, "utf8"));
|
|
124
|
+
if (meta.version && (meta.name === "typescript" || meta.name === "@typescript/native-preview"))
|
|
125
|
+
return meta.version;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
/* unreadable package.json: keep looking */
|
|
129
|
+
}
|
|
101
130
|
}
|
|
102
131
|
dir = path.dirname(dir);
|
|
103
132
|
}
|
|
104
|
-
return
|
|
133
|
+
return undefined;
|
|
105
134
|
}
|
|
106
135
|
function info(bin, version, source) {
|
|
107
136
|
const major = Number(version.split(".")[0]) || 0;
|
package/dist/html.js
CHANGED
|
@@ -419,11 +419,14 @@ function ts7Body(r) {
|
|
|
419
419
|
for (const c of t.checkers ?? [])
|
|
420
420
|
cols.push({ label: `7, --checkers ${c.value}`, value: c.checkTimeMs.median, display: time(c.checkTimeMs.median), tone: "accent", note: !fromBlocked && c.checkTimeMs.median ? `${Math.round((a / c.checkTimeMs.median) * 10) / 10}×` : "" });
|
|
421
421
|
const list = (title, items, tone) => items.length ? `<section><div class="section-head"><h2>${esc(title)}</h2><span class="count ${tone}">${items.length}</span></div><ul class="plain">${items.map((i) => `<li>${rich(i)}</li>`).join("")}</ul></section>` : "";
|
|
422
|
-
|
|
422
|
+
const warn = (t.warnings ?? []).length
|
|
423
|
+
? `<section class="banner warn"><div class="banner-title">${ICON.dot} Noisy measurements</div>${(t.warnings ?? []).map((w) => `<p class="reason">${esc(w.replace(/^Warning: (.)/, (_m, c) => c.toUpperCase()))}</p>`).join("")}</section>`
|
|
424
|
+
: "";
|
|
425
|
+
return `${hero}${warn}${cols.length ? `<section><div class="section-head"><h2>Check time</h2></div>${columns(cols)}</section>` : ""}
|
|
423
426
|
${list("tsconfig options to change", t.config.removed, "bad")}
|
|
424
427
|
${list("New errors with TypeScript 7", t.diagnostics.added.map((d) => d.split("\n")[0]), "bad")}
|
|
425
428
|
${list(`Deprecated in TypeScript ${t.from.compiler.version}`, t.config.deprecated, "warn")}
|
|
426
|
-
<section><div class="section-head"><h2>Summary</h2></div><ul class="plain">${t.summary.map((s) => `<li>${rich(s)}</li>`).join("")}</ul></section>`;
|
|
429
|
+
<section><div class="section-head"><h2>Summary</h2></div><ul class="plain">${t.summary.filter((s) => !(t.warnings ?? []).includes(s)).map((s) => `<li>${rich(s)}</li>`).join("")}</ul></section>`;
|
|
427
430
|
}
|
|
428
431
|
/* -------------------------------------------------------------------- page */
|
|
429
432
|
const CSS = `
|
package/dist/markdown.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mb, num, rangeNum, rangeTime, time } from "./format.js";
|
|
2
|
+
import { spreadPct } from "./stats.js";
|
|
2
3
|
/* Markdown for pull-request comments. The first line is a stable marker, so
|
|
3
4
|
the GitHub Action can find and update its own comment. */
|
|
4
5
|
/** PR-comment ready: summary table, top deltas, budget status. */
|
|
@@ -43,6 +44,29 @@ export function renderMarkdown(r) {
|
|
|
43
44
|
if (m.total.instantiations)
|
|
44
45
|
out.push(`| Instantiations | ${num(m.total.instantiations.median)} | ${rangeNum(m.total.instantiations) || "1 run"} |`);
|
|
45
46
|
}
|
|
47
|
+
if (r.ts7) {
|
|
48
|
+
const t = r.ts7;
|
|
49
|
+
out.push("", `TypeScript ${t.from.compiler.version} vs ${t.to.compiler.version}, median of ${t.from.measurement.runs} run${t.from.measurement.runs === 1 ? "" : "s"} each.`, "");
|
|
50
|
+
out.push("| Condition | Check time | Min | Max | Spread | Total time | Memory |", "|---|---:|---:|---:|---:|---:|---:|");
|
|
51
|
+
const row = (label, check, total, memory, blocked = false) => out.push(blocked
|
|
52
|
+
? `| ${label} | did not type-check | | | | | |`
|
|
53
|
+
: `| ${label} | **${time(check.median)}** | ${time(check.min)} | ${time(check.max)} | ${spreadPct(check)}% | ${total ? time(total.median) : ""} | ${memory ? mb(memory.median) : ""} |`);
|
|
54
|
+
const m = (x) => [x.total.checkTimeMs, x.total.totalTimeMs, x.total.memoryMB, x.warnings.length > 0];
|
|
55
|
+
row(`TypeScript ${t.from.compiler.version}`, ...m(t.from.measurement));
|
|
56
|
+
row(`TypeScript ${t.to.compiler.version} (default)`, ...m(t.to.measurement));
|
|
57
|
+
if (t.singleThreaded)
|
|
58
|
+
row(`TypeScript ${t.to.compiler.version} single-threaded`, ...m(t.singleThreaded));
|
|
59
|
+
for (const c of t.checkers ?? [])
|
|
60
|
+
row(`TypeScript ${t.to.compiler.version} --checkers ${c.value}`, c.checkTimeMs, c.totalTimeMs);
|
|
61
|
+
if (t.warnings?.length)
|
|
62
|
+
out.push("", "> [!WARNING]", ...t.warnings.map((w) => `> - ${w.replace(/^Warning: (.)/, (_m, c) => c.toUpperCase())}`));
|
|
63
|
+
const summary = t.summary.filter((s) => !t.warnings?.includes(s));
|
|
64
|
+
out.push("", "**Summary**", "", ...summary.map((s) => `- ${s}`));
|
|
65
|
+
if (t.config.removed.length)
|
|
66
|
+
out.push("", "**tsconfig options TypeScript 7 rejects**", "", ...t.config.removed.map((o) => `- ${o}`));
|
|
67
|
+
if (t.diagnostics.added.length)
|
|
68
|
+
out.push("", "**New errors with TypeScript 7**", "", ...t.diagnostics.added.slice(0, 20).map((d) => `- \`${d.split("\n")[0]}\``));
|
|
69
|
+
}
|
|
46
70
|
if (r.findings?.length) {
|
|
47
71
|
out.push("", "**Findings**", "");
|
|
48
72
|
for (const f of r.findings)
|
package/dist/report.js
CHANGED
|
@@ -338,8 +338,10 @@ function renderTs7(r) {
|
|
|
338
338
|
for (const d of t.diagnostics.removed.slice(0, 10))
|
|
339
339
|
out.push(` ${green("−")} ${d.split("\n")[0]}`);
|
|
340
340
|
}
|
|
341
|
+
for (const w of t.warnings ?? [])
|
|
342
|
+
out.push("", ...wrapText(`${badge("WARNING", yellow)} ${w.replace(/^Warning: (.)/, (_m, c) => c.toUpperCase())}`, W() - 4, " ").map((l, i) => (i === 0 ? ` ${l}` : l)));
|
|
341
343
|
out.push("", title("Summary"));
|
|
342
|
-
for (const s of t.summary)
|
|
344
|
+
for (const s of t.summary.filter((x) => !(t.warnings ?? []).includes(x)))
|
|
343
345
|
out.push(...wrapText(`${cyan("•")} ${s}`, W() - 4, " ").map((l, i) => (i === 0 ? ` ${l}` : l)));
|
|
344
346
|
return out;
|
|
345
347
|
}
|
package/dist/ts7.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CompilerInfo, Ts7Report } from "./types.js";
|
|
1
|
+
import type { CompilerInfo, Stat, Ts7Report } from "./types.js";
|
|
2
2
|
export interface Ts7Options {
|
|
3
3
|
/** The project's current compiler (TypeScript 5 or 6). */
|
|
4
4
|
from: CompilerInfo;
|
|
@@ -16,3 +16,34 @@ export interface Ts7Options {
|
|
|
16
16
|
* the flag), diagnostics, and the tsconfig options each compiler complains about.
|
|
17
17
|
*/
|
|
18
18
|
export declare function ts7Report(o: Ts7Options): Promise<Ts7Report>;
|
|
19
|
+
export interface ParallelismInput {
|
|
20
|
+
/** Check time of the current compiler. */
|
|
21
|
+
from: Stat;
|
|
22
|
+
/** TypeScript 7 with its default settings. */
|
|
23
|
+
to: Stat;
|
|
24
|
+
/** TypeScript 7 with --singleThreaded, when the compiler supports it. */
|
|
25
|
+
single?: Stat;
|
|
26
|
+
/** TypeScript 7 with each --checkers value tried. */
|
|
27
|
+
checkers?: {
|
|
28
|
+
value: number;
|
|
29
|
+
checkTimeMs: Stat;
|
|
30
|
+
}[];
|
|
31
|
+
cpus: number;
|
|
32
|
+
fromVersion: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* How much of the TypeScript 7 speed-up comes from the native compiler and how
|
|
36
|
+
* much from parallel checking, computed from the measurements. A difference
|
|
37
|
+
* counts only when the run ranges do not overlap (the same noise rule as
|
|
38
|
+
* everywhere else), so "parallel checking helps" is never assumed.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parallelismSummary(p: ParallelismInput): string[];
|
|
41
|
+
/**
|
|
42
|
+
* One warning per measured condition whose check-time spread is above the
|
|
43
|
+
* threshold, naming the condition and its spread, with what to do about it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function spreadWarnings(conditions: {
|
|
46
|
+
label: string;
|
|
47
|
+
checkTimeMs: Stat;
|
|
48
|
+
skip?: boolean;
|
|
49
|
+
}[], thresholdPct?: number): string[];
|
package/dist/ts7.js
CHANGED
|
@@ -2,7 +2,8 @@ import os from "node:os";
|
|
|
2
2
|
import { capabilities, showConfig } from "./detect.js";
|
|
3
3
|
import { measure } from "./measure.js";
|
|
4
4
|
import { configDiagnostics } from "./parse.js";
|
|
5
|
-
import {
|
|
5
|
+
import { NOISE_WARN_PCT } from "./constants.js";
|
|
6
|
+
import { clearlyLower, fmtPct, round, spreadPct } from "./stats.js";
|
|
6
7
|
const mem = (n) => (n >= 1024 ? `${round(n / 1024, 1)} GB` : `${Math.round(n)} MB`);
|
|
7
8
|
const ms = (n) => (n >= 1000 ? `${round(n / 1000, 2)} s` : `${round(n)} ms`);
|
|
8
9
|
/** Strip what legitimately differs between compilers (nothing for now) so the diff shows real changes. */
|
|
@@ -62,14 +63,17 @@ export async function ts7Report(o) {
|
|
|
62
63
|
/* no speed or memory comparison: one side did not type-check */
|
|
63
64
|
}
|
|
64
65
|
else if (b > 0)
|
|
65
|
-
summary.push(`Check time: ${ms(a)} → ${ms(b)} (${round(a / b, 1)}× faster with TypeScript ${o.to.version}, median of ${runs} runs).`);
|
|
66
|
-
if (!blocked &&
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
summary.push(`Check time: ${ms(a)} → ${ms(b)} (${round(a / b, 1)}× faster with TypeScript ${o.to.version}, median of ${runs} run${runs === 1 ? "" : "s"}).`);
|
|
67
|
+
if (!blocked && b > 0) {
|
|
68
|
+
summary.push(...parallelismSummary({
|
|
69
|
+
from: fromM.total.checkTimeMs,
|
|
70
|
+
to: toM.total.checkTimeMs,
|
|
71
|
+
single: single && !single.warnings.length ? single.total.checkTimeMs : undefined,
|
|
72
|
+
checkers,
|
|
73
|
+
cpus: os.cpus().length,
|
|
74
|
+
fromVersion: o.from.version,
|
|
75
|
+
}));
|
|
69
76
|
}
|
|
70
|
-
const best = checkers?.slice().sort((x, y) => x.checkTimeMs.median - y.checkTimeMs.median)[0];
|
|
71
|
-
if (!blocked && best && best.checkTimeMs.max < toM.total.checkTimeMs.min)
|
|
72
|
-
summary.push(`--checkers ${best.value} was faster than the default on this machine (${ms(best.checkTimeMs.median)}).`);
|
|
73
77
|
const fm = fromM.total.memoryMB?.median;
|
|
74
78
|
const tm = toM.total.memoryMB?.median;
|
|
75
79
|
if (!blocked && fm && tm)
|
|
@@ -82,6 +86,13 @@ export async function ts7Report(o) {
|
|
|
82
86
|
summary.push("No new errors with TypeScript 7.");
|
|
83
87
|
if (removed.length)
|
|
84
88
|
summary.push(`${removed.length} error${removed.length > 1 ? "s" : ""} reported by TypeScript ${o.from.version} no longer appear${removed.length > 1 ? "" : "s"} with 7.`);
|
|
89
|
+
const warnings = spreadWarnings([
|
|
90
|
+
{ label: `TypeScript ${o.from.version}`, checkTimeMs: fromM.total.checkTimeMs, skip: fromBlocked },
|
|
91
|
+
{ label: `TypeScript ${o.to.version} (default)`, checkTimeMs: toM.total.checkTimeMs, skip: toBlocked },
|
|
92
|
+
...(single ? [{ label: `TypeScript ${o.to.version} single-threaded`, checkTimeMs: single.total.checkTimeMs, skip: single.warnings.length > 0 }] : []),
|
|
93
|
+
...(checkers ?? []).map((c) => ({ label: `TypeScript ${o.to.version} --checkers ${c.value}`, checkTimeMs: c.checkTimeMs })),
|
|
94
|
+
]);
|
|
95
|
+
summary.push(...warnings);
|
|
85
96
|
if (fromM.stability.counters === "identical" && toM.stability.counters === "varies")
|
|
86
97
|
summary.push(`TypeScript 7's counters varied between runs (up to ${fmtPct(toM.stability.counterSpreadPct)}): use a tolerance in budgets.`);
|
|
87
98
|
return {
|
|
@@ -92,5 +103,56 @@ export async function ts7Report(o) {
|
|
|
92
103
|
diagnostics: { added, removed },
|
|
93
104
|
config: { deprecated, removed: gone },
|
|
94
105
|
summary,
|
|
106
|
+
warnings,
|
|
95
107
|
};
|
|
96
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* How much of the TypeScript 7 speed-up comes from the native compiler and how
|
|
111
|
+
* much from parallel checking, computed from the measurements. A difference
|
|
112
|
+
* counts only when the run ranges do not overlap (the same noise rule as
|
|
113
|
+
* everywhere else), so "parallel checking helps" is never assumed.
|
|
114
|
+
*/
|
|
115
|
+
export function parallelismSummary(p) {
|
|
116
|
+
const out = [];
|
|
117
|
+
const a = p.from.median;
|
|
118
|
+
const b = p.to.median;
|
|
119
|
+
const cpus = `${p.cpus} CPU${p.cpus === 1 ? "" : "s"}`;
|
|
120
|
+
if (p.single && p.single.median > 0 && b > 0) {
|
|
121
|
+
const s = p.single.median;
|
|
122
|
+
const native = round(a / s, 1);
|
|
123
|
+
const parallel = round(s / b, 2);
|
|
124
|
+
if (clearlyLower(p.to, p.single)) {
|
|
125
|
+
out.push(`Single-threaded: ${ms(s)}. The native compiler alone is ${native}× faster, and parallel checking adds ${round(s / b, 1)}× on this machine (${cpus}).`);
|
|
126
|
+
}
|
|
127
|
+
else if (clearlyLower(p.single, p.to)) {
|
|
128
|
+
out.push(`Single-threaded: ${ms(s)}, default: ${ms(b)}. All of the gain comes from the native compiler (${native}×): on this machine (${cpus}), parallel checking by default is slower than one thread (factor ${parallel}).`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
out.push(`Single-threaded: ${ms(s)}, default: ${ms(b)}. All of the gain comes from the native compiler (${native}×): on this machine (${cpus}), parallel checking by default brings nothing measurable (factor ${parallel}, within the run-to-run spread).`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const best = p.checkers?.slice().sort((x, y) => x.checkTimeMs.median - y.checkTimeMs.median)[0];
|
|
135
|
+
if (best && clearlyLower(best.checkTimeMs, p.to)) {
|
|
136
|
+
out.push(`--checkers ${best.value} is faster than the default on this machine: ${ms(best.checkTimeMs.median)} instead of ${ms(b)} (${round(a / best.checkTimeMs.median, 1)}× faster than TypeScript ${p.fromVersion}).`);
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* One warning per measured condition whose check-time spread is above the
|
|
142
|
+
* threshold, naming the condition and its spread, with what to do about it.
|
|
143
|
+
*/
|
|
144
|
+
export function spreadWarnings(conditions, thresholdPct = NOISE_WARN_PCT) {
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const c of conditions) {
|
|
147
|
+
if (c.skip || c.checkTimeMs.values.length < 2)
|
|
148
|
+
continue;
|
|
149
|
+
const spread = spreadPct(c.checkTimeMs);
|
|
150
|
+
if (spread <= thresholdPct)
|
|
151
|
+
continue;
|
|
152
|
+
// Suggest more runs than were made: --runs 10 means nothing to someone who already ran 10.
|
|
153
|
+
const runs = c.checkTimeMs.values.length;
|
|
154
|
+
const more = Math.max(10, runs * 2);
|
|
155
|
+
out.push(`Warning: check times of ${c.label} are spread by ${spread}% (${ms(c.checkTimeMs.min)} to ${ms(c.checkTimeMs.max)} over ${runs} runs, above the ${thresholdPct}% threshold), so its median is less reliable. Run more times (--runs ${more}) and close other applications.`);
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -268,6 +268,8 @@ export interface Ts7Report {
|
|
|
268
268
|
removed: string[];
|
|
269
269
|
};
|
|
270
270
|
summary: string[];
|
|
271
|
+
/** Conditions whose check-time spread is above the noise threshold (also in the summary). */
|
|
272
|
+
warnings: string[];
|
|
271
273
|
}
|
|
272
274
|
export interface Environment {
|
|
273
275
|
node: string;
|
package/docs/schema.md
CHANGED
|
@@ -95,5 +95,5 @@ that were crossed).
|
|
|
95
95
|
|
|
96
96
|
`from` and `to` (`{ compiler, measurement }`), `singleThreaded` (when the compiler supports `--singleThreaded`),
|
|
97
97
|
`checkers` (`{ value, checkTimeMs, totalTimeMs? }[]`, when it supports `--checkers`), `diagnostics` (`{ added, removed }`,
|
|
98
|
-
excluding tsconfig errors), `config` (`{ deprecated, removed }`, from each compiler's own TS5xxx diagnostics)
|
|
99
|
-
(factual sentences).
|
|
98
|
+
excluding tsconfig errors), `config` (`{ deprecated, removed }`, from each compiler's own TS5xxx diagnostics), `summary`
|
|
99
|
+
(factual sentences) and `warnings` (conditions whose check-time spread is above 10%, also repeated in `summary`).
|
package/package.json
CHANGED
|
@@ -1102,6 +1102,13 @@
|
|
|
1102
1102
|
"items": {
|
|
1103
1103
|
"type": "string"
|
|
1104
1104
|
}
|
|
1105
|
+
},
|
|
1106
|
+
"warnings": {
|
|
1107
|
+
"type": "array",
|
|
1108
|
+
"items": {
|
|
1109
|
+
"type": "string"
|
|
1110
|
+
},
|
|
1111
|
+
"description": "Conditions whose check-time spread is above the noise threshold (10%)."
|
|
1105
1112
|
}
|
|
1106
1113
|
}
|
|
1107
1114
|
},
|