├── .github ├── CODEOWNERS ├── codeql │ └── codeql-configuration.yml └── dependabot.yml ├── scripts ├── src │ ├── __tests__ │ │ └── __file_snapshots__ │ │ │ └── setupPipeline │ │ │ ├── bun │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── baseline │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── default │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── faster │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ └── outputVariables.snap │ │ │ ├── full │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── public │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── regular │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── tsc-only │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ └── outputVariables.snap │ │ │ ├── vscode │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── startup-only │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ ├── matrix.snap │ │ │ └── outputVariables.snap │ │ │ ├── tsserver-only │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ ├── matrix.snap │ │ │ └── outputVariables.snap │ │ │ ├── faster commits= │ │ │ ├── compute.snap │ │ │ ├── matrix.snap │ │ │ ├── parameters.snap │ │ │ ├── outputVariables.snap │ │ │ └── error.snap │ │ │ ├── predictable=true │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── this is not a preset │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── hosts=bun@1.1.3,vscode@1.88.1 │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ └── parameters.snap │ │ │ ├── startup-only hosts=node@22.8.0 │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ ├── matrix.snap │ │ │ └── outputVariables.snap │ │ │ ├── faster predictable host=node@18.5.1 │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ └── outputVariables.snap │ │ │ ├── faster commits=release-5.3...release-5.4 │ │ │ ├── error.snap │ │ │ ├── compute.snap │ │ │ ├── parameters.snap │ │ │ └── outputVariables.snap │ │ │ └── faster commits=release-5.3..release-5.4 │ │ │ ├── compute.snap │ │ │ ├── matrix.snap │ │ │ ├── parameters.snap │ │ │ ├── outputVariables.snap │ │ │ └── error.snap │ ├── backfill │ │ ├── backfillLatestOnBranch.ts │ │ └── common.ts │ ├── checkLatestCommitForRef.ts │ ├── utils.ts │ └── buildTypeScript.ts ├── vitest.config.mjs ├── tsconfig.json └── package.json ├── ts-perf ├── packages │ ├── cli │ │ ├── bin │ │ │ └── ts-perf │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ │ └── index.ts │ ├── core │ │ ├── README.md │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── pathComparer.ts │ │ ├── tsconfig.json │ │ └── package.json │ ├── profiler │ │ ├── bin │ │ │ └── ts-profiler │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── commandLine.ts │ │ │ ├── commands │ │ │ │ ├── profiler.ts │ │ │ │ └── heapProfiler.ts │ │ │ └── executable.ts │ │ └── package.json │ ├── api │ │ ├── README.md │ │ ├── src │ │ │ ├── model │ │ │ │ ├── benchmarkHeader.ts │ │ │ │ ├── index.ts │ │ │ │ ├── measurementPivot.ts │ │ │ │ ├── tsserverconfig.ts │ │ │ │ ├── measurementComparisonPivot.ts │ │ │ │ ├── hostPattern.ts │ │ │ │ ├── benchmarkComparison.ts │ │ │ │ └── valueComparison.ts │ │ │ ├── index.ts │ │ │ ├── azure.ts │ │ │ ├── utils.ts │ │ │ └── utest.ts │ │ ├── tsconfig.json │ │ └── package.json │ ├── commands │ │ ├── README.md │ │ ├── src │ │ │ ├── benchmark │ │ │ │ ├── print │ │ │ │ │ ├── html │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── console │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── benchmark.ts │ │ │ │ │ ├── markdown │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── tsc.ts │ │ │ │ ├── startup.ts │ │ │ │ ├── tsserver.ts │ │ │ │ └── tscpublic.ts │ │ │ ├── analyze │ │ │ │ └── model │ │ │ │ │ └── profiler │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── nodeHierarchy.ts │ │ │ │ │ ├── nodeViewHierarchy.ts │ │ │ │ │ ├── bailoutView.ts │ │ │ │ │ ├── location.ts │ │ │ │ │ ├── event.ts │ │ │ │ │ ├── positionTickInfoView.ts │ │ │ │ │ ├── lineTick.ts │ │ │ │ │ ├── lineTickView.ts │ │ │ │ │ └── eventRangeView.ts │ │ │ ├── host │ │ │ │ ├── utils.ts │ │ │ │ ├── index.ts │ │ │ │ ├── configure.ts │ │ │ │ ├── install.ts │ │ │ │ └── uninstall.ts │ │ │ ├── scenario │ │ │ │ ├── local.ts │ │ │ │ ├── index.ts │ │ │ │ ├── add.ts │ │ │ │ ├── configure.ts │ │ │ │ ├── list.ts │ │ │ │ └── delete.ts │ │ │ ├── merge │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── package.json │ ├── events │ │ ├── README.md │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── src │ │ │ └── index.ts │ ├── inspector │ │ ├── tsconfig.json │ │ ├── README.md │ │ ├── src │ │ │ ├── schema.ts │ │ │ └── index.ts │ │ └── package.json │ ├── tsconfig.json │ └── tsconfig-base.json ├── bin │ ├── ts-profiler │ └── ts-perf ├── README.md └── package.json ├── pnpm-workspace.yaml ├── .vscode ├── extensions.json └── settings.template.json ├── ansible ├── .gitignore ├── reboot.yml ├── tasks │ ├── check_reboot.yml │ ├── pyperf.yml │ ├── packages.yml │ └── isolation.yml ├── update.yml ├── setup.yml └── README.md ├── .npmrc ├── cases ├── solutions │ ├── .gitignore │ ├── Compiler │ │ ├── tsconfig-base.json │ │ └── tsconfig.json │ └── Compiler-Unions │ │ └── tsconfig.json ├── scenarios │ ├── typescript-startup │ │ └── scenario.json │ ├── tsc-startup │ │ └── scenario.json │ ├── tsserverlibrary-startup │ │ └── scenario.json │ ├── tsserver-startup │ │ └── scenario.json │ ├── vscode │ │ ├── setup.sh │ │ └── scenario.json │ ├── self-build-src │ │ ├── scenario.json │ │ └── setup.sh │ ├── xstate-main-1 │ │ ├── setup.sh │ │ └── scenario.json │ ├── webpack │ │ ├── scenario.json │ │ └── setup.sh │ ├── xstate-main-1-tsserver │ │ ├── setup.sh │ │ └── scenario.json │ ├── mui-docs │ │ ├── scenario.json │ │ └── setup.sh │ ├── vscode-1 │ │ ├── scenario.json │ │ └── setup.sh │ ├── webpack-1 │ │ ├── scenario.json │ │ └── setup.sh │ ├── mui-docs-1 │ │ ├── scenario.json │ │ └── setup.sh │ ├── xstate-main │ │ ├── scenario.json │ │ └── setup.sh │ ├── angular-1 │ │ ├── setup.sh │ │ └── scenario.json │ ├── self-compiler │ │ ├── scenario.json │ │ └── setup.sh │ ├── Compiler │ │ └── scenario.json │ ├── self-build-src-public-api │ │ ├── scenario.json │ │ └── setup.sh │ ├── Compiler-Unions │ │ └── scenario.json │ ├── ts-pre-modules │ │ ├── scenario.json │ │ └── setup.sh │ ├── CompilerTSServer │ │ └── scenario.json │ └── Compiler-UnionsTSServer │ │ └── scenario.json └── sandbox │ └── proxy.Dockerfile ├── vitest.config.mjs ├── SUPPORT.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── package.json ├── .dprint.jsonc ├── SECURITY.md ├── README.md └── .gitignore /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jakebailey 2 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/bun/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/baseline/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/default/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/full/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/public/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/regular/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsc-only/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/vscode/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /ts-perf/packages/cli/bin/ts-perf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../dist'); 3 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsserver-only/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=/compute.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=/matrix.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/predictable=true/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /ts-perf/bin/ts-profiler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../packages/profiler/dist'); 3 | -------------------------------------------------------------------------------- /ts-perf/packages/core/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/core` 2 | 3 | Core utilties for `ts-perf`. 4 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/bin/ts-profiler: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../dist'); 3 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'scripts' 3 | - 'ts-perf' 4 | - 'ts-perf/packages/*' 5 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=/parameters.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/this is not a preset/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=/outputVariables.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /ts-perf/packages/api/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/api` 2 | 3 | Shared API and data model for `ts-perf`. 4 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/commands` 2 | 3 | Core commands for `ts-perf`. 4 | -------------------------------------------------------------------------------- /ts-perf/packages/events/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/events` 2 | 3 | Typed event subsystem for `ts-perf`. 4 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/hosts=bun@1.1.3,vscode@1.88.1/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only hosts=node@22.8.0/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /.github/codeql/codeql-configuration.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL Configuration 2 | 3 | paths-ignore: 4 | - cases/** 5 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster predictable host=node@18.5.1/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=/error.snap: -------------------------------------------------------------------------------- 1 | [Error: Expected value for commits] -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3...release-5.4/error.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3..release-5.4/compute.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3..release-5.4/matrix.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3..release-5.4/parameters.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/benchmarkHeader.ts: -------------------------------------------------------------------------------- 1 | export interface BenchmarkHeader { 2 | version: string; 3 | } 4 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3..release-5.4/outputVariables.snap: -------------------------------------------------------------------------------- 1 | undefined -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/print/html/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./benchmark"; 2 | export * from "./comparison"; 3 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/profiler` 2 | 3 | v8 CPU Profile and heap snapshot generator for `ts-perf`. 4 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/print/console/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./benchmark"; 2 | export * from "./comparison"; 3 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/print/markdown/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./benchmark"; 2 | export * from "./comparison"; 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "dprint.dprint" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /ansible/.gitignore: -------------------------------------------------------------------------------- 1 | # These should probably be stored separately, but just make sure we don't commit them. 2 | secrets.yml 3 | inventory.yml 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | use-lockfile-v6=true 2 | resolution-mode=highest 3 | auto-install-peers=true 4 | strict-peer-dependencies=false 5 | shell-emulator=true 6 | -------------------------------------------------------------------------------- /cases/solutions/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all directories; manually add new dirs as unignored if needed. 2 | /*/ 3 | !/Compiler 4 | !/Compiler-Unions 5 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3..release-5.4/error.snap: -------------------------------------------------------------------------------- 1 | [Error: Expected "..." in commits, not ".."] -------------------------------------------------------------------------------- /ansible/reboot.yml: -------------------------------------------------------------------------------- 1 | - name: Reboot 2 | hosts: tsperf 3 | 4 | tasks: 5 | - name: Reboot 6 | ansible.builtin.reboot: 7 | become: yes 8 | -------------------------------------------------------------------------------- /cases/scenarios/typescript-startup/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-startup", 3 | "kind": "startup", 4 | "args": [ 5 | "typescript.js" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /cases/scenarios/tsc-startup/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsc-startup", 3 | "kind": "startup", 4 | "args": [ 5 | "tsc.js", 6 | "--version" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /ts-perf/packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./pathComparer"; 2 | export * from "./stringComparer"; 3 | export * from "./sys"; 4 | export * from "./types"; 5 | export * from "./utils"; 6 | -------------------------------------------------------------------------------- /cases/scenarios/tsserverlibrary-startup/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsserverlibrary-startup", 3 | "kind": "startup", 4 | "args": [ 5 | "tsserverlibrary.js" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/bun/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "47m 42s", 3 | "perAgent": { 4 | "any": "3h 49m 24s", 5 | }, 6 | "total": "3h 49m 24s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/default/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "1h 58m 6s", 5 | }, 6 | "total": "1h 58m 6s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/full/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "4h 40m 32s", 5 | }, 6 | "total": "4h 40m 32s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/public/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/regular/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "7m 52s", 3 | "perAgent": { 4 | "any": "29m 22s", 5 | }, 6 | "total": "29m 22s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsc-only/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "1h 58m 6s", 5 | }, 6 | "total": "1h 58m 6s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsserver-only/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "5m 18s", 3 | "perAgent": { 4 | "any": "14m 58s", 5 | }, 6 | "total": "14m 58s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/vscode/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/predictable=true/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/this is not a preset/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "2h 42m 26s", 5 | }, 6 | "total": "2h 42m 26s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only hosts=node@22.8.0/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "7m 52s", 3 | "perAgent": { 4 | "any": "29m 22s", 5 | }, 6 | "total": "29m 22s", 7 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/hosts=bun@1.1.3,vscode@1.88.1/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "27m 5s", 3 | "perAgent": { 4 | "any": "5h 24m 52s", 5 | }, 6 | "total": "5h 24m 52s", 7 | } -------------------------------------------------------------------------------- /cases/scenarios/tsserver-startup/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsserver-startup", 3 | "kind": "startup", 4 | "args": [ 5 | "tsserver.js", 6 | "--disableAutomaticTypingAcquisition" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster predictable host=node@18.5.1/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "1h 58m 6s", 5 | }, 6 | "total": "1h 58m 6s", 7 | } -------------------------------------------------------------------------------- /ts-perf/packages/events/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3...release-5.4/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "26m 18s", 3 | "perAgent": { 4 | "any": "1h 58m 6s", 5 | }, 6 | "total": "1h 58m 6s", 7 | } -------------------------------------------------------------------------------- /scripts/vitest.config.mjs: -------------------------------------------------------------------------------- 1 | import { configDefaults, defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | exclude: [...configDefaults.exclude, "**/dist/**"], 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /cases/scenarios/vscode/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/vscode.git 9 | 10 | run_sandboxed sh -c 'npm ci --ignore-scripts' 11 | -------------------------------------------------------------------------------- /ts-perf/packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [] 9 | } 10 | -------------------------------------------------------------------------------- /cases/scenarios/self-build-src/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "self-build-src", 3 | "kind": "tsc", 4 | "args": [ 5 | "-b", 6 | "${suiteDirectory}/self-build-src/src" 7 | ], 8 | "platforms": [ 9 | "linux" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /ts-perf/README.md: -------------------------------------------------------------------------------- 1 | # TypeScript Performance Tool `ts-perf` 2 | 3 | `ts-perf` is a suite of performance testing tools designed for analyzing and benchmarking performance for the TypeScript compiler. 4 | 5 | See [packages/cli/README.md](packages/cli/README.md) for more info. 6 | -------------------------------------------------------------------------------- /vitest.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | projects: [ 6 | "scripts", 7 | // "ts-perf", 8 | // "ts-perf/packages/*", 9 | ], 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main-1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/statelyai/xstate.git 9118720b2d81cd3cd6b8e4ea8da75d576c47fa8d 9 | 10 | run_sandboxed sh -c 'yarn install' 11 | -------------------------------------------------------------------------------- /cases/scenarios/webpack/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/webpack", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main-1-tsserver/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/statelyai/xstate.git 9118720b2d81cd3cd6b8e4ea8da75d576c47fa8d 9 | 10 | run_sandboxed sh -c 'yarn install' 11 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/baseline/compute.snap: -------------------------------------------------------------------------------- 1 | { 2 | "parallel": "35m 47s", 3 | "perAgent": { 4 | "ts-perf1": "35m 47s", 5 | "ts-perf2": "35m 42s", 6 | "ts-perf3": "35m 18s", 7 | "ts-perf4": "33m 29s", 8 | }, 9 | "total": "2h 20m 16s", 10 | } -------------------------------------------------------------------------------- /ts-perf/packages/api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [ 9 | { "path": "../core" } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /cases/scenarios/vscode/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/vscode/src", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/mui-docs/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mui-docs", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/mui-docs/docs", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/vscode-1/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-1", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/vscode-1/src", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/webpack-1/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-1", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/webpack-1", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ansible/tasks/check_reboot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check if reboot required 3 | ansible.builtin.stat: 4 | path: /var/run/reboot-required 5 | register: reboot_required_file 6 | 7 | - name: Reboot if required 8 | when: reboot_required_file.stat.exists 9 | ansible.builtin.reboot: 10 | become: yes 11 | -------------------------------------------------------------------------------- /cases/scenarios/mui-docs-1/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mui-docs-1", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/mui-docs-1/docs", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xstate-main", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/xstate-main", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./commands"; 2 | export * from "./expansion"; 3 | export * from "./format"; 4 | export * from "./model"; 5 | export * from "./options"; 6 | export * from "./types"; 7 | export * from "./utils"; 8 | 9 | import * as fmt from "./format"; 10 | export { fmt }; 11 | -------------------------------------------------------------------------------- /cases/scenarios/angular-1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/angular/angular.git cc57d4c4998b4e38f940afdf358af37185028072 9 | 10 | run_sandboxed sh -c 'yarn install --ignore-scripts --ignore-engines' 11 | -------------------------------------------------------------------------------- /cases/scenarios/vscode-1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/vscode.git f88bce8fe6a6d2ccd27cbd64bb26853cd8779afa 9 | 10 | run_sandboxed sh -c 'yarn install --ignore-scripts --ignore-engines' 11 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main-1/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xstate-main-1", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/xstate-main-1", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/angular-1/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-1", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/angular-1/packages/tsconfig.json", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/self-compiler/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "self-compiler", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/self-compiler/src/compiler", 7 | "--outdir", 8 | "${outDirectory}" 9 | ], 10 | "platforms": [ 11 | "linux" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/Compiler/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Compiler", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/Compiler", 7 | "--target", 8 | "es5", 9 | "--module", 10 | "amd", 11 | "--outfile", 12 | "${outDirectory}/out.js" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /ts-perf/packages/inspector/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [ 9 | { "path": "../core" }, 10 | { "path": "../events" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [ 9 | { "path": "../core" }, 10 | { "path": "../inspector" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/baseline/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": false, 6 | "isCustomCommitRange": false, 7 | "newCommit": "", 8 | "newName": "", 9 | "predictable": undefined, 10 | "preset": "baseline", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/bun/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "bun", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/full/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "full", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/default/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "regular", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "faster", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/public/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "public", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/regular/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "regular", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/vscode/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "vscode", 11 | } -------------------------------------------------------------------------------- /cases/scenarios/mui-docs/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/mui/material-ui.git 9 | 10 | run_sandboxed sh -c 'npx $(node -e "console.log(JSON.parse(fs.readFileSync(\"package.json\", \"utf8\")).packageManager)") install --ignore-scripts' 11 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/predictable=true/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": true, 10 | "preset": "regular", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsc-only/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "tsc-only", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "startup-only", 11 | } -------------------------------------------------------------------------------- /.vscode/settings.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": true 4 | }, 5 | "[typescript][typescriptreact][javascript][javascriptreact][json][jsonc][yaml][github-actions-workflow][markdown]": { 6 | "editor.defaultFormatter": "dprint.dprint", 7 | "editor.formatOnSave": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/this is not a preset/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "regular", 11 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsserver-only/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": false, 7 | "newCommit": "HEAD", 8 | "newName": "pr", 9 | "predictable": undefined, 10 | "preset": "tsserver-only", 11 | } -------------------------------------------------------------------------------- /ansible/update.yml: -------------------------------------------------------------------------------- 1 | - name: Update 2 | hosts: tsperf 3 | 4 | tasks: 5 | - name: apt upgrade 6 | ansible.builtin.apt: 7 | upgrade: dist 8 | autoclean: yes 9 | autoremove: yes 10 | update_cache: yes 11 | become: yes 12 | 13 | - name: Check reboot 14 | ansible.builtin.import_tasks: tasks/check_reboot.yml 15 | -------------------------------------------------------------------------------- /cases/scenarios/self-build-src-public-api/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "self-build-src-public-api", 3 | "kind": "tsc", 4 | "args": [ 5 | "-b", 6 | "${suiteDirectory}/self-build-src-public-api/src" 7 | ], 8 | "platforms": [ 9 | "linux" 10 | ], 11 | "tscConfig": { 12 | "usePublicApi": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ts-perf/packages/cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [ 9 | { "path": "../api" }, 10 | { "path": "../commands" }, 11 | { "path": "../core" } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/Compiler-Unions/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Compiler-Unions", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/Compiler-Unions/tsconfig.json", 7 | "--target", 8 | "es5", 9 | "--module", 10 | "amd", 11 | "--outfile", 12 | "${outDirectory}/out.js" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": "src", 5 | "outDir": "dist" 6 | }, 7 | "include": ["src/**/*.ts"], 8 | "references": [ 9 | { "path": "../api" }, 10 | { "path": "../core" }, 11 | { "path": "../inspector" } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/statelyai/xstate.git 9 | 10 | run_sandboxed sh -c 'PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npx $(node -e "console.log(JSON.parse(fs.readFileSync(\"package.json\", \"utf8\")).packageManager)") install' 11 | -------------------------------------------------------------------------------- /cases/scenarios/ts-pre-modules/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-pre-modules", 3 | "kind": "tsc", 4 | "args": [ 5 | "-p", 6 | "${suiteDirectory}/ts-pre-modules/src/compiler", 7 | "--outfile", 8 | "${outDirectory}/out.js", 9 | "--composite", 10 | "false" 11 | ], 12 | "platforms": [ 13 | "linux" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /cases/scenarios/mui-docs-1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/mui/material-ui.git 48a29227cb737c6f008a62f9c8c4c47aedd99c43 9 | 10 | run_sandboxed sh -c 'npx $(node -e "console.log(JSON.parse(fs.readFileSync(\"package.json\", \"utf8\")).packageManager)") install --ignore-scripts' 11 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster predictable host=node@18.5.1/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": [ 5 | "node@18.5.1", 6 | ], 7 | "isComparison": true, 8 | "isCustomCommitRange": false, 9 | "newCommit": "HEAD", 10 | "newName": "pr", 11 | "predictable": true, 12 | "preset": "faster", 13 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only hosts=node@22.8.0/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": [ 5 | "node@22.8.0", 6 | ], 7 | "isComparison": true, 8 | "isCustomCommitRange": false, 9 | "newCommit": "HEAD", 10 | "newName": "pr", 11 | "predictable": undefined, 12 | "preset": "startup-only", 13 | } -------------------------------------------------------------------------------- /ts-perf/packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | export type ArgTypes = F extends (...args: infer A) => any ? A 2 | : any[]; 3 | 4 | export type MatchingKeys = [keyof TRecord] extends [infer K] 5 | ? K extends (TRecord[Extract] extends TMatch ? K : never) ? K : never 6 | : never; 7 | 8 | export type Mutable = { 9 | -readonly [P in keyof T]: T[P]; 10 | }; 11 | -------------------------------------------------------------------------------- /ts-perf/packages/inspector/README.md: -------------------------------------------------------------------------------- 1 | # `@ts-perf/inspector` 2 | 3 | v8 inspector subsystem for `ts-perf`. 4 | 5 | ## Notes 6 | 7 | - Information on the v8 inspector protocol can be found here: https://chromedevtools.github.io/debugger-protocol-viewer/v8/ 8 | - Information on the trace format used for Timelines can be found here: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit 9 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | ## Microsoft Support Policy 10 | 11 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 12 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/hosts=bun@1.1.3,vscode@1.88.1/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "HEAD^1", 3 | "baselineName": "baseline", 4 | "hosts": [ 5 | "bun@1.1.3", 6 | "vscode@1.88.1", 7 | ], 8 | "isComparison": true, 9 | "isCustomCommitRange": false, 10 | "newCommit": "HEAD", 11 | "newName": "pr", 12 | "predictable": undefined, 13 | "preset": "regular", 14 | } -------------------------------------------------------------------------------- /cases/scenarios/self-build-src/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/TypeScript.git $TYPESCRIPT_COMMIT 9 | 10 | run_sandboxed sh -c ' 11 | npm ci 12 | if test -f Herebyfile.mjs; then 13 | npx hereby generate-diagnostics 14 | else 15 | npx gulp generate-diagnostics 16 | fi 17 | ' 18 | -------------------------------------------------------------------------------- /cases/scenarios/self-compiler/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/TypeScript.git $TYPESCRIPT_COMMIT 9 | 10 | run_sandboxed sh -c ' 11 | npm ci 12 | if test -f Herebyfile.mjs; then 13 | npx hereby generate-diagnostics 14 | else 15 | npx gulp generate-diagnostics 16 | fi 17 | ' 18 | -------------------------------------------------------------------------------- /cases/scenarios/self-build-src-public-api/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/TypeScript.git $TYPESCRIPT_COMMIT 9 | 10 | run_sandboxed sh -c ' 11 | npm ci 12 | if test -f Herebyfile.mjs; then 13 | npx hereby generate-diagnostics 14 | else 15 | npx gulp generate-diagnostics 16 | fi 17 | ' 18 | -------------------------------------------------------------------------------- /ts-perf/packages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { "noEmit": true }, 3 | "files": [], 4 | "include": [], 5 | "exclude": [], 6 | "references": [ 7 | { "path": "./api" }, 8 | { "path": "./cli" }, 9 | { "path": "./commands" }, 10 | { "path": "./core" }, 11 | { "path": "./events" }, 12 | { "path": "./inspector" }, 13 | { "path": "./profiler" } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /cases/scenarios/ts-pre-modules/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/microsoft/TypeScript.git d83a5e1281379da54221fe39d5c0cb6ef4d1c109 9 | 10 | run_sandboxed sh -c ' 11 | npm ci 12 | if test -f Herebyfile.mjs; then 13 | npx hereby generate-diagnostics 14 | else 15 | npx gulp generate-diagnostics 16 | fi 17 | ' 18 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3...release-5.4/parameters.snap: -------------------------------------------------------------------------------- 1 | { 2 | "baselineCommit": "27047e3391323fa2d8987f46a4c42f5361d07926", 3 | "baselineName": "release-5.3", 4 | "hosts": undefined, 5 | "isComparison": true, 6 | "isCustomCommitRange": true, 7 | "newCommit": "6ea273cdcca99db809074d2b2d38d0e5b59ee81b", 8 | "newName": "release-5.4", 9 | "predictable": undefined, 10 | "preset": "faster", 11 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /ts-perf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-perf-monorepo", 3 | "version": "0.8.0", 4 | "private": true, 5 | "description": "TypeScript performance testing tool", 6 | "bin": { 7 | "ts-perf": "./packages/cli/bin/ts-perf" 8 | }, 9 | "author": "Microsoft Corp.", 10 | "license": "MIT", 11 | "engines": { 12 | "node": ">= 20.19.0 || >=22.12.0" 13 | }, 14 | "scripts": { 15 | "build": "tsc -b ./packages/tsconfig.json" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./category"; 2 | export * from "./context"; 3 | export * from "./event"; 4 | export * from "./eventRangesView"; 5 | export * from "./eventRangeView"; 6 | export * from "./events"; 7 | export * from "./node"; 8 | export * from "./nodeHierarchy"; 9 | export * from "./nodeView"; 10 | export * from "./nodeViewHierarchy"; 11 | export * from "./profile"; 12 | export * from "./profileAnalyzer"; 13 | export * from "./profileView"; 14 | -------------------------------------------------------------------------------- /ansible/tasks/pyperf.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install packages 3 | ansible.builtin.apt: 4 | pkg: 5 | - python3-venv 6 | - python3-pip 7 | become: yes 8 | 9 | - name: Install pyperf python package 10 | ansible.builtin.pip: 11 | name: pyperf 12 | become: yes 13 | 14 | - name: Allow any user to sudo pyperf 15 | ansible.builtin.copy: 16 | dest: /etc/sudoers.d/pyperf 17 | owner: root 18 | group: root 19 | content: 'ALL ALL=(ALL) NOPASSWD: /usr/local/bin/pyperf' 20 | validate: /usr/sbin/visudo -csf %s 21 | become: yes 22 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/tsc.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | 3 | import { benchmark } from "."; 4 | 5 | const command: Command = { 6 | commandName: "tsc", 7 | summary: "Benchmark tsc scenarios.", 8 | description: "Benchmark tsc scenarios.", 9 | include: ["compiler"], 10 | lock: true, 11 | update: true, 12 | exec: ({ options }, host) => benchmark({ kind: "tsc", options }, host), 13 | }; 14 | 15 | export function registerCommands(commands: CommandMap) { 16 | commands.tsc = command; 17 | } 18 | -------------------------------------------------------------------------------- /cases/solutions/Compiler/tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es5"], 4 | "noEmitOnError": false, 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "noUnusedLocals": true, 8 | "noUnusedParameters": true, 9 | "alwaysStrict": true, 10 | "pretty": true, 11 | "preserveConstEnums": true, 12 | "stripInternal": true, 13 | "sourceMap": true, 14 | "target": "es5", 15 | "newLine": "lf", 16 | "types": [] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ts-perf/bin/ts-perf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { spawn } = require("child_process"); 3 | const child = spawn(process.execPath, [require.resolve("../packages/cli/dist"), ...process.argv.slice(2)], { stdio: "inherit" }).on("exit", (code, signal) => { 4 | process.on("exit", () => { 5 | if (signal) { 6 | process.kill(process.pid, signal); 7 | } 8 | else { 9 | process.exit(code); 10 | } 11 | }); 12 | }); 13 | process.on("SIGINT", () => { 14 | child.kill("SIGINT"); 15 | child.kill("SIGTERM"); 16 | }); 17 | -------------------------------------------------------------------------------- /cases/scenarios/webpack/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/webpack/webpack.git 9 | 10 | run_sandboxed sh -c ' 11 | set -ex 12 | yarn install --ignore-scripts --ignore-engines 13 | 14 | # https://github.com/webpack/webpack/blob/228fc69f40c3e9ec6d99a5105fdc85b5bca4ce43/.github/workflows/test.yml#L135 15 | LINK_FOLDER=$PWD/node_modules/.yarn-link 16 | yarn link --link-folder $LINK_FOLDER 17 | yarn link --link-folder $LINK_FOLDER webpack 18 | ' 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: 'github-actions' 9 | directory: '/' 10 | schedule: 11 | interval: 'weekly' 12 | groups: 13 | github-actions: 14 | patterns: 15 | - '*' 16 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/startup.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | 3 | import { benchmark } from "."; 4 | 5 | const command: Command = { 6 | commandName: "startup", 7 | summary: "Benchmark startup scenarios.", 8 | description: "Benchmark startup scenarios.", 9 | include: ["startup"], 10 | lock: true, 11 | update: true, 12 | exec: ({ options }, host) => benchmark({ kind: "startup", options }, host), 13 | }; 14 | 15 | export function registerCommands(commands: CommandMap) { 16 | commands.startup = command; 17 | } 18 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/tsserver.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | 3 | import { benchmark } from "."; 4 | 5 | const command: Command = { 6 | commandName: "tsserver", 7 | summary: "Benchmark tsserver scenarios.", 8 | description: "Benchmark tsserver scenarios.", 9 | include: ["tsserver"], 10 | lock: true, 11 | update: true, 12 | exec: ({ options }, host) => benchmark({ kind: "tsserver", options }, host), 13 | }; 14 | 15 | export function registerCommands(commands: CommandMap) { 16 | commands.tsserver = command; 17 | } 18 | -------------------------------------------------------------------------------- /cases/scenarios/webpack-1/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exo pipefail 4 | cd "${0%/*}" 5 | 6 | source ../../common.sh 7 | 8 | clone_scenario https://github.com/webpack/webpack.git 228fc69f40c3e9ec6d99a5105fdc85b5bca4ce43 9 | 10 | run_sandboxed sh -c ' 11 | set -ex 12 | yarn install --ignore-scripts --ignore-engines 13 | 14 | # https://github.com/webpack/webpack/blob/228fc69f40c3e9ec6d99a5105fdc85b5bca4ce43/.github/workflows/test.yml#L135 15 | LINK_FOLDER=$PWD/node_modules/.yarn-link 16 | yarn link --link-folder $LINK_FOLDER 17 | yarn link --link-folder $LINK_FOLDER webpack 18 | ' 19 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2023"], 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "target": "es2023", 7 | "rootDir": "src", 8 | "outDir": "dist", 9 | "sourceMap": true, 10 | 11 | "strict": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "allowUnusedLabels": false, 15 | "noImplicitOverride": true, 16 | "noImplicitReturns": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /cases/sandbox/proxy.Dockerfile: -------------------------------------------------------------------------------- 1 | # Using the node image is overkill, but we're already going to pull it. 2 | ARG BASE_IMAGE= 3 | FROM ${BASE_IMAGE} 4 | 5 | RUN apt-get update && apt-get install -y tinyproxy 6 | 7 | RUN cat < /etc/tinyproxy/tinyproxy.conf 8 | Port 8888 9 | User nobody 10 | Group nogroup 11 | Timeout 600 12 | Filter "/etc/tinyproxy/filter" 13 | FilterDefaultDeny Yes 14 | LogLevel Notice 15 | EOF 16 | 17 | RUN cat < /etc/tinyproxy/filter 18 | ^registry\.npmjs\.org$ 19 | ^registry\.yarnpkg\.com$ 20 | ^codeload\.github\.com$ 21 | ^github\.com$ 22 | ^saucelabs\.com$ 23 | EOF 24 | 25 | CMD ["/usr/bin/tinyproxy", "-d"] 26 | -------------------------------------------------------------------------------- /ts-perf/packages/tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "NodeNext", 4 | "moduleResolution": "NodeNext", 5 | "target": "es2023", 6 | "lib": ["es2023"], 7 | "types": ["node"], 8 | "composite": true, 9 | "declaration": true, 10 | "declarationMap": true, 11 | "sourceMap": true, 12 | "strict": true, 13 | "noEmitOnError": true, 14 | "experimentalDecorators": true, 15 | "skipLibCheck": true, 16 | "allowSyntheticDefaultImports": true, 17 | "esModuleInterop": true, 18 | "useUnknownInCatchVariables": false, 19 | "noUnusedLocals": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/nodeHierarchy.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyProvider, Queryable } from "iterable-query"; 2 | 3 | import { CpuProfileNode } from "./node"; 4 | import { CpuProfile } from "./profile"; 5 | 6 | export class CpuProfileNodeHierarchy implements HierarchyProvider { 7 | public profile: CpuProfile; 8 | constructor(profile: CpuProfile) { 9 | this.profile = profile; 10 | } 11 | owns(node: CpuProfileNode): boolean { 12 | return node.profile === this.profile; 13 | } 14 | parent(node: CpuProfileNode): CpuProfileNode | undefined { 15 | return node.parent; 16 | } 17 | children(node: CpuProfileNode): Queryable | undefined { 18 | return node.children; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/nodeViewHierarchy.ts: -------------------------------------------------------------------------------- 1 | // import { HierarchyProvider, Queryable } from "iterable-query"; 2 | // import { CpuProfileNodeView } from "./nodeView"; 3 | // import { CpuProfileView } from "./profileView"; 4 | 5 | // export class CpuProfileNodeViewHierarchy implements HierarchyProvider { 6 | // public profileView: CpuProfileView; 7 | // constructor(profile: CpuProfileView) { 8 | // this.profileView = profile; 9 | // } 10 | // owns(node: CpuProfileNodeView): boolean { return node.profileView === this.profileView; } 11 | // parent(node: CpuProfileNodeView): CpuProfileNodeView | undefined { return node.parent; } 12 | // children(node: CpuProfileNodeView): Queryable | undefined { return node.childNodes; } 13 | // } 14 | 15 | export {}; 16 | -------------------------------------------------------------------------------- /ts-perf/packages/events/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/events", 3 | "description": "Typed event subsystem for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/events" 19 | }, 20 | "files": [ 21 | "dist", 22 | "LICENSE", 23 | "README.md" 24 | ], 25 | "scripts": { 26 | "build": "tsc -b", 27 | "prepack": "pnpm run build" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@typescript/benchmarking-scripts", 3 | "version": "0.0.0", 4 | "private": true, 5 | "author": "Microsoft Corp.", 6 | "license": "MIT", 7 | "type": "module", 8 | "engines": { 9 | "node": ">= 20.19.0 || >=22.12.0" 10 | }, 11 | "devDependencies": { 12 | "@badrap/valita": "^0.4.6", 13 | "@types/minimist": "^1.2.5", 14 | "azure-devops-node-api": "^15.1.1", 15 | "dotenv": "^17.2.3", 16 | "es-main": "^1.4.0", 17 | "execa": "^9.6.0", 18 | "filenamify": "^7.0.1", 19 | "glob": "^13.0.0", 20 | "minimist": "^1.2.8", 21 | "octokit": "^5.0.5", 22 | "ora": "^9.0.0", 23 | "pretty-ms": "^9.3.0", 24 | "sort-keys": "^6.0.0" 25 | }, 26 | "scripts": { 27 | "build": "tsc", 28 | "prepack": "pnpm run build" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/host/utils.ts: -------------------------------------------------------------------------------- 1 | import stream from "node:stream"; 2 | 3 | export function pipeAsync(input: stream.Stream, output: NodeJS.WritableStream, options?: { end?: boolean; }) { 4 | return new Promise((resolve, reject) => { 5 | const stream = input.pipe(output, options); 6 | const cleanup = () => { 7 | stream.removeListener("finish", onevent); 8 | stream.removeListener("unpipe", onevent); 9 | stream.removeListener("error", onerror); 10 | }; 11 | const onevent = () => { 12 | resolve(); 13 | cleanup(); 14 | }; 15 | const onerror = (err: any) => { 16 | reject(err); 17 | cleanup(); 18 | }; 19 | stream.once("finish", onevent); 20 | stream.once("unpipe", onevent); 21 | stream.once("error", onerror); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/local.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | 3 | import { Command, CommandMap } from "@ts-perf/api"; 4 | import { HostContext, localScenariosDirectory } from "@ts-perf/core"; 5 | 6 | export async function localScenario(_options: unknown, context: HostContext) { 7 | if (!fs.existsSync(localScenariosDirectory)) { 8 | await fs.promises.mkdir(localScenariosDirectory, { recursive: true }); 9 | } 10 | context.info(`Local scenarios directory created at '${localScenariosDirectory}'.`); 11 | } 12 | 13 | const command: Command = { 14 | commandName: "local", 15 | summary: "Set up a local scenarios directory.", 16 | description: "Set up a local scenarios directory.", 17 | options: {}, 18 | exec: ({ options }, host) => localScenario(options, host), 19 | }; 20 | 21 | export function registerCommands(commands: CommandMap) { 22 | commands.local = command; 23 | } 24 | -------------------------------------------------------------------------------- /ts-perf/packages/inspector/src/schema.ts: -------------------------------------------------------------------------------- 1 | import { StrictEventEmitter } from "@ts-perf/events"; 2 | 3 | import * as inspector from "./inspector"; 4 | import { Session } from "./session"; 5 | 6 | export interface SchemaEvents { 7 | } 8 | 9 | /** 10 | * Provides information about the protocol schema. 11 | */ 12 | export class Schema extends StrictEventEmitter { 13 | public readonly session: Session; 14 | 15 | constructor(session: Session) { 16 | super(); 17 | this.session = session; 18 | } 19 | 20 | /** 21 | * Returns supported domains. 22 | */ 23 | public getDomains() { 24 | return this.session.postAsync("Schema.getDomains"); 25 | } 26 | } 27 | 28 | export namespace Schema { 29 | export import Domain = inspector.Schema.Domain; 30 | export import GetDomainsReturnType = inspector.Schema.GetDomainsReturnType; 31 | } 32 | 33 | export import Domain = inspector.Schema.Domain; 34 | -------------------------------------------------------------------------------- /ts-perf/packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/core", 3 | "description": "Core utilities for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/core" 19 | }, 20 | "files": [ 21 | "dist", 22 | "LICENSE", 23 | "README.md" 24 | ], 25 | "dependencies": { 26 | "@esfx/canceltoken": "^1.0.0", 27 | "@esfx/equatable": "^1.0.2" 28 | }, 29 | "scripts": { 30 | "build": "tsc -b", 31 | "prepack": "pnpm run build" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/src/index.ts: -------------------------------------------------------------------------------- 1 | import "source-map-support/register"; 2 | 3 | import { parseCommandLine, printHelp } from "./commandLine"; 4 | import { HeapOptions } from "./commands/heapProfiler"; 5 | import { ProfilerOptions } from "./commands/profiler"; 6 | 7 | async function main(args: string[]) { 8 | const { commandName, options, help } = parseCommandLine(args); 9 | if (help) return printHelp(commandName); 10 | switch (commandName) { 11 | case "profile": 12 | const profiler = require("./commands/profiler"); 13 | await profiler.profile(options as ProfilerOptions); 14 | break; 15 | case "heap": 16 | const heapProfiler = require("./commands/heapProfiler"); 17 | await heapProfiler.heapProfile(options as HeapOptions); 18 | break; 19 | default: 20 | printHelp(); 21 | break; 22 | } 23 | } 24 | 25 | main(process.argv.slice(2)).catch(console.error); 26 | -------------------------------------------------------------------------------- /ansible/tasks/packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install packages 3 | ansible.builtin.apt: 4 | pkg: 5 | - ripgrep 6 | - unzip 7 | # https://github.com/microsoft/vscode/blob/08631fab3a63e8439bec69dce08aa5cf95360d48/resources/linux/snap/snapcraft.yaml#L22 8 | - ca-certificates 9 | - libasound2 10 | - libatk-bridge2.0-0 11 | - libatk1.0-0 12 | - libatspi2.0-0 13 | - libcairo2 14 | - libcanberra-gtk3-module 15 | - libcurl3-gnutls 16 | - libcurl3-nss 17 | - libcurl4 18 | - libdrm2 19 | - libgbm1 20 | - libgl1 21 | - libglib2.0-0 22 | - libgtk-3-0 23 | - libibus-1.0-5 24 | - libnss3 25 | - libpango-1.0-0 26 | - libsecret-1-0 27 | - libxcomposite1 28 | - libxdamage1 29 | - libxfixes3 30 | - libxkbcommon0 31 | - libxkbfile1 32 | - libxrandr2 33 | - libxss1 34 | - locales-all 35 | - packagekit-gtk3-module 36 | - xdg-utils 37 | become: yes 38 | -------------------------------------------------------------------------------- /scripts/src/backfill/backfillLatestOnBranch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This script backfills the latest commit on each provided branch. 3 | */ 4 | 5 | import assert from "node:assert"; 6 | 7 | import dotenv from "dotenv"; 8 | import minimist from "minimist"; 9 | 10 | import { runPipeline } from "./common.js"; 11 | 12 | dotenv.config(); 13 | 14 | const args = minimist(process.argv.slice(2), { 15 | string: ["pipeline"], 16 | default: { 17 | pipeline: 69, 18 | }, 19 | }); 20 | 21 | const pipeline = args.pipeline; 22 | assert(pipeline, "Must provide --pipeline"); 23 | 24 | for (const branch of args._) { 25 | const refName = `refs/heads/${branch}`; 26 | console.log(`Queueing backfill for ${branch}`); 27 | 28 | await runPipeline(pipeline, { 29 | resources: { 30 | repositories: { 31 | TypeScript: { 32 | refName, 33 | }, 34 | }, 35 | }, 36 | templateParameters: { 37 | HISTORICAL_RUN: "true", 38 | }, 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /ansible/setup.yml: -------------------------------------------------------------------------------- 1 | - name: Setup 2 | hosts: tsperf 3 | 4 | vars: 5 | agent_user: azdo 6 | agent_home: '/home/{{ agent_user }}' 7 | agent_root: '{{ agent_home }}/agent' 8 | agent_download_url: 'https://vstsagentpackage.azureedge.net/agent/3.220.5/vsts-agent-linux-x64-3.220.5.tar.gz' 9 | 10 | install_agent: true 11 | remove_agent: false 12 | 13 | tasks: 14 | - name: Install packages required for ansible 15 | ansible.builtin.apt: 16 | pkg: 17 | - acl 18 | become: yes 19 | 20 | - name: Install packages 21 | ansible.builtin.import_tasks: tasks/packages.yml 22 | 23 | - name: Set up pyperf 24 | ansible.builtin.import_tasks: tasks/pyperf.yml 25 | 26 | - name: Set up azdo 27 | ansible.builtin.import_tasks: tasks/azdo.yml 28 | 29 | - name: Set up isolation 30 | ansible.builtin.import_tasks: tasks/isolation.yml 31 | 32 | - name: Set up docker 33 | ansible.builtin.import_tasks: tasks/docker.yml 34 | 35 | - name: Check reboot 36 | ansible.builtin.import_tasks: tasks/check_reboot.yml 37 | -------------------------------------------------------------------------------- /ansible/tasks/isolation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Configure kernel parameters for isolation 3 | ansible.builtin.copy: 4 | dest: /etc/default/grub.d/ts-perf.cfg 5 | owner: root 6 | group: root 7 | content: > 8 | GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT isolcpus={{ isolated_cpus }} rcu_nocbs={{ isolated_cpus }}" 9 | become: yes 10 | register: grub_cfg 11 | 12 | - name: Update grub 13 | when: grub_cfg.changed 14 | ansible.builtin.shell: update-grub && touch /var/run/reboot-required 15 | become: yes 16 | 17 | - name: Add TSPERF_AGENT_BENCHMARK_CPU to .env 18 | ansible.builtin.lineinfile: 19 | path: '{{ agent_root }}/.env' 20 | regexp: '^TSPERF_AGENT_BENCHMARK_CPU=' 21 | line: 'TSPERF_AGENT_BENCHMARK_CPU={{ benchmark_cpu }}' 22 | become: yes 23 | become_user: '{{ agent_user }}' 24 | register: env_line 25 | when: install_agent 26 | 27 | - name: Restart agent if .env edited 28 | ansible.builtin.shell: ./svc.sh stop && ./svc.sh start 29 | args: 30 | chdir: '{{ agent_root }}' 31 | become: yes 32 | when: svc_status_running and env_line.changed 33 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/host/index.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | 3 | import * as configureHost from "./configure"; 4 | import * as installHost from "./install"; 5 | import * as listHosts from "./list"; 6 | import * as uninstallHost from "./uninstall"; 7 | 8 | export { configureHost, ConfigureHostOptions } from "./configure"; 9 | export { installHost, InstallHostOptions } from "./install"; 10 | export { listHosts, ListHostsOptions } from "./list"; 11 | export { uninstallHost, UninstallHostOptions } from "./uninstall"; 12 | 13 | export function registerCommands(commands: CommandMap) { 14 | commands.host = command; 15 | } 16 | 17 | const command: Command = { 18 | commandName: "host", 19 | summary: "Manage test hosts.", 20 | description: "Review, add, modify, and remove test hosts.", 21 | alias: ["hosts"], 22 | container: true, 23 | commands: {}, 24 | }; 25 | 26 | installHost.registerCommands(command.commands!); 27 | uninstallHost.registerCommands(command.commands!); 28 | configureHost.registerCommands(command.commands!); 29 | listHosts.registerCommands(command.commands!); 30 | -------------------------------------------------------------------------------- /ts-perf/packages/inspector/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/inspector", 3 | "description": "v8 inspector subsystem for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/inspector" 19 | }, 20 | "files": [ 21 | "dist", 22 | "LICENSE", 23 | "README.md" 24 | ], 25 | "dependencies": { 26 | "@esfx/async-deferred": "^1.0.0", 27 | "@ts-perf/core": "workspace:^", 28 | "@ts-perf/events": "workspace:^", 29 | "source-map-support": "^0.5.21" 30 | }, 31 | "devDependencies": { 32 | "@types/source-map-support": "^0.5.10" 33 | }, 34 | "scripts": { 35 | "build": "tsc -b", 36 | "prepack": "pnpm run build" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/azure.ts: -------------------------------------------------------------------------------- 1 | import { DefaultAzureCredential } from "@azure/identity"; 2 | import { BlobServiceClient } from "@azure/storage-blob"; 3 | 4 | import { AzureStorageOptions } from "./options"; 5 | 6 | const defaultAzureStorageAccount = "tsperfstorage2"; 7 | const defaultBlobContainer = "benchmark"; 8 | 9 | export function getBlobService(options: AzureStorageOptions | undefined) { 10 | const azureStorageAccount = getAzureStorageAccount(options); 11 | const azureStorageUrl = `https://${azureStorageAccount}.blob.core.windows.net`; 12 | const credential = new DefaultAzureCredential(); 13 | return new BlobServiceClient(azureStorageUrl, credential); 14 | } 15 | 16 | function getAzureStorageAccount(options: AzureStorageOptions | undefined) { 17 | return options && options.azureStorageAccount 18 | || process.env.TSPERF_AZURE_STORAGE_ACCOUNT 19 | || defaultAzureStorageAccount; 20 | } 21 | 22 | export function getBlobContainer(options: AzureStorageOptions | undefined) { 23 | return options && options.azureStorageContainer 24 | || process.env.TSPERF_AZURE_STORAGE_CONTAINER 25 | || defaultBlobContainer; 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /ts-perf/packages/cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-perf", 3 | "description": "ts-perf command line utility", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/cli" 19 | }, 20 | "bin": { 21 | "ts-perf": "./bin/ts-perf" 22 | }, 23 | "files": [ 24 | "bin", 25 | "dist", 26 | "LICENSE", 27 | "README.md" 28 | ], 29 | "dependencies": { 30 | "@ts-perf/api": "workspace:^", 31 | "@ts-perf/core": "workspace:^", 32 | "power-options": "^0.3.4", 33 | "source-map-support": "^0.5.21" 34 | }, 35 | "devDependencies": { 36 | "@types/source-map-support": "^0.5.10" 37 | }, 38 | "scripts": { 39 | "build": "tsc -b", 40 | "prepack": "pnpm run build" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/profiler", 3 | "description": "v8 CPU Profile and heap snapshot generator for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/profiler" 19 | }, 20 | "bin": { 21 | "ts-profiler": "./bin/ts-profiler" 22 | }, 23 | "files": [ 24 | "bin", 25 | "dist", 26 | "LICENSE", 27 | "README.md" 28 | ], 29 | "dependencies": { 30 | "@ts-perf/inspector": "workspace:^", 31 | "power-options": "^0.3.4", 32 | "source-map-support": "^0.5.21" 33 | }, 34 | "devDependencies": { 35 | "@types/source-map-support": "^0.5.10" 36 | }, 37 | "scripts": { 38 | "build": "tsc -b", 39 | "prepack": "pnpm run build" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/index.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | 3 | import * as addScenario from "./add"; 4 | import * as configureScenario from "./configure"; 5 | import * as deleteScenario from "./delete"; 6 | import * as listScenario from "./list"; 7 | import * as localScenario from "./local"; 8 | 9 | export { addScenario, AddScenarioOptions } from "./add"; 10 | export { configureScenario, ConfigureScenarioOptions } from "./configure"; 11 | export { deleteScenario, DeleteScenarioOptions } from "./delete"; 12 | export { ListScenarioOptions, listScenarios } from "./list"; 13 | 14 | export function registerCommands(commands: CommandMap) { 15 | commands.scenario = command; 16 | } 17 | 18 | const commands: CommandMap = {}; 19 | addScenario.registerCommands(commands); 20 | configureScenario.registerCommands(commands); 21 | deleteScenario.registerCommands(commands); 22 | listScenario.registerCommands(commands); 23 | localScenario.registerCommands(commands); 24 | const command: Command = { 25 | commandName: "scenario", 26 | summary: "Manage performance scenarios.", 27 | description: "Review, add, modify, and remove performance scenarios.", 28 | alias: ["scenarios"], 29 | container: true, 30 | commands, 31 | }; 32 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/index.ts: -------------------------------------------------------------------------------- 1 | export { Benchmark, BenchmarkComponents } from "./benchmark"; 2 | export { BenchmarkComparison, BenchmarkComparisonComponents } from "./benchmarkComparison"; 3 | export { Host, HostComponents } from "./host"; 4 | export { HostPattern } from "./hostPattern"; 5 | export { HostSpecifier } from "./hostSpecifier"; 6 | export { HostSpecifierComponents } from "./hostSpecifierComponents"; 7 | export { Measurement, MeasurementComponents } from "./measurement"; 8 | export { MeasurementComparison, MeasurementComparisonComponents } from "./measurementComparison"; 9 | export { MeasurementComparisonPivot } from "./measurementComparisonPivot"; 10 | export { MeasurementPivot } from "./measurementPivot"; 11 | export { Repository } from "./repository"; 12 | export * from "./sample"; 13 | export { Scenario, ScenarioComponents } from "./scenario"; 14 | export { 15 | TSServerCommand, 16 | TSServerCompletionInfoCommand, 17 | TSServerConfig, 18 | TSServerGeterrCommand, 19 | TSServerNavtoCommand, 20 | TSServerReferencesCommand, 21 | TSServerUpdateOpenCommand, 22 | } from "./tsserverconfig"; 23 | export { computeMetrics, Value, ValueComponents } from "./value"; 24 | export { ValueComparison, ValueComparisonComponents } from "./valueComparison"; 25 | -------------------------------------------------------------------------------- /cases/scenarios/CompilerTSServer/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CompilerTSServer", 3 | "kind": "tsserver", 4 | "args": [], 5 | "tsserverConfig": { 6 | "solution": "Compiler", 7 | "commands": [ 8 | { 9 | "commandName": "updateOpen", 10 | "args": [ 11 | { 12 | "file": "checker.ts" 13 | } 14 | ] 15 | }, 16 | { 17 | "commandName": "geterr", 18 | "args": [ 19 | "checker.ts" 20 | ] 21 | }, 22 | { 23 | "commandName": "references", 24 | "args": { 25 | "file": "checker.ts", 26 | "line": 11696, 27 | "offset": 48 28 | } 29 | }, 30 | { 31 | "commandName": "navto", 32 | "args": { 33 | "searchValue": "Type" 34 | } 35 | }, 36 | { 37 | "commandName": "completionInfo", 38 | "args": { 39 | "file": "checker.ts", 40 | "line": 26636, 41 | "offset": 6 42 | } 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cases/scenarios/Compiler-UnionsTSServer/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Compiler-UnionsTSServer", 3 | "kind": "tsserver", 4 | "args": [], 5 | "tsserverConfig": { 6 | "solution": "Compiler-Unions", 7 | "commands": [ 8 | { 9 | "commandName": "updateOpen", 10 | "args": [ 11 | { 12 | "file": "checker.ts" 13 | } 14 | ] 15 | }, 16 | { 17 | "commandName": "geterr", 18 | "args": [ 19 | "checker.ts" 20 | ] 21 | }, 22 | { 23 | "commandName": "references", 24 | "args": { 25 | "file": "checker.ts", 26 | "line": 10960, 27 | "offset": 48 28 | } 29 | }, 30 | { 31 | "commandName": "navto", 32 | "args": { 33 | "searchValue": "Type" 34 | } 35 | }, 36 | { 37 | "commandName": "completionInfo", 38 | "args": { 39 | "file": "checker.ts", 40 | "line": 25149, 41 | "offset": 6 42 | } 43 | } 44 | ] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ts-perf/packages/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/api", 3 | "description": "Shared API and data model for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/api" 19 | }, 20 | "files": [ 21 | "dist", 22 | "LICENSE", 23 | "README.md" 24 | ], 25 | "dependencies": { 26 | "@azure/identity": "^4.13.0", 27 | "@azure/storage-blob": "^12.29.1", 28 | "@esfx/collections-hashmap": "^1.0.2", 29 | "@esfx/collections-hashset": "^1.0.2", 30 | "@esfx/equatable": "^1.0.2", 31 | "@stdlib/stats-base-dists-normal-cdf": "^0.2.2", 32 | "@ts-perf/core": "workspace:^", 33 | "chalk": "^4.1.2", 34 | "iterable-query": "1.0.0-pre.16", 35 | "power-options": "^0.3.4", 36 | "semver": "^7.7.3" 37 | }, 38 | "devDependencies": { 39 | "@types/semver": "^7.7.1" 40 | }, 41 | "scripts": { 42 | "build": "tsc -b", 43 | "prepack": "pnpm run build" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/print/index.ts: -------------------------------------------------------------------------------- 1 | import { Benchmark, BenchmarkComparison } from "@ts-perf/api"; 2 | 3 | import { BenchmarkOptions } from "../"; 4 | import * as console from "./console"; 5 | import * as html from "./html"; 6 | import * as markdown from "./markdown"; 7 | 8 | export function printComparison( 9 | comparison: BenchmarkComparison, 10 | options: BenchmarkOptions, 11 | out: NodeJS.WritableStream, 12 | ) { 13 | switch (options.format) { 14 | case "console": 15 | console.printComparison(comparison, options, out); 16 | break; 17 | case "markdown": 18 | markdown.printComparison(comparison, options, out); 19 | break; 20 | case "html": 21 | case "html-fragment": 22 | html.printComparison(comparison, options, out); 23 | break; 24 | } 25 | } 26 | 27 | export function printBenchmark(benchmark: Benchmark, options: BenchmarkOptions, out: NodeJS.WritableStream) { 28 | switch (options.format) { 29 | case "console": 30 | console.printBenchmark(benchmark, options, out); 31 | break; 32 | 33 | case "markdown": 34 | markdown.printBenchmark(benchmark, options, out); 35 | break; 36 | 37 | case "html": 38 | case "html-fragment": 39 | html.printBenchmark(benchmark, options, out); 40 | break; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsserver-only/matrix.snap: -------------------------------------------------------------------------------- 1 | { 2 | "any": { 3 | "tsserver_node_18_15_0_CompilerTSServer": { 4 | "TSPERF_JOB_HOST": "node@18.15.0", 5 | "TSPERF_JOB_ITERATIONS": 6, 6 | "TSPERF_JOB_KIND": "tsserver", 7 | "TSPERF_JOB_NAME": "tsserver_node_18_15_0_CompilerTSServer", 8 | "TSPERF_JOB_SCENARIO": "CompilerTSServer", 9 | "TSPERF_JOB_WARMUPS": 1, 10 | }, 11 | "tsserver_node_18_15_0_Compiler_UnionsTSServer": { 12 | "TSPERF_JOB_HOST": "node@18.15.0", 13 | "TSPERF_JOB_ITERATIONS": 6, 14 | "TSPERF_JOB_KIND": "tsserver", 15 | "TSPERF_JOB_NAME": "tsserver_node_18_15_0_Compiler_UnionsTSServer", 16 | "TSPERF_JOB_SCENARIO": "Compiler-UnionsTSServer", 17 | "TSPERF_JOB_WARMUPS": 1, 18 | }, 19 | "tsserver_node_18_15_0_xstate_main_1_tsserver": { 20 | "TSPERF_JOB_HOST": "node@18.15.0", 21 | "TSPERF_JOB_ITERATIONS": 6, 22 | "TSPERF_JOB_KIND": "tsserver", 23 | "TSPERF_JOB_NAME": "tsserver_node_18_15_0_xstate_main_1_tsserver", 24 | "TSPERF_JOB_SCENARIO": "xstate-main-1-tsserver", 25 | "TSPERF_JOB_WARMUPS": 1, 26 | }, 27 | }, 28 | "ts-perf1": {}, 29 | "ts-perf10": {}, 30 | "ts-perf11": {}, 31 | "ts-perf12": {}, 32 | "ts-perf2": {}, 33 | "ts-perf3": {}, 34 | "ts-perf4": {}, 35 | "ts-perf5": {}, 36 | "ts-perf6": {}, 37 | "ts-perf7": {}, 38 | "ts-perf8": {}, 39 | "ts-perf9": {}, 40 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@typescript/benchmarking", 3 | "version": "0.0.0", 4 | "private": true, 5 | "author": "Microsoft Corp.", 6 | "license": "MIT", 7 | "engines": { 8 | "node": ">= 20.19.0 || >=22.12.0" 9 | }, 10 | "devDependencies": { 11 | "@eslint/js": "^9.39.1", 12 | "@types/node": "^22.19.1", 13 | "@typescript-eslint/eslint-plugin": "^8.47.0", 14 | "@typescript-eslint/parser": "^8.47.0", 15 | "dprint": "^0.50.2", 16 | "eslint": "^9.39.1", 17 | "eslint-plugin-simple-import-sort": "^12.1.1", 18 | "eslint-plugin-unicorn": "^62.0.0", 19 | "globals": "^16.5.0", 20 | "typescript": "^5.9.3", 21 | "typescript-eslint": "^8.47.0", 22 | "vitest": "^4.0.10" 23 | }, 24 | "packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748", 25 | "scripts": { 26 | "build": "pnpm run --filter './scripts' --filter './ts-perf' build", 27 | "test": "vitest" 28 | }, 29 | "pnpm": { 30 | "requiredScripts": [ 31 | "build" 32 | ], 33 | "overrides": { 34 | "@types/node": "$@types/node" 35 | }, 36 | "onlyBuiltDependencies": [ 37 | "@esfx/equatable", 38 | "dprint", 39 | "esbuild" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/src/commandLine.ts: -------------------------------------------------------------------------------- 1 | import { CommandLine } from "power-options"; 2 | 3 | import { HeapOptions } from "./commands/heapProfiler"; 4 | import { ProfilerOptions } from "./commands/profiler"; 5 | 6 | export function parseCommandLine(args: string[]) { 7 | return commandLine.parse(args); 8 | } 9 | 10 | export function printHelp(commandName?: string) { 11 | return commandLine.printHelp(commandName); 12 | } 13 | 14 | const commandLine = new CommandLine({ 15 | name: "ts-profiler", 16 | auto: true, 17 | color: true, 18 | commands: { 19 | profile: { 20 | options: { 21 | out: { type: "string", alias: "cpuprofile", position: 0, required: true }, 22 | sourceMap: { type: "boolean" }, 23 | sourceRoot: { type: "string" }, 24 | timeline: { type: "boolean", defaultValue: true }, 25 | trim: { type: "boolean" }, 26 | pretty: { type: "boolean", hidden: true }, 27 | }, 28 | }, 29 | heap: { 30 | options: { 31 | out: { type: "string", alias: "heapsnapshot", position: 0, required: true }, 32 | events: { type: "string", longName: "event", multiple: true }, 33 | }, 34 | }, 35 | }, 36 | options: { 37 | args: { 38 | type: "string", 39 | passthru: true, 40 | }, 41 | }, 42 | }); 43 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/bailoutView.ts: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | 3 | import { Table } from "../../decorators"; 4 | import { CpuProfileFunctionView } from "./functionView"; 5 | import { CpuProfileNode } from "./node"; 6 | import { CpuProfile } from "./profile"; 7 | 8 | @Table, {}>({ 9 | createContext: () => ({}), 10 | columns: [ 11 | { 12 | header: "function", 13 | expression: x => `${x.functionName || "(anonymous function)"} ${chalk.gray(`(${x.location})`)}`, 14 | }, 15 | { header: "count", expression: x => x.count, align: "right" }, 16 | { header: "reason", expression: x => x.reason }, 17 | ], 18 | }) 19 | export class BailoutView { 20 | readonly profile: CpuProfile; 21 | readonly owner: TOwner; 22 | readonly reason: string; 23 | readonly nodes: readonly CpuProfileNode[]; 24 | readonly count: number; 25 | 26 | constructor(owner: TOwner, reason: string, nodes: readonly CpuProfileNode[]) { 27 | this.owner = owner; 28 | this.profile = owner.profile; 29 | this.reason = reason; 30 | this.nodes = nodes; 31 | this.count = nodes.length; 32 | } 33 | 34 | get functionName() { 35 | return this.owner.functionName; 36 | } 37 | get location() { 38 | return this.owner.location; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/src/commands/profiler.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | 3 | import { Profiler, Session, Timeline } from "@ts-perf/inspector"; 4 | 5 | import { Executable } from "../executable"; 6 | 7 | export interface ProfilerOptions { 8 | args: string[]; 9 | out: string; 10 | sourceMap: boolean; 11 | sourceRoot: string; 12 | timeline: boolean; 13 | trim: boolean; 14 | pretty: boolean; 15 | } 16 | 17 | export async function profile(options: ProfilerOptions) { 18 | const session = new Session(); 19 | try { 20 | const compiler = new Executable(options.args); 21 | const profiler = new Profiler(session); 22 | profiler.on("progress", message => { 23 | console.log(message); 24 | }); 25 | 26 | session.connect(); 27 | if (options.timeline) { 28 | session.startTimeline(); 29 | } 30 | await profiler.enable(); 31 | await profiler.start(); 32 | await compiler.exec(); 33 | const profile = await profiler.stop(options); 34 | await profiler.disable(); 35 | const result = options.timeline ? session.stopTimeline() : profile; 36 | const content = options.pretty ? JSON.stringify(result, undefined, " ") 37 | : result instanceof Timeline ? result.toString() : JSON.stringify(result); 38 | fs.writeFileSync(options.out, content, { encoding: "utf8" }); 39 | } 40 | finally { 41 | session.disconnect(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/src/executable.ts: -------------------------------------------------------------------------------- 1 | const processExitSentinel = {}; 2 | 3 | export class Executable { 4 | public readonly args: readonly string[]; 5 | 6 | constructor(args: readonly string[] = []) { 7 | this.args = args; 8 | } 9 | 10 | public exec() { 11 | return new Promise(resolve => { 12 | const savedExit = process.exit; 13 | const savedArgs = process.argv; 14 | 15 | let exitCode = 0; 16 | process.exit = (code = 0) => { 17 | exitCode = +(code ?? 1); 18 | throw processExitSentinel; 19 | }; 20 | 21 | process.once("beforeExit", handleExit); 22 | process.argv = [process.argv[0], ...this.args, "--diagnostics"]; 23 | 24 | try { 25 | // Exec the compiler 26 | require(this.args[0]); 27 | } 28 | catch (e) { 29 | if (e === processExitSentinel) { 30 | handleExit(); 31 | } 32 | else { 33 | throw e; 34 | } 35 | } 36 | 37 | function handleExit() { 38 | process.exit = savedExit; 39 | process.argv = savedArgs; 40 | try { 41 | resolve(exitCode); 42 | } 43 | catch (e) { 44 | console.error(e); 45 | process.exit(-1); 46 | } 47 | } 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /cases/scenarios/xstate-main-1-tsserver/scenario.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xstate-main-1-tsserver", 3 | "kind": "tsserver", 4 | "args": [], 5 | "tsserverConfig": { 6 | "solution": "xstate-main-1-tsserver", 7 | "commands": [ 8 | { 9 | "commandName": "updateOpen", 10 | "args": [ 11 | { 12 | "file": "packages/core/src/index.ts" 13 | }, 14 | { 15 | "file": "packages/core/src/StateNode.ts" 16 | } 17 | ] 18 | }, 19 | { 20 | "commandName": "geterr", 21 | "args": [ 22 | "packages/core/src/StateNode.ts" 23 | ] 24 | }, 25 | { 26 | "commandName": "references", 27 | "args": { 28 | "file": "packages/core/src/index.ts", 29 | "line": 14, 30 | "offset": 15 31 | } 32 | }, 33 | { 34 | "commandName": "navto", 35 | "args": { 36 | "searchValue": "State" 37 | } 38 | }, 39 | { 40 | "commandName": "completionInfo", 41 | "args": { 42 | "file": "packages/core/src/index.ts", 43 | "line": 47, 44 | "offset": 1 45 | } 46 | } 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ts-perf/packages/inspector/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | BreakLocation, 3 | BreakpointId, 4 | CallFrameId, 5 | Debugger, 6 | CallFrame as DebuggerCallFrame, 7 | DebuggerEvents, 8 | Location, 9 | Scope, 10 | ScriptPosition, 11 | SearchMatch, 12 | } from "./debugger"; 13 | export { 14 | HeapProfiler, 15 | HeapProfilerEvents, 16 | HeapSnapshotObjectId, 17 | SamplingHeapProfile, 18 | SamplingHeapProfileNode, 19 | } from "./heapProfiler"; 20 | export { 21 | CoverageRange, 22 | FunctionCoverage, 23 | PositionTickInfo, 24 | Profile, 25 | ProfileNode, 26 | Profiler, 27 | ProfilerEvents, 28 | ScriptCoverage, 29 | } from "./profiler"; 30 | export { 31 | CallArgument, 32 | CallFrame, 33 | CustomPreview, 34 | EntryPreview, 35 | ExceptionDetails, 36 | ExecutionContextDescription, 37 | ExecutionContextId, 38 | InternalPropertyDescriptor, 39 | ObjectPreview, 40 | PropertyDescriptor, 41 | PropertyPreview, 42 | RemoteObject, 43 | RemoteObjectId, 44 | Runtime, 45 | RuntimeEvents, 46 | ScriptId, 47 | StackTrace, 48 | Timestamp, 49 | UnserializableValue, 50 | } from "./runtime"; 51 | export { Domain, Schema, SchemaEvents } from "./schema"; 52 | export { Session, SessionActions, SessionEvents } from "./session"; 53 | export { ReadonlyTimeline, Timeline, TimelineView } from "./timeline"; 54 | export { Visitor } from "./visitor"; 55 | export { ProfileTrimmer } from "./visitors/profileTrimmer"; 56 | export { SourceMapper } from "./visitors/sourceMapper"; 57 | -------------------------------------------------------------------------------- /cases/solutions/Compiler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig-base", 3 | "compilerOptions": { 4 | "removeComments": true, 5 | "outFile": "../../built/local/tsc.js", 6 | "declaration": true 7 | }, 8 | "files": [ 9 | "core.ts", 10 | "performance.ts", 11 | "sys.ts", 12 | "types.ts", 13 | "scanner.ts", 14 | "parser.ts", 15 | "utilities.ts", 16 | "binder.ts", 17 | "symbolWalker.ts", 18 | "checker.ts", 19 | "factory.ts", 20 | "visitor.ts", 21 | "transformers/utilities.ts", 22 | "transformers/ts.ts", 23 | "transformers/jsx.ts", 24 | "transformers/esnext.ts", 25 | "transformers/es2017.ts", 26 | "transformers/es2016.ts", 27 | "transformers/es2015.ts", 28 | "transformers/es5.ts", 29 | "transformers/generators.ts", 30 | "transformers/destructuring.ts", 31 | "transformers/module/module.ts", 32 | "transformers/module/system.ts", 33 | "transformers/module/es2015.ts", 34 | "transformer.ts", 35 | "comments.ts", 36 | "sourcemap.ts", 37 | "declarationEmitter.ts", 38 | "emitter.ts", 39 | "watchUtilities.ts", 40 | "program.ts", 41 | "builderState.ts", 42 | "builder.ts", 43 | "resolutionCache.ts", 44 | "watch.ts", 45 | "commandLineParser.ts", 46 | "tsc.ts", 47 | "diagnosticInformationMap.generated.ts" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsserver-only/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"tsserver_node_18_15_0_CompilerTSServer":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsserver","TSPERF_JOB_NAME":"tsserver_node_18_15_0_CompilerTSServer","TSPERF_JOB_SCENARIO":"CompilerTSServer","TSPERF_JOB_WARMUPS":1},"tsserver_node_18_15_0_Compiler_UnionsTSServer":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsserver","TSPERF_JOB_NAME":"tsserver_node_18_15_0_Compiler_UnionsTSServer","TSPERF_JOB_SCENARIO":"Compiler-UnionsTSServer","TSPERF_JOB_WARMUPS":1},"tsserver_node_18_15_0_xstate_main_1_tsserver":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsserver","TSPERF_JOB_NAME":"tsserver_node_18_15_0_xstate_main_1_tsserver","TSPERF_JOB_SCENARIO":"xstate-main-1-tsserver","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "tsserver", 23 | } -------------------------------------------------------------------------------- /ts-perf/packages/commands/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ts-perf/commands", 3 | "description": "Core commands for ts-perf", 4 | "version": "0.8.0", 5 | "private": true, 6 | "main": "dist", 7 | "typings": "dist", 8 | "author": "Microsoft Corp.", 9 | "license": "MIT", 10 | "engines": { 11 | "node": ">= 20.19.0 || >=22.12.0" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/microsoft/typescript-benchmarking/issues" 15 | }, 16 | "repository": { 17 | "url": "github:microsoft/typescript-benchmarking", 18 | "directory": "ts-perf/packages/commands" 19 | }, 20 | "files": [ 21 | "dist", 22 | "LICENSE", 23 | "README.md" 24 | ], 25 | "dependencies": { 26 | "@esfx/async-delay": "^1.0.0", 27 | "@esfx/canceltoken": "^1.0.0", 28 | "@ts-perf/api": "workspace:^", 29 | "@ts-perf/core": "workspace:^", 30 | "@ts-perf/inspector": "workspace:^", 31 | "@ts-perf/profiler": "workspace:^", 32 | "@typescript/server-harness": "^0.3.5", 33 | "@vscode/test-electron": "^2.5.2", 34 | "chalk": "^4.1.2", 35 | "iterable-query": "1.0.0-pre.16", 36 | "iterable-query-linq": "^0.1.0", 37 | "power-options": "^0.3.4", 38 | "semver": "^7.7.3", 39 | "table-style": "^0.1.4", 40 | "tmp": "^0.2.5" 41 | }, 42 | "devDependencies": { 43 | "@types/semver": "^7.7.1", 44 | "@types/tmp": "^0.2.6" 45 | }, 46 | "scripts": { 47 | "build": "tsc -b", 48 | "prepack": "pnpm run build" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/tscpublic.ts: -------------------------------------------------------------------------------- 1 | const [typescript, ...args] = process.argv.slice(2); 2 | 3 | interface TypeScript { 4 | Debug: { 5 | loggingHost: { 6 | log(level: unknown, s: string): void; 7 | }; 8 | isDebugging: boolean; 9 | enableDebugInfo(): void; 10 | }; 11 | executeCommandLine?(sys: {}, cb: () => void, args: string[]): void; 12 | noop(): void; 13 | sys: { 14 | args: string[]; 15 | newLine: string; 16 | write(s: string): void; 17 | tryEnableSourceMapsForHost?(): void; 18 | setBlocking?(): void; 19 | getEnvironmentVariable(name: string): string; 20 | }; 21 | } 22 | 23 | const ts: TypeScript = require(typescript); 24 | 25 | if (!ts.executeCommandLine) { 26 | // Don't use stderr here; tsc errors via stdout. 27 | console.log("Expected TypeScript API to have executeCommandLine method."); 28 | process.exit(1); 29 | } 30 | 31 | ts.sys.args = args; 32 | process.argv = [process.argv[0], ...args]; 33 | 34 | // Copied from https://github.com/microsoft/TypeScript/blob/main/src/tsc/tsc.ts 35 | ts.Debug.loggingHost = { 36 | log(_level, s) { 37 | ts.sys.write(`${s || ""}${ts.sys.newLine}`); 38 | }, 39 | }; 40 | 41 | if (ts.Debug.isDebugging) { 42 | ts.Debug.enableDebugInfo(); 43 | } 44 | 45 | if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) { 46 | ts.sys.tryEnableSourceMapsForHost(); 47 | } 48 | 49 | if (ts.sys.setBlocking) { 50 | ts.sys.setBlocking(); 51 | } 52 | 53 | ts.executeCommandLine(ts.sys, ts.noop, ts.sys.args); 54 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only/matrix.snap: -------------------------------------------------------------------------------- 1 | { 2 | "any": { 3 | "startup_node_18_15_0_tsc_startup": { 4 | "TSPERF_JOB_HOST": "node@18.15.0", 5 | "TSPERF_JOB_ITERATIONS": 6, 6 | "TSPERF_JOB_KIND": "startup", 7 | "TSPERF_JOB_NAME": "startup_node_18_15_0_tsc_startup", 8 | "TSPERF_JOB_SCENARIO": "tsc-startup", 9 | "TSPERF_JOB_WARMUPS": 1, 10 | }, 11 | "startup_node_18_15_0_tsserver_startup": { 12 | "TSPERF_JOB_HOST": "node@18.15.0", 13 | "TSPERF_JOB_ITERATIONS": 6, 14 | "TSPERF_JOB_KIND": "startup", 15 | "TSPERF_JOB_NAME": "startup_node_18_15_0_tsserver_startup", 16 | "TSPERF_JOB_SCENARIO": "tsserver-startup", 17 | "TSPERF_JOB_WARMUPS": 1, 18 | }, 19 | "startup_node_18_15_0_tsserverlibrary_startup": { 20 | "TSPERF_JOB_HOST": "node@18.15.0", 21 | "TSPERF_JOB_ITERATIONS": 6, 22 | "TSPERF_JOB_KIND": "startup", 23 | "TSPERF_JOB_NAME": "startup_node_18_15_0_tsserverlibrary_startup", 24 | "TSPERF_JOB_SCENARIO": "tsserverlibrary-startup", 25 | "TSPERF_JOB_WARMUPS": 1, 26 | }, 27 | "startup_node_18_15_0_typescript_startup": { 28 | "TSPERF_JOB_HOST": "node@18.15.0", 29 | "TSPERF_JOB_ITERATIONS": 6, 30 | "TSPERF_JOB_KIND": "startup", 31 | "TSPERF_JOB_NAME": "startup_node_18_15_0_typescript_startup", 32 | "TSPERF_JOB_SCENARIO": "typescript-startup", 33 | "TSPERF_JOB_WARMUPS": 1, 34 | }, 35 | }, 36 | "ts-perf1": {}, 37 | "ts-perf10": {}, 38 | "ts-perf11": {}, 39 | "ts-perf12": {}, 40 | "ts-perf2": {}, 41 | "ts-perf3": {}, 42 | "ts-perf4": {}, 43 | "ts-perf5": {}, 44 | "ts-perf6": {}, 45 | "ts-perf7": {}, 46 | "ts-perf8": {}, 47 | "ts-perf9": {}, 48 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only hosts=node@22.8.0/matrix.snap: -------------------------------------------------------------------------------- 1 | { 2 | "any": { 3 | "startup_node_22_8_0_tsc_startup": { 4 | "TSPERF_JOB_HOST": "node@22.8.0", 5 | "TSPERF_JOB_ITERATIONS": 6, 6 | "TSPERF_JOB_KIND": "startup", 7 | "TSPERF_JOB_NAME": "startup_node_22_8_0_tsc_startup", 8 | "TSPERF_JOB_SCENARIO": "tsc-startup", 9 | "TSPERF_JOB_WARMUPS": 1, 10 | }, 11 | "startup_node_22_8_0_tsserver_startup": { 12 | "TSPERF_JOB_HOST": "node@22.8.0", 13 | "TSPERF_JOB_ITERATIONS": 6, 14 | "TSPERF_JOB_KIND": "startup", 15 | "TSPERF_JOB_NAME": "startup_node_22_8_0_tsserver_startup", 16 | "TSPERF_JOB_SCENARIO": "tsserver-startup", 17 | "TSPERF_JOB_WARMUPS": 1, 18 | }, 19 | "startup_node_22_8_0_tsserverlibrary_startup": { 20 | "TSPERF_JOB_HOST": "node@22.8.0", 21 | "TSPERF_JOB_ITERATIONS": 6, 22 | "TSPERF_JOB_KIND": "startup", 23 | "TSPERF_JOB_NAME": "startup_node_22_8_0_tsserverlibrary_startup", 24 | "TSPERF_JOB_SCENARIO": "tsserverlibrary-startup", 25 | "TSPERF_JOB_WARMUPS": 1, 26 | }, 27 | "startup_node_22_8_0_typescript_startup": { 28 | "TSPERF_JOB_HOST": "node@22.8.0", 29 | "TSPERF_JOB_ITERATIONS": 6, 30 | "TSPERF_JOB_KIND": "startup", 31 | "TSPERF_JOB_NAME": "startup_node_22_8_0_typescript_startup", 32 | "TSPERF_JOB_SCENARIO": "typescript-startup", 33 | "TSPERF_JOB_WARMUPS": 1, 34 | }, 35 | }, 36 | "ts-perf1": {}, 37 | "ts-perf10": {}, 38 | "ts-perf11": {}, 39 | "ts-perf12": {}, 40 | "ts-perf2": {}, 41 | "ts-perf3": {}, 42 | "ts-perf4": {}, 43 | "ts-perf5": {}, 44 | "ts-perf6": {}, 45 | "ts-perf7": {}, 46 | "ts-perf8": {}, 47 | "ts-perf9": {}, 48 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"startup_node_18_15_0_tsc_startup":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_18_15_0_tsc_startup","TSPERF_JOB_SCENARIO":"tsc-startup","TSPERF_JOB_WARMUPS":1},"startup_node_18_15_0_tsserver_startup":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_18_15_0_tsserver_startup","TSPERF_JOB_SCENARIO":"tsserver-startup","TSPERF_JOB_WARMUPS":1},"startup_node_18_15_0_tsserverlibrary_startup":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_18_15_0_tsserverlibrary_startup","TSPERF_JOB_SCENARIO":"tsserverlibrary-startup","TSPERF_JOB_WARMUPS":1},"startup_node_18_15_0_typescript_startup":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_18_15_0_typescript_startup","TSPERF_JOB_SCENARIO":"typescript-startup","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "startup", 23 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/startup-only hosts=node@22.8.0/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"startup_node_22_8_0_tsc_startup":{"TSPERF_JOB_HOST":"node@22.8.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_22_8_0_tsc_startup","TSPERF_JOB_SCENARIO":"tsc-startup","TSPERF_JOB_WARMUPS":1},"startup_node_22_8_0_tsserver_startup":{"TSPERF_JOB_HOST":"node@22.8.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_22_8_0_tsserver_startup","TSPERF_JOB_SCENARIO":"tsserver-startup","TSPERF_JOB_WARMUPS":1},"startup_node_22_8_0_tsserverlibrary_startup":{"TSPERF_JOB_HOST":"node@22.8.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_22_8_0_tsserverlibrary_startup","TSPERF_JOB_SCENARIO":"tsserverlibrary-startup","TSPERF_JOB_WARMUPS":1},"startup_node_22_8_0_typescript_startup":{"TSPERF_JOB_HOST":"node@22.8.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"startup","TSPERF_JOB_NAME":"startup_node_22_8_0_typescript_startup","TSPERF_JOB_SCENARIO":"typescript-startup","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "startup", 23 | } -------------------------------------------------------------------------------- /cases/solutions/Compiler-Unions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "removeComments": true, 4 | "outFile": "built/local/tsc.js", 5 | "declaration": true, 6 | "lib": ["es5"], 7 | "noEmitOnError": false, 8 | "noImplicitAny": true, 9 | "noImplicitThis": true, 10 | "noUnusedParameters": true, 11 | "alwaysStrict": true, 12 | "pretty": true, 13 | "preserveConstEnums": true, 14 | "stripInternal": true, 15 | "sourceMap": true, 16 | "target": "es5", 17 | "types": [] 18 | }, 19 | "files": [ 20 | "core.ts", 21 | "performance.ts", 22 | "sys.ts", 23 | "types.ts", 24 | "scanner.ts", 25 | "parser.ts", 26 | "utilities.ts", 27 | "binder.ts", 28 | "symbolWalker.ts", 29 | "checker.ts", 30 | "factory.ts", 31 | "visitor.ts", 32 | "transformers/utilities.ts", 33 | "transformers/ts.ts", 34 | "transformers/jsx.ts", 35 | "transformers/esnext.ts", 36 | "transformers/es2017.ts", 37 | "transformers/es2016.ts", 38 | "transformers/es2015.ts", 39 | "transformers/es5.ts", 40 | "transformers/generators.ts", 41 | "transformers/destructuring.ts", 42 | "transformers/module/module.ts", 43 | "transformers/module/system.ts", 44 | "transformers/module/es2015.ts", 45 | "transformer.ts", 46 | "comments.ts", 47 | "sourcemap.ts", 48 | "declarationEmitter.ts", 49 | "emitter.ts", 50 | "program.ts", 51 | "commandLineParser.ts", 52 | "tsc.ts", 53 | "diagnosticInformationMap.generated.ts" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/location.ts: -------------------------------------------------------------------------------- 1 | import * as inspector from "@ts-perf/inspector"; 2 | import { Comparable, fn } from "iterable-query"; 3 | 4 | export class Location implements Comparable { 5 | readonly url: string; 6 | readonly lineNumber: number; 7 | readonly columnNumber: number; 8 | 9 | constructor(url: string, lineNumber = -1, columnNumber = -1) { 10 | this.url = url && fileURLToPath(url); 11 | this.lineNumber = lineNumber; 12 | this.columnNumber = columnNumber; 13 | } 14 | 15 | get inlined() { 16 | return !!this.url && this.lineNumber === -1 && this.columnNumber === -1; 17 | } 18 | 19 | static fromCallFrame(callFrame: inspector.CallFrame) { 20 | return new Location( 21 | callFrame.url, 22 | callFrame.lineNumber, 23 | callFrame.columnNumber, 24 | ); 25 | } 26 | 27 | valueOf() { 28 | return this.toString(); 29 | } 30 | 31 | toString() { 32 | if (this.inlined) return ""; 33 | let s = this.url || "program"; 34 | if (this.url && this.lineNumber !== -1) { 35 | s += ":" + (this.lineNumber + 1); 36 | if (this.columnNumber !== -1) { 37 | s += ":" + (this.columnNumber + 1); 38 | } 39 | } 40 | return s; 41 | } 42 | 43 | [Comparable.compareTo](other: unknown) { 44 | if (!(other instanceof Location)) throw new TypeError(); 45 | return fn.compare(this.url, other.url) 46 | || fn.compare(this.lineNumber, other.lineNumber) 47 | || fn.compare(this.columnNumber, other.columnNumber); 48 | } 49 | } 50 | function fileURLToPath(url: string): string { 51 | throw new Error("Function not implemented."); 52 | } 53 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/merge/index.ts: -------------------------------------------------------------------------------- 1 | import { Benchmark, Command, CommandMap } from "@ts-perf/api"; 2 | import { HostContext } from "@ts-perf/core"; 3 | 4 | export interface MergeOptions { 5 | files: string[]; 6 | output: string; 7 | } 8 | 9 | export async function merge(options: MergeOptions, host: HostContext) { 10 | let benchmarks; 11 | try { 12 | benchmarks = await Promise.all(options.files.map(file => Benchmark.loadAsync(file))); 13 | } 14 | catch (e) { 15 | host.error(`Failed to load benchmark files: ${e}`); 16 | return; 17 | } 18 | 19 | if (benchmarks.length < 1) { 20 | host.error(`Expected at least one benchmark file`); 21 | return; 22 | } 23 | 24 | try { 25 | let result = benchmarks[0]; 26 | for (let i = 1; i < benchmarks.length; i++) { 27 | result = result.merge(benchmarks[i]); 28 | } 29 | await result.saveAsync(options.output); 30 | } 31 | catch (e) { 32 | host.error(`Failed to merge benchmark files: ${e}`); 33 | return; 34 | } 35 | } 36 | 37 | const command: Command = { 38 | commandName: "merge", 39 | summary: "Merge benchmark files.", 40 | description: "Merge benchmark files.", 41 | options: { 42 | files: { 43 | type: "string", 44 | multiple: true, 45 | required: true, 46 | rest: true, 47 | description: "Benchmark files to be merged.", 48 | }, 49 | output: { 50 | type: "string", 51 | required: true, 52 | description: "Where to store the merged benchmark file.", 53 | }, 54 | }, 55 | exec: ({ options }, host) => merge(options, host), 56 | }; 57 | 58 | export function registerCommands(commands: CommandMap) { 59 | commands.merge = command; 60 | } 61 | -------------------------------------------------------------------------------- /scripts/src/backfill/common.ts: -------------------------------------------------------------------------------- 1 | import vsts from "azure-devops-node-api"; 2 | import type { RunPipelineParameters } from "azure-devops-node-api/interfaces/PipelinesInterfaces.js"; 3 | 4 | import { getNonEmptyEnv, retry } from "../utils.js"; 5 | 6 | const unset = Symbol(); 7 | 8 | function memoize(fn: () => T): () => T { 9 | let v: T | typeof unset = unset; 10 | return () => { 11 | if (v !== unset) { 12 | return v; 13 | } 14 | return (v = fn()); 15 | }; 16 | } 17 | 18 | const project = "cf7ac146-d525-443c-b23c-0d58337efebc"; 19 | 20 | const getWebApi = memoize(() => { 21 | const vstsToken = getNonEmptyEnv("VSTS_TOKEN"); 22 | 23 | return new vsts.WebApi( 24 | "https://typescript.visualstudio.com/defaultcollection", 25 | vsts.getPersonalAccessTokenHandler(vstsToken), 26 | ); 27 | }); 28 | 29 | const getBuildApi = memoize(() => getWebApi().getBuildApi()); 30 | const getPipelinesApi = memoize(() => getWebApi().getPipelinesApi()); 31 | 32 | export async function getPendingBuildCount(pipeline: number) { 33 | const api = await getBuildApi(); 34 | const builds = await retry(() => 35 | api.getBuilds( 36 | project, 37 | [pipeline], 38 | undefined, 39 | undefined, 40 | undefined, 41 | undefined, 42 | undefined, 43 | undefined, 44 | /** @type {any} */ (1 | 32), // BuildStatus.InProgress | BuildStatus.NotStarted 45 | ) 46 | ); 47 | return builds.length; 48 | } 49 | 50 | interface PipelineRunResult { 51 | _links?: { web: { href: string; }; }; 52 | } 53 | 54 | export async function runPipeline(pipelineId: number, args: RunPipelineParameters): Promise { 55 | const api = await getPipelinesApi(); 56 | return api.runPipeline(args, project, pipelineId); 57 | } 58 | -------------------------------------------------------------------------------- /.dprint.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "indentWidth": 4, 3 | "lineWidth": 120, 4 | "newLineKind": "lf", 5 | "useTabs": false, 6 | "typescript": { 7 | "semiColons": "always", 8 | "quoteStyle": "preferDouble", 9 | "quoteProps": "consistent", 10 | "useBraces": "whenNotSingleLine", 11 | "bracePosition": "sameLineUnlessHanging", 12 | "singleBodyPosition": "sameLine", 13 | "nextControlFlowPosition": "nextLine", // Stroustrup style braces. 14 | "trailingCommas": "onlyMultiLine", 15 | "preferHanging": false, 16 | "operatorPosition": "nextLine", 17 | 18 | "arrowFunction.useParentheses": "preferNone", 19 | "conditionalExpression.linePerExpression": false, // Keep our "match/case"-ish conditionals. 20 | "functionExpression.spaceAfterFunctionKeyword": true, 21 | // "importDeclaration.forceMultiLine": true, 22 | "constructorType.spaceAfterNewKeyword": true, 23 | "constructSignature.spaceAfterNewKeyword": true, 24 | // Let eslint-plugin-simple-import-sort handle this. 25 | "module.sortImportDeclarations": "maintain", 26 | "module.sortExportDeclarations": "maintain", 27 | "exportDeclaration.sortNamedExports": "maintain", 28 | "importDeclaration.sortNamedImports": "maintain" 29 | }, 30 | "json": { 31 | "trailingCommas": "never" 32 | }, 33 | "yaml": { 34 | "indentWidth": 2, 35 | "quotes": "preferSingle" 36 | }, 37 | "excludes": [ 38 | "**/node_modules", 39 | "**/*-lock.json", 40 | "**/pnpm-lock.yaml", 41 | "**/dist/**", 42 | "cases/solutions/**", 43 | "SECURITY.md" 44 | ], 45 | "plugins": [ 46 | "https://plugins.dprint.dev/typescript-0.95.12.wasm", 47 | "https://plugins.dprint.dev/json-0.21.0.wasm", 48 | "https://plugins.dprint.dev/markdown-0.20.0.wasm", 49 | "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/measurementPivot.ts: -------------------------------------------------------------------------------- 1 | import { Measurement } from "./measurement"; 2 | import { Value } from "./value"; 3 | 4 | export class MeasurementPivot { 5 | constructor( 6 | public readonly measurement: Measurement, 7 | public readonly value: Value, 8 | ) { 9 | } 10 | 11 | public get name() { 12 | return `${this.measurement.name} - ${this.metric}`; 13 | } 14 | public get measurementName() { 15 | return this.measurement.name; 16 | } 17 | public get scenarioName() { 18 | return this.measurement.scenarioName; 19 | } 20 | public get scenarioIndex() { 21 | return this.measurement.scenarioIndex; 22 | } 23 | public get hostName() { 24 | return this.measurement.hostName; 25 | } 26 | public get hostIndex() { 27 | return this.measurement.hostIndex; 28 | } 29 | public get metric() { 30 | return this.value.metric; 31 | } 32 | public get metricIndex() { 33 | return this.value.metricIndex; 34 | } 35 | public get samples() { 36 | return this.value.samples; 37 | } 38 | public get mean() { 39 | return this.value.mean; 40 | } 41 | public get minimum() { 42 | return this.value.minimum; 43 | } 44 | public get maximum() { 45 | return this.value.maximum; 46 | } 47 | public get marginOfError() { 48 | return this.value.marginOfError; 49 | } 50 | public get variance() { 51 | return this.value.variance; 52 | } 53 | public get standardDeviation() { 54 | return this.value.standardDeviation; 55 | } 56 | public get relativeMarginOfError() { 57 | return this.value.relativeMarginOfError; 58 | } 59 | public get unit() { 60 | return this.value.unit; 61 | } 62 | public get precision() { 63 | return this.value.precision; 64 | } 65 | public get allSamplesEqual() { 66 | return this.value.allSamplesEqual; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/benchmark/print/console/benchmark.ts: -------------------------------------------------------------------------------- 1 | import { Benchmark, formatMean, formatUnit, MeasurementPivot } from "@ts-perf/api"; 2 | import { Query } from "iterable-query"; 3 | import { Border, Table } from "table-style"; 4 | 5 | import { BenchmarkOptions } from "../../"; 6 | 7 | export function printBenchmark(benchmark: Benchmark, options: BenchmarkOptions, out: NodeJS.WritableStream) { 8 | const measurements = Query 9 | .from(benchmark.measurements) 10 | .flatMap(measurement => measurement.pivot()) 11 | .orderBy(measurement => measurement.scenarioIndex) 12 | .thenBy(measurement => measurement.hostIndex) 13 | .thenBy(measurement => measurement.metricIndex); 14 | 15 | const table = new Table({ 16 | useColor: options.color, 17 | group: [ 18 | { by: x => x.measurementName }, 19 | ], 20 | columns: [ 21 | { header: "Project", key: "metric", expression: x => x.metric }, 22 | { header: "Average", expression: x => formatMean(x), align: "right" }, 23 | { header: "Best", expression: x => x.allSamplesEqual ? "~" : formatUnit(x.minimum, x), align: "right" }, 24 | { header: "Worst", expression: x => x.allSamplesEqual ? "~" : formatUnit(x.maximum, x), align: "right" }, 25 | ], 26 | rowStyles: [ 27 | "*", 28 | { className: "group header", border: Border.single.updateFrom({ top: "double" }) }, 29 | { className: "body", match: (x: MeasurementPivot) => x.metric === "Parse Time", border: { top: "single" } }, 30 | { className: "body", match: (x: MeasurementPivot) => x.metric === "Total Time", border: { top: "single" } }, 31 | { 32 | className: "body", 33 | match: (x: MeasurementPivot) => x.metric === "Errors", 34 | foregroundColor: "dark-gray", 35 | }, 36 | ], 37 | }); 38 | 39 | table.render(measurements, out); 40 | } 41 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/tsserverconfig.ts: -------------------------------------------------------------------------------- 1 | export interface TSServerConfig { 2 | /** 3 | * Name of the solution to be tested, e.g.'xstate'. 4 | */ 5 | solution: string; 6 | commands: TSServerCommands; 7 | } 8 | 9 | type TSServerCommands = [ 10 | TSServerUpdateOpenCommand, 11 | TSServerGeterrCommand, 12 | TSServerReferencesCommand, 13 | TSServerNavtoCommand, 14 | TSServerCompletionInfoCommand, 15 | ...TSServerCommand[], // Extended commands - not part of basic suite 16 | ]; 17 | 18 | interface TSServerCommandBase { 19 | commandName: TSServerCommandName; 20 | args: object; 21 | } 22 | 23 | export type TSServerCommandName = 24 | | "updateOpen" 25 | | "geterr" 26 | | "references" 27 | | "navto" 28 | | "completionInfo"; 29 | 30 | export type TSServerCommand = 31 | | TSServerUpdateOpenCommand 32 | | TSServerGeterrCommand 33 | | TSServerReferencesCommand 34 | | TSServerNavtoCommand 35 | | TSServerCompletionInfoCommand; 36 | 37 | export interface TSServerUpdateOpenCommand extends TSServerCommandBase { 38 | commandName: "updateOpen"; 39 | args: FileArg[]; 40 | } 41 | 42 | export interface TSServerGeterrCommand extends TSServerCommandBase { 43 | commandName: "geterr"; 44 | args: File[]; 45 | } 46 | 47 | export interface TSServerReferencesCommand extends TSServerCommandBase { 48 | commandName: "references"; 49 | args: FilePos; 50 | } 51 | 52 | export interface TSServerNavtoCommand extends TSServerCommandBase { 53 | commandName: "navto"; 54 | args: { 55 | searchValue: string; 56 | }; 57 | } 58 | 59 | export interface TSServerCompletionInfoCommand extends TSServerCommandBase { 60 | commandName: "completionInfo"; 61 | args: FilePos; 62 | } 63 | 64 | type File = string; 65 | interface FileArg { 66 | file: File; 67 | } 68 | interface FilePos { 69 | file: File; 70 | line: number; 71 | /** 72 | * Position's character index into line 73 | */ 74 | offset: number; 75 | } 76 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandMap } from "@ts-perf/api"; 2 | 3 | import * as analyze from "./analyze"; 4 | import * as benchmark from "./benchmark"; 5 | import * as heap from "./heap"; 6 | import * as host from "./host"; 7 | import * as merge from "./merge"; 8 | import * as patch from "./patch"; 9 | import * as profile from "./profile"; 10 | import * as scenario from "./scenario"; 11 | import * as trace from "./trace"; 12 | 13 | export { analyze, AnalyzeOptions } from "./analyze"; 14 | export { benchmark, BenchmarkOptions } from "./benchmark"; 15 | export { heap, HeapProfilerOptions } from "./heap"; 16 | export { 17 | configureHost, 18 | ConfigureHostOptions, 19 | installHost, 20 | InstallHostOptions, 21 | listHosts, 22 | ListHostsOptions, 23 | uninstallHost, 24 | UninstallHostOptions, 25 | } from "./host"; 26 | export { merge, MergeOptions } from "./merge"; 27 | export { patch, PatchOptions } from "./patch"; 28 | export { profile, ProfilerOptions } from "./profile"; 29 | export { 30 | addScenario, 31 | AddScenarioOptions, 32 | configureScenario, 33 | ConfigureScenarioOptions, 34 | deleteScenario, 35 | DeleteScenarioOptions, 36 | ListScenarioOptions, 37 | listScenarios, 38 | } from "./scenario"; 39 | export { trace, TraceOptions } from "./trace"; 40 | 41 | export function activate(commands: CommandMap) { 42 | scenario.registerCommands(commands); 43 | host.registerCommands(commands); 44 | benchmark.registerCommands(commands); 45 | profile.registerCommands(commands); 46 | analyze.registerCommands(commands); 47 | heap.registerCommands(commands); 48 | patch.registerCommands(commands); 49 | trace.registerCommands(commands); 50 | merge.registerCommands(commands); 51 | commands.install = { aliasFor: { command: ["host", "install"] }, visibility: "advanced" }; 52 | commands.uninstall = { aliasFor: { command: ["host", "uninstall"] } }; 53 | commands.config = { aliasFor: { command: ["host", "config"] } }; 54 | } 55 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Comparer, Equaler } from "@esfx/equatable"; 2 | import { StringComparer } from "@ts-perf/core"; 3 | import * as semver from "semver"; 4 | 5 | export class VersionComparer implements Comparer, Equaler { 6 | public static readonly default = new VersionComparer(); 7 | 8 | public compare(x: string, y: string): number; 9 | public compare(x: string | null | undefined, y: string | null | undefined): number; 10 | public compare(x: string | null | undefined, y: string | null | undefined) { 11 | if (x === y) return 0; 12 | if (!x) return -1; 13 | if (!y) return +1; 14 | const xv = semver.validRange(x, /*loose*/ true); 15 | const yv = semver.validRange(y, /*loose*/ true); 16 | return xv && yv ? semver.compare(xv, yv) : StringComparer.caseInsensitiveNumeric.compare(x, y); 17 | } 18 | 19 | public equals(x: string, y: string): boolean; 20 | public equals(x: string | null | undefined, y: string | null | undefined): boolean; 21 | public equals(x: string | null | undefined, y: string | null | undefined) { 22 | if (x === y) return true; 23 | if (!x) return false; 24 | if (!y) return false; 25 | const xv = semver.validRange(x, /*loose*/ true); 26 | const yv = semver.validRange(y, /*loose*/ true); 27 | return xv && yv ? semver.eq(xv, yv) : StringComparer.caseInsensitiveNumeric.equals(x, y); 28 | } 29 | 30 | public hash(x: string): number { 31 | const v = semver.validRange(x, /*loose*/ true); 32 | if (!v) return 0; 33 | return StringComparer.caseInsensitiveNumeric.hash(x); 34 | } 35 | 36 | public satisfies(x: string | null | undefined, y: string | null | undefined) { 37 | if (x === y) return true; 38 | if (!x) return false; 39 | if (!y) return false; 40 | const xv = semver.validRange(x, /*loose*/ true); 41 | const yv = semver.validRange(y, /*loose*/ true); 42 | if (xv === "*") return true; 43 | return xv && yv ? semver.satisfies(xv, yv) : StringComparer.caseInsensitiveNumeric.equals(x, y); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/event.ts: -------------------------------------------------------------------------------- 1 | import { fmt, TimeSpan } from "@ts-perf/api"; 2 | import chalk from "chalk"; 3 | import { from, Lazy } from "iterable-query"; 4 | 5 | import { Table } from "../../decorators"; 6 | import { CpuProfileEvents } from "./events"; 7 | import { CpuProfile } from "./profile"; 8 | 9 | interface TableContext { 10 | readonly hitCount: number; 11 | } 12 | 13 | @Table({ 14 | createContext: ([{ profileEvents: { hitCount } }]) => { 15 | return { hitCount }; 16 | }, 17 | headers: [ 18 | { expression: ({ hitCount }) => `events (total): ${hitCount}` }, 19 | ], 20 | columns: [ 21 | { header: "event", key: "eventName" }, 22 | { 23 | header: "total count", 24 | expression: x => `${x.hitCount} ${fmt.formatPercent(x.hitPercent, { pad: 7, color: chalk.gray })}`, 25 | align: "right", 26 | }, 27 | ], 28 | }) 29 | export class CpuProfileEvent { 30 | readonly profile: CpuProfile; 31 | readonly profileEvents: CpuProfileEvents; 32 | readonly eventName: string; 33 | readonly timestamps: readonly TimeSpan[]; 34 | readonly hitCount: number; 35 | 36 | private _lazyCommonFields = Lazy.from(getCommonFields, this); 37 | 38 | constructor(profileEvents: CpuProfileEvents, eventName: string, timestamps: Iterable) { 39 | this.profileEvents = profileEvents; 40 | this.profile = profileEvents.profile; 41 | this.eventName = eventName; 42 | this.timestamps = from(timestamps).toArray(); 43 | this.hitCount = this.timestamps.length; 44 | } 45 | 46 | get startTime() { 47 | return this._lazyCommonFields.value.startTime; 48 | } 49 | get endTime() { 50 | return this._lazyCommonFields.value.endTime; 51 | } 52 | get hitPercent() { 53 | return this.hitCount / this.profileEvents.hitCount; 54 | } 55 | } 56 | 57 | function getCommonFields(event: CpuProfileEvent) { 58 | const startTime = from(event.timestamps).min() || TimeSpan.NaN; 59 | const endTime = from(event.timestamps).max() || TimeSpan.NaN; 60 | return { startTime, endTime }; 61 | } 62 | -------------------------------------------------------------------------------- /scripts/src/checkLatestCommitForRef.ts: -------------------------------------------------------------------------------- 1 | import assert from "node:assert"; 2 | 3 | import minimist from "minimist"; 4 | import { Octokit } from "octokit"; 5 | 6 | import { getNonEmptyEnv, getRepoInfo, setJobVariable } from "./utils.js"; 7 | 8 | const auth = getNonEmptyEnv("GH_TOKEN"); 9 | 10 | const refPrefix = "refs/"; 11 | 12 | function removeRefPrefix(ref: string) { 13 | assert(ref.startsWith(refPrefix)); 14 | return ref.slice(refPrefix.length); 15 | } 16 | 17 | async function isLatestCommitForRef(ref: string, commit: string) { 18 | const gh = new Octokit({ auth }); 19 | const latest = await gh.rest.git.getRef({ owner: "microsoft", repo: "TypeScript", ref: removeRefPrefix(ref) }); 20 | const isLatest = latest.data.object.sha === commit; 21 | console.log(`Latest commit for ${ref} is: ${latest.data.object.sha}`); 22 | console.log(`This run was for: ${commit}`); 23 | if (isLatest) { 24 | console.log("This is the latest commit for this ref."); 25 | } 26 | else { 27 | console.log("This is not the latest commit for this ref."); 28 | } 29 | return isLatest; 30 | } 31 | 32 | const args = minimist(process.argv.slice(2), { 33 | string: ["builtDir"], 34 | }); 35 | 36 | const info = await getRepoInfo(args.builtDir); 37 | 38 | // If the current commit is the latest for the given ref, then we save it as such. 39 | // This is generally safe because even if we are currently the most recent build for a ref 40 | // and this returns false, then it must be the case that the newer commit will get enqueued 41 | // at some point in the future. 42 | // 43 | // Note that there is a chance that "latest" will lag behind; if we get lots of merges 44 | // in a row and Pipelines happens to run them in order, then each will say "I'm not latest", 45 | // and skip the upload, until the actual latest happens to run. But, anecdotally, Pipelines 46 | // likes to run builds out of order, often with the _newest_ build first, so this should be fine. 47 | // If this turns out not to be fine, we can come up with something fancier, but since we don't 48 | // use baselines to test PRs anymore, it's likely not harmful. 49 | const ref = getNonEmptyEnv("REF"); 50 | const isLatest = await isLatestCommitForRef(ref, info.commit); 51 | 52 | setJobVariable("TSPERF_BLOB_LATEST", isLatest); 53 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/add.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import * as path from "node:path"; 3 | 4 | import { Command, CommandMap, CommonOptions, Scenario } from "@ts-perf/api"; 5 | import { HostContext, localScenariosDirectory } from "@ts-perf/core"; 6 | 7 | export interface AddScenarioOptions extends CommonOptions { 8 | name: string; 9 | args?: string[]; 10 | platforms?: string[]; 11 | default?: boolean; 12 | disabled?: boolean; 13 | } 14 | 15 | export async function addScenario(options: AddScenarioOptions, context: HostContext) { 16 | const scenarioDir = path.resolve( 17 | options.scenarioDir ? options.scenarioDir : localScenariosDirectory, 18 | path.basename(options.name), 19 | ); 20 | if (!fs.existsSync(scenarioDir)) { 21 | await fs.promises.mkdir(scenarioDir, { recursive: true }); 22 | } 23 | 24 | const configFile = path.resolve(scenarioDir, "scenario.json"); 25 | const scenario = Scenario.create({ ...options, kind: "tsc", configFile }); 26 | await scenario.saveAsync(configFile); 27 | 28 | context.info(`Scenario '${scenario.name}' added locally`); 29 | } 30 | 31 | const command: Command = { 32 | commandName: "add", 33 | summary: "Add a local compiler scenario.", 34 | description: "Add a local compiler scenario.", 35 | include: ["common"], 36 | options: { 37 | name: { 38 | type: "string", 39 | longName: "scenario", 40 | alias: ["name"], 41 | required: true, 42 | position: 0, 43 | defaultValue: () => [], 44 | param: "name", 45 | description: "", 46 | }, 47 | args: { 48 | type: "string", 49 | multiple: "comma-separated", 50 | }, 51 | platforms: { 52 | type: "string", 53 | multiple: "comma-separated", 54 | in: ["win32", "linux"], 55 | }, 56 | default: { 57 | type: "boolean", 58 | }, 59 | disabled: { 60 | type: "boolean", 61 | }, 62 | }, 63 | exec: ({ options }, host) => addScenario(options, host), 64 | }; 65 | 66 | export function registerCommands(commands: CommandMap) { 67 | commands.add = command; 68 | } 69 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/positionTickInfoView.ts: -------------------------------------------------------------------------------- 1 | import { fmt } from "@ts-perf/api"; 2 | import chalk from "chalk"; 3 | 4 | import { Table } from "../../decorators"; 5 | import { CpuProfileFunctionView } from "./functionView"; 6 | import { Location } from "./location"; 7 | import { CpuProfileNode } from "./node"; 8 | import { CpuProfile } from "./profile"; 9 | 10 | @Table, {}>({ 11 | createContext: () => ({}), 12 | columns: [ 13 | { 14 | header: "function", 15 | expression: x => `${x.functionName || "(anonymous function)"} ${chalk.gray(`(${x.location})`)}`, 16 | }, 17 | { 18 | header: `time (% of function)`, 19 | expression: x => 20 | `${fmt.formatMilliseconds(x.duration)} ${ 21 | fmt.formatPercent(x.tickPercent, { pad: 7, color: chalk.gray }) 22 | }`, 23 | align: "right", 24 | }, 25 | ], 26 | }) 27 | export class PositionTickInfoView { 28 | readonly profile: CpuProfile; 29 | readonly owner: TOwner; 30 | readonly nodes: readonly CpuProfileNode[]; 31 | readonly ticks: number; 32 | readonly location: Location; 33 | 34 | constructor(owner: TOwner, nodes: readonly CpuProfileNode[], lineNumber: number, ticks: number) { 35 | this.owner = owner; 36 | this.profile = owner.profile; 37 | this.nodes = nodes; 38 | this.ticks = ticks; 39 | this.location = new Location(owner.url, lineNumber); 40 | } 41 | 42 | get duration() { 43 | return this.profile.averageSampleDuration.scale(this.ticks); 44 | } 45 | get functionName() { 46 | return this.nodes[0].functionName; 47 | } 48 | get tickPercent() { 49 | return this.owner.positionTickCount === 0 ? 0 : this.ticks / this.owner.positionTickCount; 50 | } 51 | 52 | // aliases 53 | get name() { 54 | return this.functionName; 55 | } 56 | get url() { 57 | return this.location.url; 58 | } 59 | get lineNumber() { 60 | return this.location.lineNumber; 61 | } 62 | get line() { 63 | return this.location.lineNumber; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/host/configure.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap, Host } from "@ts-perf/api"; 2 | import { HostContext } from "@ts-perf/core"; 3 | 4 | export interface ConfigureHostOptions { 5 | hosts: string[]; 6 | key: string; 7 | value: string; 8 | } 9 | 10 | export async function configureHost(options: ConfigureHostOptions, host: HostContext) { 11 | const logger = host.logger; 12 | const { key, value = "" } = options; 13 | if (key) { 14 | let found = false; 15 | for (const host of await Host.findHosts(options.hosts, { installed: true })) { 16 | found = true; 17 | const updated = host.withPairs([[key, value]]); 18 | if (updated !== host) { 19 | await updated.saveAsync(host.configFile!); 20 | } 21 | } 22 | if (!found) { 23 | logger.warn(`A host matching '${options.hosts}' was not found.`); 24 | } 25 | } 26 | } 27 | 28 | const command: Command = { 29 | commandName: "configure", 30 | alias: ["config"], 31 | summary: "Changes configuration options for hosts.", 32 | description: "Changes configuration options for hosts.", 33 | options: { 34 | hosts: { 35 | type: "string", 36 | longName: "host", 37 | multiple: true, 38 | required: true, 39 | position: 0, 40 | defaultValue: () => [], 41 | param: "host", 42 | description: 43 | "Configures the specified (can be supplied multiple times). A host has the following form:\n [,version=v][,arch=]", 44 | }, 45 | key: { 46 | type: "string", 47 | param: "key", 48 | position: 1, 49 | required: true, 50 | description: "The configuration key.", 51 | }, 52 | value: { 53 | type: "string", 54 | param: "value", 55 | position: 2, 56 | required: true, 57 | description: "The configuration value.", 58 | }, 59 | }, 60 | exec: ({ options }, host) => configureHost(options, host), 61 | }; 62 | 63 | export function registerCommands(commands: CommandMap) { 64 | commands.configure = command; 65 | } 66 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/configure.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap, CommonOptions, Scenario } from "@ts-perf/api"; 2 | import { HostContext } from "@ts-perf/core"; 3 | 4 | export interface ConfigureScenarioOptions extends CommonOptions { 5 | scenarios: string[]; 6 | args?: string[]; 7 | platforms?: string[]; 8 | default?: boolean; 9 | disabled?: boolean; 10 | } 11 | 12 | export async function configureScenario(options: ConfigureScenarioOptions, context: HostContext) { 13 | const scenarios = await Scenario.findScenarios(options.scenarios, { scenarioDir: options.scenarioDir }); 14 | if (scenarios.length === 0) { 15 | context.error(`No matching scenarios.`); 16 | return; 17 | } 18 | 19 | const updated = scenarios.map(scenario => 20 | scenario.with({ 21 | args: options.args, 22 | platforms: options.platforms, 23 | default: options.default, 24 | disabled: options.disabled, 25 | }) 26 | ); 27 | 28 | await Promise.all(updated.map(scenario => scenario.saveAsync(scenario.configFile))); 29 | context.log(`Scenarios updated`); 30 | } 31 | 32 | const command: Command = { 33 | commandName: "configure", 34 | summary: "Configure a scenario.", 35 | description: "Configure a scenario.", 36 | alias: ["config", "common"], 37 | options: { 38 | scenarios: { 39 | type: "string", 40 | longName: "scenario", 41 | required: true, 42 | multiple: true, 43 | position: 0, 44 | defaultValue: () => [], 45 | param: "name", 46 | description: "", 47 | }, 48 | args: { 49 | type: "string", 50 | multiple: "comma-separated", 51 | }, 52 | platforms: { 53 | type: "string", 54 | multiple: "comma-separated", 55 | in: ["win32", "linux"], 56 | }, 57 | default: { 58 | type: "boolean", 59 | }, 60 | disabled: { 61 | type: "boolean", 62 | }, 63 | }, 64 | exec: ({ options }, host) => configureScenario(options, host), 65 | }; 66 | 67 | export function registerCommands(commands: CommandMap) { 68 | commands.configure = command; 69 | } 70 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/measurementComparisonPivot.ts: -------------------------------------------------------------------------------- 1 | import { MeasurementComparison } from "./measurementComparison"; 2 | import { ValueComparison } from "./valueComparison"; 3 | 4 | export class MeasurementComparisonPivot { 5 | constructor( 6 | public readonly measurement: MeasurementComparison, 7 | public readonly value: ValueComparison, 8 | ) { 9 | } 10 | 11 | public get name() { 12 | return `${this.measurementName} - ${this.metric}`; 13 | } 14 | public get measurementName() { 15 | return this.measurement.name; 16 | } 17 | public get scenarioName() { 18 | return this.measurement.scenarioName; 19 | } 20 | public get scenarioIndex() { 21 | return this.measurement.scenarioIndex; 22 | } 23 | public get hostName() { 24 | return this.measurement.hostName; 25 | } 26 | public get hostIndex() { 27 | return this.measurement.hostIndex; 28 | } 29 | public get host() { 30 | return this.measurement.host; 31 | } 32 | public get metric() { 33 | return this.value.metric; 34 | } 35 | public get metricIndex() { 36 | return this.value.metricIndex; 37 | } 38 | public get benchmark() { 39 | return this.value.benchmark; 40 | } 41 | public get benchmarkRelativeDelta() { 42 | return this.value.benchmarkRelativeDelta; 43 | } 44 | public get baseline() { 45 | return this.value.baseline; 46 | } 47 | public get baselineRelativeDelta() { 48 | return this.value.baselineRelativeDelta; 49 | } 50 | public get baselineRelativePValue() { 51 | return this.value.baselineRelativePValue; 52 | } 53 | public get baselineRelativeIsSignificant() { 54 | return this.value.baselineRelativeIsSignificant; 55 | } 56 | public get midline() { 57 | return this.value.midline; 58 | } 59 | public get midlineRelativeDelta() { 60 | return this.value.midlineRelativeDelta; 61 | } 62 | public get midlineRelativePValue() { 63 | return this.value.midlineRelativePValue; 64 | } 65 | public get midlineRelativeIsSignificant() { 66 | return this.value.midlineRelativeIsSignificant; 67 | } 68 | public get worst() { 69 | return this.value.worst; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ts-perf/packages/events/src/index.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from "node:events"; 2 | 3 | export type StrictEventArgTypes = F extends (...args: infer A) => any ? A 4 | : never; 5 | 6 | export type StrictEventsBase = { [P in Extract]: (...args: any[]) => void; }; 7 | 8 | export interface StrictEventEmitter> extends EventEmitter { 9 | addListener( 10 | event: E, 11 | listener: (this: this, ...args: StrictEventArgTypes) => void, 12 | ): this; 13 | addListener(event: never, listener: (...args: any[]) => void): this; 14 | removeListener( 15 | event: E, 16 | listener: (this: this, ...args: StrictEventArgTypes) => void, 17 | ): this; 18 | removeListener(event: never, listener: (...args: any[]) => void): this; 19 | prependListener( 20 | event: E, 21 | listener: (this: this, ...args: StrictEventArgTypes) => void, 22 | ): this; 23 | prependListener(event: never, listener: (...args: any[]) => void): this; 24 | prependOnceListener( 25 | event: E, 26 | listener: (this: this, ...args: StrictEventArgTypes) => void, 27 | ): this; 28 | prependOnceListener(event: never, listener: (...args: any[]) => void): this; 29 | on( 30 | event: E, 31 | listener: (this: this, ...args: StrictEventArgTypes) => void, 32 | ): this; 33 | on(event: never, listener: (...args: any[]) => void): this; 34 | once( 35 | event: E, 36 | listener: (this: this, ...args: StrictEventArgTypes) => void, 37 | ): this; 38 | once(event: never, listener: (...args: any[]) => void): this; 39 | emit(event: E, ...args: StrictEventArgTypes): boolean; 40 | emit(event: never, ...args: any[]): boolean; 41 | listenerCount(event: keyof TEvents): number; 42 | listenerCount(event: never): number; 43 | } 44 | 45 | // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging 46 | export class StrictEventEmitter> extends EventEmitter { 47 | } 48 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/list.ts: -------------------------------------------------------------------------------- 1 | import * as os from "node:os"; 2 | 3 | import { Command, CommandMap, CommonOptions, Scenario } from "@ts-perf/api"; 4 | import { HostContext } from "@ts-perf/core"; 5 | import { Table } from "table-style"; 6 | 7 | export interface ListScenarioOptions extends CommonOptions { 8 | color?: boolean; 9 | } 10 | 11 | export async function listScenarios(options: ListScenarioOptions, context: HostContext) { 12 | const scenarios = await Scenario.getAvailableScenarios({ scenarioDir: options.scenarioDir }); 13 | context.log( 14 | os.EOL + "Scenarios:" + os.EOL + new Table({ 15 | useColor: options.color, 16 | columns: [ 17 | { 18 | header: "Scenario", 19 | expression: x => 20 | `${x.name}${x.isOverriding ? " (OVERRIDING)" : x.isLocal ? " (local)" : ""}${ 21 | x.disabled ? " (disabled)" : x.default ? " (default)" : "" 22 | }`, 23 | }, 24 | { header: "Kind", expression: x => x.kind }, 25 | { header: "Arguments", expression: x => x.args ? x.args.join(" ") : "" }, 26 | { header: "Platform", expression: x => x.platforms ? x.platforms.join(", ") : "" }, 27 | ], 28 | rowStyles: [ 29 | "*", 30 | { match: (x: Scenario) => !!x.disabled, foregroundColor: "dark-gray" }, 31 | { 32 | match: (x: Scenario) => 33 | !!x.platforms && !!x.platforms.length && x.platforms.indexOf(os.platform()) === -1, 34 | foregroundColor: "dark-gray", 35 | }, 36 | ], 37 | }).render(scenarios), 38 | ); 39 | } 40 | 41 | const command: Command = { 42 | commandName: "list", 43 | summary: "List scenarios.", 44 | description: "List Scenarios.", 45 | alias: ["ls"], 46 | include: ["common"], 47 | options: { 48 | color: { 49 | type: "boolean", 50 | defaultValue: true, 51 | description: "Determines whether to print results in color.", 52 | }, 53 | }, 54 | exec: ({ options }, host) => listScenarios(options, host), 55 | }; 56 | 57 | export function registerCommands(commands: CommandMap) { 58 | commands.list = command; 59 | } 60 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/host/install.ts: -------------------------------------------------------------------------------- 1 | import { Command, CommandMap } from "@ts-perf/api"; 2 | import { HostContext } from "@ts-perf/core"; 3 | 4 | import { installMatchingBunHosts } from "./bunInstaller"; 5 | import { installMatchingNodeHosts } from "./nodeInstaller"; 6 | import { installMatchingVSCodeHosts } from "./vscodeInstaller"; 7 | 8 | export interface InstallHostOptions { 9 | hosts: string[]; 10 | sets: string[]; 11 | force?: boolean; 12 | } 13 | 14 | export async function installHost(options: InstallHostOptions, context: HostContext) { 15 | let unmatchedHosts = await installMatchingNodeHosts(options, context); 16 | unmatchedHosts = await installMatchingBunHosts({ ...options, hosts: unmatchedHosts }, context); 17 | unmatchedHosts = await installMatchingVSCodeHosts({ ...options, hosts: unmatchedHosts }, context); 18 | if (unmatchedHosts.length !== 0) { 19 | context.error(`Could not install ${unmatchedHosts.join(", ")}}`); 20 | } 21 | } 22 | 23 | const command: Command = { 24 | commandName: "install", 25 | alias: ["i", "add"], 26 | summary: "Install a test host.", 27 | description: "Installs the specified test host.", 28 | options: { 29 | hosts: { 30 | type: "string", 31 | longName: "host", 32 | multiple: true, 33 | required: true, 34 | position: 0, 35 | defaultValue: () => [], 36 | param: "host", 37 | description: 38 | "Installs the specified (can be supplied multiple times). A host should have the form:\n node@", 39 | }, 40 | sets: { 41 | type: "string", 42 | longName: "config", 43 | multiple: true, 44 | defaultValue: () => [], 45 | param: "entry", 46 | description: 47 | "Sets the value for the specified key/value pair (can be supplied multiple times). An has the form: =", 48 | }, 49 | force: { 50 | type: "boolean", 51 | shortName: "F", 52 | description: "If the remote performance service is locked, forcibly overwrite the lock (requires --ssh).", 53 | }, 54 | }, 55 | lock: true, 56 | exec: ({ options }, host) => installHost(options, host), 57 | }; 58 | 59 | export function registerCommands(commands: CommandMap) { 60 | commands.install = command; 61 | } 62 | -------------------------------------------------------------------------------- /ansible/README.md: -------------------------------------------------------------------------------- 1 | # ansible 2 | 3 | This folder contains the ansible playbooks used to set up perf machines. 4 | 5 | For this ansible playbook to work, you must have added your SSH key to the 6 | remote systems. This can be achieved by using something like: 7 | 8 | ```sh 9 | $ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostname 10 | ``` 11 | 12 | You'll need `inventory.yml`, which should look something like: 13 | 14 | ```yml 15 | tsperf: 16 | children: 17 | pool: 18 | children: 19 | group1: 20 | hosts: 21 | ts-perf1: 22 | ansible_host: 0.0.0.1 23 | ts-perf2: 24 | ansible_host: 0.0.0.2 25 | ts-perf3: 26 | ansible_host: 0.0.0.3 27 | ts-perf4: 28 | ansible_host: 0.0.0.4 29 | vars: 30 | ansible_connection: ssh 31 | ansible_user: someuser 32 | ansible_become_pass: '{{ secret_password }}' 33 | # All machines are identical; I checked "lscpu -e" and chose the values of 34 | # "CPU" on that would free up a single "CORE". 35 | isolated_cpus: '14,15' 36 | # Bless one of the isolated CPUs as the benchmark CPU. 37 | benchmark_cpu: '14' 38 | vars: 39 | azdo_url: https://typescript.visualstudio.com 40 | agent_pool: ts-perf-ddfun 41 | ``` 42 | 43 | Note: ensure that the hostnames are unique, and are added to `benchmark.yml` and `setupPipeline.ts`. 44 | 45 | You'll also need to create `secrets.yml`, which looks like: 46 | 47 | ```yml 48 | secret_azdo_pat: ... 49 | secret_password: ... 50 | ``` 51 | 52 | But with the values plugged in. Make sure to include secrets referenced by `inventory.yml` if needed. 53 | 54 | Some basic usage: 55 | 56 | ```sh 57 | # Get everything set up 58 | $ ansible-playbook -i /path/to/inventory.yml -e @/path/to/secrets.yml setup.yml 59 | 60 | # Force a reconfigure of the agent 61 | $ ansible-playbook -i /path/to/inventory.yml -e @/path/to/secrets.yml setup.yml -e '{"remove_agent": true}' 62 | 63 | # Stop the agent and deconfigure it 64 | $ ansible-playbook -i /path/to/inventory.yml -e @/path/to/secrets.yml setup.yml -e '{"remove_agent": true, "install_agent": false}' 65 | 66 | # Reboot all of the machines 67 | $ ansible-playbook -i /path/to/inventory.yml -e @/path/to/secrets.yml reboot.yml 68 | 69 | # Update all of the machines 70 | $ ansible-playbook -i /path/to/inventory.yml -e @/path/to/secrets.yml update.yml 71 | ``` 72 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/host/uninstall.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import * as path from "node:path"; 3 | 4 | import { Command, CommandMap, Host, HostPattern, HostSpecifier } from "@ts-perf/api"; 5 | import { HostContext } from "@ts-perf/core"; 6 | 7 | export interface UninstallHostOptions { 8 | hosts: string[]; 9 | } 10 | 11 | export async function uninstallHost(options: UninstallHostOptions, host: HostContext) { 12 | const hostPatterns = options.hosts 13 | .map(testHost => HostPattern.parse(testHost)) 14 | .filter(hostPattern => 15 | hostPattern.name === "node" || hostPattern.name === "bun" || hostPattern.name === "vscode" 16 | || host.error(`Unsupported host specification '${hostPattern.name}'.`) 17 | ); 18 | const hosts = await Host.findHosts(hostPatterns, { installed: true }); 19 | await Promise.all(hosts.map(testHost => uninstall(testHost, host))); 20 | } 21 | 22 | async function uninstall(testHost: Host, host: HostContext) { 23 | const dirname = path.dirname(testHost.configFile!); 24 | try { 25 | await fs.promises.rm(dirname, { recursive: true }); 26 | host.log(`Uninstalled '${HostSpecifier.create(testHost)}'.`); 27 | } 28 | catch (e) { 29 | host.error(`Failed to uninstall '${HostSpecifier.create(testHost)}': ${e}`); 30 | } 31 | } 32 | 33 | const command: Command = { 34 | commandName: "uninstall", 35 | alias: ["u", "delete"], 36 | summary: "Uninstall a test host.", 37 | description: "Uninstalls the specified test host.", 38 | options: { 39 | hosts: { 40 | type: "string", 41 | longName: "host", 42 | multiple: true, 43 | required: true, 44 | position: 0, 45 | defaultValue: () => [], 46 | param: "host", 47 | description: 48 | "Uninstalls the specified (can be supplied multiple times). A host has the following form:\n [,version=v][,arch=]", 49 | }, 50 | force: { 51 | type: "boolean", 52 | shortName: "F", 53 | description: "If the remote performance service is locked, forcibly overwrite the lock (requires --ssh).", 54 | }, 55 | }, 56 | lock: true, 57 | exec: ({ options }, host) => uninstallHost(options, host), 58 | }; 59 | 60 | export function registerCommands(commands: CommandMap) { 61 | commands.uninstall = command; 62 | } 63 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/scenario/delete.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import * as path from "node:path"; 3 | 4 | import { Command, CommandMap, CommonOptions, CompilerOptions, Scenario } from "@ts-perf/api"; 5 | import { HostContext } from "@ts-perf/core"; 6 | 7 | export interface DeleteScenarioOptions extends CompilerOptions, CommonOptions { 8 | scenario: string; 9 | recursive?: boolean; 10 | } 11 | 12 | export async function deleteScenario(options: DeleteScenarioOptions, context: HostContext) { 13 | const scenarios = await Scenario.findScenarios([options.scenario], { 14 | scenarioDir: options.scenarioDir, 15 | includeUnsupported: true, 16 | }); 17 | if (scenarios.length === 0) { 18 | context.error(`Scenario '${options.scenario}' not found.`); 19 | return; 20 | } 21 | else if (scenarios.length > 1) { 22 | context.error(`Multiple scenarios for '${options.scenario}' were found.`); 23 | return; 24 | } 25 | 26 | const scenario = scenarios[0]; 27 | if (!scenario.configFile) { 28 | context.error(`Scenario '${scenario.name}' is built-in and cannot be deleted.`); 29 | return; 30 | } 31 | 32 | const configFile = path.resolve(scenario.configFile); 33 | if (!fs.existsSync(configFile)) { 34 | context.error(`'${configFile}' not found.`); 35 | return; 36 | } 37 | 38 | const configDir = path.dirname(configFile); 39 | await fs.promises.unlink(scenario.configFile); 40 | 41 | try { 42 | await fs.promises.rm(configDir, { recursive: options.recursive }); 43 | } 44 | catch (e) { 45 | if (options.recursive) { 46 | throw e; 47 | } 48 | } 49 | 50 | context.info(`Scenario '${scenario.name}' deleted.`); 51 | } 52 | 53 | const command: Command = { 54 | commandName: "delete", 55 | summary: "Delete a scenario.", 56 | description: "Delete a scenario.", 57 | alias: ["rm"], 58 | include: ["common"], 59 | options: { 60 | scenario: { 61 | type: "string", 62 | longName: "scenario", 63 | required: true, 64 | position: 0, 65 | defaultValue: () => [], 66 | param: "name", 67 | description: "", 68 | }, 69 | recursive: { 70 | type: "boolean", 71 | }, 72 | }, 73 | exec: ({ options }, host) => deleteScenario(options, host), 74 | }; 75 | 76 | export function registerCommands(commands: CommandMap) { 77 | commands.delete = command; 78 | } 79 | -------------------------------------------------------------------------------- /scripts/src/utils.ts: -------------------------------------------------------------------------------- 1 | import assert from "node:assert"; 2 | import fs from "node:fs"; 3 | import path from "node:path"; 4 | 5 | import * as v from "@badrap/valita"; 6 | import { $ as _$ } from "execa"; 7 | 8 | export const $pipe = _$({ verbose: "short" }); 9 | export const $ = _$({ verbose: "short", stdio: "inherit" }); 10 | 11 | const RepoInfo = v.object({ 12 | commit: v.string(), 13 | commitShort: v.string(), 14 | branch: v.string().optional(), 15 | date: v.string(), 16 | timestampDir: v.string(), 17 | }); 18 | export type RepoInfo = v.Infer; 19 | 20 | export async function retry(fn: () => Promise, count = 3, wait = 5) { 21 | let lastError; 22 | 23 | while (count > 0) { 24 | count--; 25 | try { 26 | return await fn(); 27 | } 28 | catch (e) { 29 | console.error(e); 30 | lastError = e; 31 | if (count === 0) { 32 | break; 33 | } 34 | await sleepSeconds(wait); 35 | } 36 | } 37 | 38 | throw lastError; 39 | } 40 | 41 | /** 42 | * @param {number} seconds 43 | */ 44 | export function sleepSeconds(seconds: number) { 45 | return new Promise(resolve => setTimeout(resolve, seconds * 1000)); 46 | } 47 | 48 | export function checkNonEmpty(x: T | undefined, message: string): T { 49 | assert(x, message); 50 | return x; 51 | } 52 | 53 | export function getNonEmptyEnv(name: string) { 54 | const value = process.env[name]; 55 | assert(value, `Expected ${name} environment variable to be set`); 56 | return value; 57 | } 58 | 59 | export async function getRepoInfo(builtDir: string) { 60 | assert(builtDir, "Expected non-empty builtDir"); 61 | const repoInfoPath = path.join(builtDir, "info.json"); 62 | const parsed = JSON.parse(await fs.promises.readFile(repoInfoPath, { encoding: "utf8" })); 63 | return RepoInfo.parse(parsed); 64 | } 65 | 66 | export function setOutputVariable(name: string, value: string | number | boolean) { 67 | console.log(`setting output ${name}=${value}`); 68 | console.log(`##vso[task.setvariable variable=${name};isOutput=true]${value}`); 69 | } 70 | 71 | export function setJobVariable(name: string, value: string | number | boolean) { 72 | console.log(`setting variable ${name}=${value}`); 73 | console.log(`##vso[task.setvariable variable=${name}]${value}`); 74 | } 75 | 76 | export function parseBoolean(value: string | undefined, defaultValue: boolean): boolean { 77 | if (!value) return defaultValue; 78 | return value.toUpperCase() === "TRUE"; 79 | } 80 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/utest.ts: -------------------------------------------------------------------------------- 1 | import cdf from "@stdlib/stats-base-dists-normal-cdf"; 2 | 3 | // This function returns the p-value determined by the two-sided Mann-Whitney U-Test, 4 | // via the normal approximation. 5 | // Emperically, its behavior matches scipy's scipy.stats.mannwhitneyu function (though 6 | // implemented differently). 7 | // https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test 8 | // https://sphweb.bumc.bu.edu/otlt/mph-modules/bs/bs704_nonparametric/bs704_nonparametric4.html 9 | export function utest(x1: readonly number[], x2: readonly number[]): number { 10 | function toLabeled(x: readonly number[], label: "x1" | "x2") { 11 | return x.map(x => ({ x, label })); 12 | } 13 | 14 | const all = toLabeled(x1, "x1").concat(toLabeled(x2, "x2")).sort((a, b) => a.x - b.x); 15 | 16 | const rankSums = { x1: 0, x2: 0 }; 17 | // This is Σ_j (t_j³ - t_j) in https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test#Normal_approximation_and_tie_correction 18 | let tieCorrection = 0; 19 | 20 | for (let i = 0; i < all.length;) { 21 | const curr = all[i]; 22 | i++; 23 | 24 | const rankCounts = { x1: 0, x2: 0 }; 25 | rankCounts[curr.label]++; 26 | 27 | // Find ties 28 | const firstRank = i; 29 | while (i < all.length) { 30 | const next = all[i]; 31 | if (next.x !== curr.x) { 32 | break; 33 | } 34 | 35 | rankCounts[next.label]++; 36 | i++; 37 | } 38 | const lastRank = i; 39 | 40 | const rank = (lastRank + firstRank) / 2; 41 | rankSums.x1 += rankCounts.x1 * rank; 42 | rankSums.x2 += rankCounts.x2 * rank; 43 | 44 | const t = lastRank - firstRank + 1; 45 | if (t > 1) { 46 | tieCorrection += t * t * t - t; 47 | } 48 | } 49 | 50 | const n1 = x1.length; 51 | const n2 = x2.length; 52 | const n = n1 + n2; 53 | 54 | const R1 = rankSums.x1; 55 | const U1 = n1 * n2 + (n1 * (n1 + 1)) / 2 - R1; 56 | const U2 = n1 * n2 - U1; // Simplified, as n1*n2 = U1 + U2. 57 | const U = Math.max(U1, U2); 58 | 59 | const m_U = n1 * n2 / 2; 60 | const sigma_U = Math.sqrt(((n1 * n2) / 12) * ((n + 1) - tieCorrection / (n * (n - 1)))); 61 | 62 | // 0.5 is the "continuity correction" (see the docs on https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mannwhitneyu.html) 63 | const z = (U - m_U - 0.5) / sigma_U; 64 | 65 | let pValue = 2 * (1 - cdf(z, 0, 1)); // Multiply by 2; two-sided test. 66 | pValue = Math.max(0, pValue); 67 | pValue = Math.min(1, pValue); 68 | return pValue; 69 | } 70 | -------------------------------------------------------------------------------- /ts-perf/packages/profiler/src/commands/heapProfiler.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import * as path from "node:path"; 3 | 4 | import { HeapProfiler, Runtime, Session } from "@ts-perf/inspector"; 5 | 6 | import { Executable } from "../executable"; 7 | 8 | export interface HeapOptions { 9 | args: string[]; 10 | out: string; 11 | events: string[]; 12 | } 13 | 14 | export async function heapProfile(options: HeapOptions) { 15 | const events = new Set(options.events); 16 | const pendingActions: Promise[] = []; 17 | let tracking = false; 18 | let takingSnapshot = false; 19 | 20 | // setup profiler 21 | const session = new Session(); 22 | const compiler = new Executable(options.args); 23 | const heapProfiler = new HeapProfiler(session); 24 | const runtime = new Runtime(session); 25 | 26 | session.connect(); 27 | await runtime.addBinding("onProfilerEvent"); 28 | await heapProfiler.enable(); 29 | 30 | runtime.on("bindingCalled", ({ name, payload }) => { 31 | if (name === "onProfilerEvent" && tracking && !takingSnapshot && events.has(payload)) { 32 | takingSnapshot = true; 33 | pendingActions.push(takeSnapshot(payload)); 34 | } 35 | }); 36 | 37 | await heapProfiler.startTrackingHeapObjects(); 38 | 39 | tracking = true; 40 | await compiler.exec(); 41 | tracking = false; 42 | 43 | pendingActions.push( 44 | options.events 45 | ? heapProfiler.stopTrackingHeapObjects() 46 | : heapProfiler.stopTrackingHeapObjects(fs.createWriteStream(getSnapshotName(), "utf8"), { end: true }), 47 | ); 48 | 49 | await Promise.all(pendingActions); 50 | 51 | // tear down profiler 52 | await heapProfiler.disable(); 53 | session.disconnect(); 54 | 55 | function getSnapshotName(eventName?: string) { 56 | const extname = path.extname(options.out); 57 | if (eventName) { 58 | const basename = path.basename(options.out, extname); 59 | const dirname = path.dirname(options.out); 60 | return path.join( 61 | dirname, 62 | extname 63 | ? basename + "." + eventName + extname 64 | : basename + "." + eventName + ".heapsnapshot", 65 | ); 66 | } 67 | else { 68 | return extname 69 | ? options.out 70 | : options.out + ".heapsnapshot"; 71 | } 72 | } 73 | 74 | async function takeSnapshot(eventName: string) { 75 | takingSnapshot = true; 76 | await heapProfiler.takeHeapSnapshot(fs.createWriteStream(getSnapshotName(eventName), "utf8"), { end: true }); 77 | takingSnapshot = false; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # typescript-benchmarking 2 | 3 | This repo contains the infrastructure for TypeScript's benchmarking system, including build scripts 4 | and the `ts-perf` CLI tool. 5 | 6 | ## Adding a benchmark 7 | 8 | Public benchmarks are stored in the `cases` directory. 9 | 10 | The simplest thing to do is to copy another benchmark; `cases/scenarios/vscode` is a good template. 11 | 12 | Each benchmark consists of: 13 | 14 | - `cases/scenarios//scenario.json` - This is JSON file which describes what `ts-perf` will run. 15 | - `cases/scenarios//setup.sh` - This is an optional script that CI will run before benchmarking for setting up the benchmark. 16 | This is where you would clone repos, install dependencies, etc, whatever is needed to run `tsc`. 17 | - `cases/solutions/` (or an ignored dir of the same name in `cases/solutions/.gitignore`) - This is where the source code for the benchmark is stored. 18 | This may be code that's checked in the repo, but preferably the directory is `.gitignore`'d and `setup.sh` script clones code here. 19 | 20 | After these files are created, they must be added to `scenarioConfig` in `scripts/src/setupPipeline.ts` to be run in CI. 21 | 22 | > [!NOTE] 23 | > Benchmark capacity is limited; we may not accept all benchmarks or run them automatically in CI. 24 | 25 | ## Contributing 26 | 27 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 28 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 29 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 30 | 31 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 32 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 33 | provided by the bot. You will only need to do this once across all repos using our CLA. 34 | 35 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 36 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 37 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 38 | 39 | ## Trademarks 40 | 41 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 42 | trademarks or logos is subject to and must follow 43 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 44 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 45 | Any use of third-party trademarks or logos are subject to those third-party's policies. 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | 132 | **/.vscode/* 133 | !**/.vscode/tasks.json 134 | !**/.vscode/settings.template.json 135 | !**/.vscode/launch.template.json 136 | !**/.vscode/extensions.json 137 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster predictable host=node@18.5.1/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"tsc_node_18_5_1_Compiler_Unions":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_Compiler_Unions","TSPERF_JOB_SCENARIO":"Compiler-Unions","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_angular_1":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_angular_1","TSPERF_JOB_SCENARIO":"angular-1","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_mui_docs":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_mui_docs","TSPERF_JOB_SCENARIO":"mui-docs","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_self_build_src":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_self_build_src","TSPERF_JOB_SCENARIO":"self-build-src","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_self_build_src_public_api":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_self_build_src_public_api","TSPERF_JOB_SCENARIO":"self-build-src-public-api","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_self_compiler":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_self_compiler","TSPERF_JOB_SCENARIO":"self-compiler","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_ts_pre_modules":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_ts_pre_modules","TSPERF_JOB_SCENARIO":"ts-pre-modules","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_vscode":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_vscode","TSPERF_JOB_SCENARIO":"vscode","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_webpack":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_webpack","TSPERF_JOB_SCENARIO":"webpack","TSPERF_JOB_WARMUPS":1},"tsc_node_18_5_1_xstate_main":{"TSPERF_JOB_HOST":"node@18.5.1","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_5_1_xstate_main","TSPERF_JOB_SCENARIO":"xstate-main","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "true", 22 | "TSPERF_PROCESS_KINDS": "tsc", 23 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"tsc_node_18_15_0_Compiler_Unions":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_Compiler_Unions","TSPERF_JOB_SCENARIO":"Compiler-Unions","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_angular_1":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_angular_1","TSPERF_JOB_SCENARIO":"angular-1","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_mui_docs":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_mui_docs","TSPERF_JOB_SCENARIO":"mui-docs","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src","TSPERF_JOB_SCENARIO":"self-build-src","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src_public_api":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src_public_api","TSPERF_JOB_SCENARIO":"self-build-src-public-api","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_compiler":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_compiler","TSPERF_JOB_SCENARIO":"self-compiler","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_ts_pre_modules":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_ts_pre_modules","TSPERF_JOB_SCENARIO":"ts-pre-modules","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_vscode":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_vscode","TSPERF_JOB_SCENARIO":"vscode","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_webpack":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_webpack","TSPERF_JOB_SCENARIO":"webpack","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_xstate_main":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_xstate_main","TSPERF_JOB_SCENARIO":"xstate-main","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "tsc", 23 | } -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/tsc-only/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"tsc_node_18_15_0_Compiler_Unions":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_Compiler_Unions","TSPERF_JOB_SCENARIO":"Compiler-Unions","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_angular_1":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_angular_1","TSPERF_JOB_SCENARIO":"angular-1","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_mui_docs":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_mui_docs","TSPERF_JOB_SCENARIO":"mui-docs","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src","TSPERF_JOB_SCENARIO":"self-build-src","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src_public_api":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src_public_api","TSPERF_JOB_SCENARIO":"self-build-src-public-api","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_compiler":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_compiler","TSPERF_JOB_SCENARIO":"self-compiler","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_ts_pre_modules":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_ts_pre_modules","TSPERF_JOB_SCENARIO":"ts-pre-modules","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_vscode":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_vscode","TSPERF_JOB_SCENARIO":"vscode","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_webpack":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_webpack","TSPERF_JOB_SCENARIO":"webpack","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_xstate_main":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_xstate_main","TSPERF_JOB_SCENARIO":"xstate-main","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "HEAD^1", 16 | "TSPERF_BASELINE_NAME": "baseline", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "false", 19 | "TSPERF_NEW_COMMIT": "HEAD", 20 | "TSPERF_NEW_NAME": "pr", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "tsc", 23 | } -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/hostPattern.ts: -------------------------------------------------------------------------------- 1 | import { StringComparer } from "@ts-perf/core"; 2 | 3 | import { VersionComparer } from "../utils"; 4 | import { 5 | formatHostComponents, 6 | HostSpecifierComponents, 7 | parseHostComponents, 8 | pickHostComponents, 9 | } from "./hostSpecifierComponents"; 10 | 11 | const invalidHostPatternRegExp = /[,;=]/; 12 | 13 | export class HostPattern { 14 | public readonly name: string; 15 | public readonly version: string; 16 | public readonly arch: string; 17 | public readonly executable: string; 18 | 19 | constructor(name?: string, version?: string, arch?: string, executable?: string) { 20 | if (name && invalidHostPatternRegExp.test(name)) throw new Error("invalid argument: name"); 21 | if (version && invalidHostPatternRegExp.test(version)) throw new Error("invalid argument: version"); 22 | if (arch && invalidHostPatternRegExp.test(arch)) throw new Error("invalid argument: arch"); 23 | this.name = name || "*"; 24 | this.version = version || "*"; 25 | this.arch = arch || "*"; 26 | this.executable = executable || "*"; 27 | } 28 | 29 | public with(components: HostSpecifierComponents) { 30 | const { name = this.name, version = this.version, arch = this.arch, executable = this.executable } = components; 31 | if (name === this.name && version === this.version && arch === this.arch && executable === this.executable) { 32 | return this; 33 | } 34 | return new HostPattern(name || "*", version || "*", arch || "*", executable || "*"); 35 | } 36 | 37 | public getComponents() { 38 | return pickHostComponents(this); 39 | } 40 | 41 | public toString() { 42 | return formatHostComponents(this); 43 | } 44 | 45 | public toJSON(): any { 46 | return pickHostComponents(this); 47 | } 48 | 49 | public match(components: HostSpecifierComponents) { 50 | return (this.name === "*" || StringComparer.caseInsensitive.equals(this.name, components.name)) 51 | && (this.version === "*" || VersionComparer.default.satisfies(components.version, this.version)) 52 | && (this.arch === "*" || StringComparer.caseInsensitive.equals(this.arch, components.arch)) 53 | && (this.executable === "*" || StringComparer.fileSystem.equals(this.executable, components.executable)); 54 | } 55 | 56 | public partialMatch(components: HostSpecifierComponents) { 57 | return this.match({ ...this.getComponents(), ...components }); 58 | } 59 | 60 | public static create(components: HostSpecifierComponents) { 61 | if (components instanceof HostPattern) { 62 | return components; 63 | } 64 | 65 | const { name, version, arch, executable } = components; 66 | return new HostPattern(name!, version!, arch!, executable!); 67 | } 68 | 69 | public static parse(host: string): HostPattern { 70 | return this.create(parseHostComponents(host)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/benchmarkComparison.ts: -------------------------------------------------------------------------------- 1 | import { Query } from "iterable-query"; 2 | 3 | import { Benchmark, BenchmarkComponents } from "./benchmark"; 4 | import { Measurement } from "./measurement"; 5 | import { MeasurementComparison } from "./measurementComparison"; 6 | 7 | export interface BenchmarkComparisonComponents { 8 | benchmark: Benchmark | BenchmarkComponents; 9 | baseline?: Benchmark | BenchmarkComponents; 10 | midline?: Benchmark | BenchmarkComponents; 11 | } 12 | 13 | export class BenchmarkComparison { 14 | public readonly measurements: readonly MeasurementComparison[]; 15 | 16 | constructor( 17 | public readonly benchmark: Benchmark, 18 | public readonly baseline: Benchmark | undefined, 19 | public readonly midline: Benchmark | undefined, 20 | ) { 21 | this.measurements = Query 22 | .from(benchmark.measurements) 23 | .fullJoin( 24 | baseline ? baseline.measurements : [], 25 | x => x.name, 26 | x => x.name, 27 | (benchmark, baseline) => ({ benchmark, baseline }), 28 | ) 29 | .fullJoin( 30 | midline ? midline.measurements : [], 31 | ({ benchmark }) => benchmark && benchmark.name, 32 | x => x.name, 33 | (left, midline) => ({ benchmark: left && left.benchmark, baseline: left && left.baseline, midline }), 34 | ) 35 | .select(({ benchmark, baseline, midline }) => Measurement.diff(benchmark, baseline, midline)!) 36 | .where((diff: MeasurementComparison | undefined): diff is MeasurementComparison => diff !== undefined) 37 | .orderBy(scenario => scenario.scenarioName) 38 | .thenBy(scenario => scenario.hostName) 39 | .toArray(); 40 | } 41 | 42 | public static create(components: BenchmarkComparisonComponents) { 43 | return components instanceof BenchmarkComparison ? components : new BenchmarkComparison( 44 | Benchmark.create(components.benchmark), 45 | components.baseline && Benchmark.create(components.baseline), 46 | components.midline && Benchmark.create(components.midline), 47 | ); 48 | } 49 | 50 | public getComponents(): BenchmarkComparisonComponents { 51 | return { 52 | benchmark: this.benchmark, 53 | baseline: this.baseline, 54 | midline: this.midline, 55 | }; 56 | } 57 | 58 | public with(components: Partial) { 59 | const { benchmark = this.benchmark } = components; 60 | const { baseline = this.baseline } = components; 61 | const { midline = this.midline } = components; 62 | 63 | if ( 64 | benchmark === this.benchmark 65 | && baseline === this.baseline 66 | && midline === this.midline 67 | ) { 68 | return this; 69 | } 70 | 71 | return BenchmarkComparison.create({ benchmark, baseline, midline }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/lineTick.ts: -------------------------------------------------------------------------------- 1 | // import { Lazy, from } from "iterable-query"; 2 | // import { PositionTickInfo } from "@ts-perf/inspector"; 3 | // import { CpuProfile } from "./profile"; 4 | // import { CpuProfileNode } from "./node"; 5 | // import { TimeSpan, formatPercent, padLeft } from "@ts-perf/api"; 6 | // import { Table } from "../../decorators"; 7 | // import chalk = require("chalk"); 8 | // import { Location } from "./location"; 9 | 10 | // interface CpuProfileLineTickTableContext { 11 | // readonly profile: CpuProfile; 12 | // readonly hitCount: number; 13 | // readonly duration: TimeSpan; 14 | // } 15 | 16 | // @Table({ 17 | // createContext: values => { 18 | // const profile = values[0].profile; 19 | // const hitCount = from(values).sum(node => node.ticks); 20 | // const duration = profile.averageSampleDuration.scale(hitCount); 21 | // return { profile, hitCount, duration }; 22 | // }, 23 | // headers: [ 24 | // { expression: ({ profile }) => `duration (total): ${profile.duration.totalMilliseconds.toFixed(1)} ms, ${profile.totalCount} samples` }, 25 | // { expression: ({ profile, hitCount, duration }) => `duration (selection): ${duration.totalMilliseconds.toFixed(1)} ms, ${hitCount} samples ${chalk.gray(`(${formatPercent(hitCount / profile.totalCount)} of total)`)}` } 26 | // ], 27 | // group: [ 28 | // { by: x => `${x.node.functionName || `(anonymous function)`} ${chalk.gray(`(${x.node.location})`)}` } 29 | // ], 30 | // columns: [ 31 | // { header: "line", 32 | // expression: x => x.location }, 33 | // // { header: "function ticks", 34 | // // expression: x => `${x.ticks} ${padLeft(chalk.gray(formatPercent(x.ticks / x.node.lineTickCount)), 7)}`, 35 | // // align: "right" }, 36 | // { header: "self time", 37 | // expression: (x, _, { hitCount }) => `${x.duration.totalMilliseconds.toFixed(1)} ms ${padLeft(chalk.gray(formatPercent(x.ticks / hitCount)), 7)}`, 38 | // align: "right" }, 39 | // ] 40 | // }) 41 | // export class CpuProfileLineTick { 42 | // readonly json: PositionTickInfo; 43 | // readonly profile: CpuProfile; 44 | // readonly node: CpuProfileNode; 45 | // readonly lineNumber: number; 46 | // readonly ticks: number; 47 | // readonly location: Location; 48 | 49 | // private _lazyDuration = Lazy.from(getDuration, this); 50 | 51 | // constructor(node: CpuProfileNode, json: PositionTickInfo) { 52 | // this.json = json; 53 | // this.node = node; 54 | // this.profile = node.profile; 55 | // this.lineNumber = json.line; 56 | // this.ticks = json.ticks; 57 | // this.location = new Location(node.location.url, this.lineNumber); 58 | // } 59 | 60 | // get duration() { return this._lazyDuration.value; } 61 | // } 62 | 63 | // function getDuration(line: CpuProfileLineTick) { 64 | // return line.profile.averageSampleDuration.scale(line.ticks); 65 | // } 66 | -------------------------------------------------------------------------------- /scripts/src/__tests__/__file_snapshots__/setupPipeline/faster commits=release-5.3...release-5.4/outputVariables.snap: -------------------------------------------------------------------------------- 1 | { 2 | "MATRIX_any": "{"tsc_node_18_15_0_Compiler_Unions":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_Compiler_Unions","TSPERF_JOB_SCENARIO":"Compiler-Unions","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_angular_1":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_angular_1","TSPERF_JOB_SCENARIO":"angular-1","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_mui_docs":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_mui_docs","TSPERF_JOB_SCENARIO":"mui-docs","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src","TSPERF_JOB_SCENARIO":"self-build-src","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_build_src_public_api":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_build_src_public_api","TSPERF_JOB_SCENARIO":"self-build-src-public-api","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_self_compiler":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_self_compiler","TSPERF_JOB_SCENARIO":"self-compiler","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_ts_pre_modules":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_ts_pre_modules","TSPERF_JOB_SCENARIO":"ts-pre-modules","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_vscode":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_vscode","TSPERF_JOB_SCENARIO":"vscode","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_webpack":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_webpack","TSPERF_JOB_SCENARIO":"webpack","TSPERF_JOB_WARMUPS":1},"tsc_node_18_15_0_xstate_main":{"TSPERF_JOB_HOST":"node@18.15.0","TSPERF_JOB_ITERATIONS":6,"TSPERF_JOB_KIND":"tsc","TSPERF_JOB_NAME":"tsc_node_18_15_0_xstate_main","TSPERF_JOB_SCENARIO":"xstate-main","TSPERF_JOB_WARMUPS":1}}", 3 | "MATRIX_ts_perf1": "{}", 4 | "MATRIX_ts_perf10": "{}", 5 | "MATRIX_ts_perf11": "{}", 6 | "MATRIX_ts_perf12": "{}", 7 | "MATRIX_ts_perf2": "{}", 8 | "MATRIX_ts_perf3": "{}", 9 | "MATRIX_ts_perf4": "{}", 10 | "MATRIX_ts_perf5": "{}", 11 | "MATRIX_ts_perf6": "{}", 12 | "MATRIX_ts_perf7": "{}", 13 | "MATRIX_ts_perf8": "{}", 14 | "MATRIX_ts_perf9": "{}", 15 | "TSPERF_BASELINE_COMMIT": "27047e3391323fa2d8987f46a4c42f5361d07926", 16 | "TSPERF_BASELINE_NAME": "release-5.3", 17 | "TSPERF_IS_COMPARISON": "true", 18 | "TSPERF_IS_CUSTOM_COMMIT_RANGE": "true", 19 | "TSPERF_NEW_COMMIT": "6ea273cdcca99db809074d2b2d38d0e5b59ee81b", 20 | "TSPERF_NEW_NAME": "release-5.4", 21 | "TSPERF_PREDICTABLE": "false", 22 | "TSPERF_PROCESS_KINDS": "tsc", 23 | } -------------------------------------------------------------------------------- /scripts/src/buildTypeScript.ts: -------------------------------------------------------------------------------- 1 | import assert from "node:assert"; 2 | import fs from "node:fs"; 3 | import path from "node:path"; 4 | 5 | import minimist from "minimist"; 6 | import { Octokit } from "octokit"; 7 | 8 | import { $, $pipe, getNonEmptyEnv, parseBoolean, RepoInfo, retry, setOutputVariable } from "./utils.js"; 9 | 10 | const { stdout: commit } = await $pipe`git rev-parse HEAD`; 11 | const { stdout: commitShort } = await $pipe`git rev-parse --short HEAD`; 12 | const { stdout: date } = await $pipe`git log -1 --format=%cI`; 13 | const { stdout: timestampDir } = await $pipe`date -d ${date} -u +%Y/%m/%d`; 14 | 15 | const args = minimist(process.argv.slice(2), { 16 | string: ["outputDir"], 17 | boolean: ["baseline"], 18 | }); 19 | 20 | const outputDir = args.outputDir; 21 | assert(outputDir, "Expected output path as first argument"); 22 | 23 | const packageJson = await fs.promises.readFile("package.json", "utf8"); 24 | assert(JSON.parse(packageJson).name === "typescript", "Expected to be run from the TypeScript repo"); 25 | 26 | await $`mkdir -p ${path.dirname(outputDir)}`; 27 | 28 | await retry(() => $`npm ci`); 29 | 30 | if (fs.existsSync("Herebyfile.mjs")) { 31 | await $`npx hereby lkg`; 32 | await $`mv lib ${outputDir}`; 33 | } 34 | else { 35 | await $`npm run build:compiler`; 36 | await $`mv built/local ${outputDir}`; 37 | } 38 | 39 | await $`git clean -fddx`; 40 | await $`git reset --hard HEAD`; 41 | 42 | let branch: string | undefined; 43 | 44 | const isPR = parseBoolean(getNonEmptyEnv("IS_PR"), false); 45 | const ref = getNonEmptyEnv("REF"); 46 | const isCustomCommitRange = parseBoolean(getNonEmptyEnv("TSPERF_IS_CUSTOM_COMMIT_RANGE"), false); 47 | 48 | // If this is a custom commit range, don't bother trying to figure out what the branch names are. 49 | if (!isCustomCommitRange) { 50 | if (isPR) { 51 | // This is a PR run. Pull the branch info from the PR. 52 | const prefix = "refs/pull/"; 53 | assert(ref.startsWith(prefix), `Expected ref to start with ${prefix}`); 54 | 55 | if (args.baseline) { 56 | const prNumber = ref.slice(prefix.length).split("/")[0]; 57 | 58 | const octokit = new Octokit(); 59 | const pr = await octokit.rest.pulls.get({ 60 | owner: "microsoft", 61 | repo: "TypeScript", 62 | pull_number: +prNumber, 63 | }); 64 | branch = pr.data.base.ref; 65 | } 66 | else { 67 | branch = ref; 68 | } 69 | } 70 | else { 71 | const prefix = "refs/heads/"; 72 | assert(ref.startsWith(prefix), `Expected ref to start with ${prefix}`); 73 | branch = ref.slice(prefix.length); 74 | } 75 | } 76 | 77 | const info: RepoInfo = { 78 | commit, 79 | commitShort, 80 | branch, 81 | date, 82 | timestampDir, 83 | }; 84 | 85 | const outputInfoPath = path.join(outputDir, "info.json"); 86 | const outputInfo = JSON.stringify(info, undefined, 4); 87 | 88 | console.log(`Writing ${outputInfoPath} with contents:\n${outputInfo}}`); 89 | await fs.promises.writeFile(outputInfoPath, outputInfo); 90 | 91 | setOutputVariable("TYPESCRIPT_COMMIT", commit); 92 | -------------------------------------------------------------------------------- /ts-perf/packages/cli/src/index.ts: -------------------------------------------------------------------------------- 1 | import "source-map-support/register"; 2 | 3 | import { CompilerOptions, discoverCommands, optionSets } from "@ts-perf/api"; 4 | import { HostContext, Logger, LogLevel, ProcessExitError } from "@ts-perf/core"; 5 | import { CommandLine, ParsedCommandLine } from "power-options"; 6 | 7 | const logger = new Logger(LogLevel.Info, { out: process.stdout, err: process.stderr }); 8 | const host = new HostContext(logger); 9 | const commandLine = new CommandLine({ 10 | package: true, 11 | color: true, 12 | auto: true, 13 | container: true, 14 | commands: discoverCommands(), 15 | optionSets, 16 | options: { 17 | // CLI options 18 | quiet: { 19 | type: "boolean", 20 | shortName: "q", 21 | description: "Only prints minimal output information.", 22 | aliasFor: ["--log-level", "quiet"], 23 | }, 24 | verbose: { 25 | type: "boolean", 26 | shortName: "v", 27 | description: "Prints detailed diagnostic information.", 28 | aliasFor: ["--log-level", "verbose"], 29 | }, 30 | logLevel: { 31 | longName: "log-level", 32 | description: "Sets the diagnostics level, either 'quiet', 'info' (default), or 'verbose'.", 33 | param: "level", 34 | type: "number", 35 | alias: "level", 36 | visibility: "advanced", 37 | map: { 38 | off: LogLevel.Off, 39 | error: LogLevel.Error, 40 | warning: LogLevel.Warning, 41 | info: LogLevel.Info, 42 | verbose: LogLevel.Verbose, 43 | 44 | none: LogLevel.Off, 45 | quiet: LogLevel.Error, 46 | warn: LogLevel.Warning, 47 | 48 | [LogLevel.Off]: LogLevel.Off, 49 | [LogLevel.Error]: LogLevel.Error, 50 | [LogLevel.Warning]: LogLevel.Warning, 51 | [LogLevel.Info]: LogLevel.Info, 52 | [LogLevel.Verbose]: LogLevel.Verbose, 53 | }, 54 | defaultValue: LogLevel.Info, 55 | }, 56 | }, 57 | preExec: async (parsed: ParsedCommandLine, host: HostContext) => { 58 | const options = parsed.options; 59 | 60 | // update the log level 61 | host.logger.level = options.logLevel; 62 | 63 | if (parsed.help || parsed.error || !parsed.command || !parsed.commandPath) return; 64 | }, 65 | }); 66 | 67 | async function main(args: string[]) { 68 | try { 69 | const result = await commandLine.parseAndExecute(args, host); 70 | if (!result.handled) { 71 | throw new Error(`Command '${result.commandPath && result.commandPath.join(" ")}' was unhandled.`); 72 | } 73 | } 74 | catch (e) { 75 | if (e instanceof ProcessExitError) { 76 | process.exit(e.exitCode); 77 | } 78 | else { 79 | throw e; 80 | } 81 | } 82 | } 83 | 84 | main(process.argv.slice(2)).then( 85 | () => { 86 | process.exit(0); 87 | }, 88 | e => { 89 | console.error(e); 90 | process.exit(1); 91 | }, 92 | ); 93 | -------------------------------------------------------------------------------- /ts-perf/packages/api/src/model/valueComparison.ts: -------------------------------------------------------------------------------- 1 | import { utest } from "../utest"; 2 | import { Value, ValueComponents } from "./value"; 3 | 4 | const alpha = 0.05; 5 | 6 | export interface ValueComparisonComponents { 7 | benchmark: Value | ValueComponents; 8 | baseline?: Value | ValueComponents; 9 | midline?: Value | ValueComponents; 10 | } 11 | 12 | export class ValueComparison { 13 | public readonly baselineRelativeDelta: number; 14 | public readonly midlineRelativeDelta: number; 15 | public readonly benchmarkRelativeDelta: number; 16 | public readonly baselineRelativePValue: number; 17 | public readonly midlineRelativePValue: number; 18 | public readonly worst: "baseline" | "midline"; 19 | 20 | constructor( 21 | public readonly benchmark: Value, 22 | public readonly baseline?: Value, 23 | public readonly midline?: Value, 24 | ) { 25 | this.baselineRelativeDelta = this.baseline ? (this.benchmark.mean - this.baseline.mean) / this.baseline.mean 26 | : 0; 27 | this.midlineRelativeDelta = this.midline ? (this.benchmark.mean - this.midline.mean) / this.midline.mean : 0; 28 | this.benchmarkRelativeDelta = Math.max(this.baselineRelativeDelta, this.midlineRelativeDelta); 29 | this.baselineRelativePValue = this.baseline ? utest(this.baseline.samples, this.benchmark.samples) : 1; 30 | this.midlineRelativePValue = this.midline ? utest(this.midline.samples, this.benchmark.samples) : 1; 31 | this.worst = this.baselineRelativeDelta > this.midlineRelativeDelta ? "baseline" : "midline"; 32 | } 33 | 34 | public get metric() { 35 | return this.benchmark.metric; 36 | } 37 | public get metricIndex() { 38 | return this.benchmark.metricIndex; 39 | } 40 | public get baselineRelativeIsSignificant() { 41 | return this.baselineRelativePValue < alpha; 42 | } 43 | public get midlineRelativeIsSignificant() { 44 | return this.midlineRelativePValue < alpha; 45 | } 46 | 47 | public static create(components: ValueComparisonComponents) { 48 | return components instanceof ValueComparison ? components : new ValueComparison( 49 | Value.create(components.benchmark), 50 | components.baseline && Value.create(components.baseline), 51 | components.midline && Value.create(components.midline), 52 | ); 53 | } 54 | 55 | public getComponents(): ValueComparisonComponents { 56 | return { 57 | benchmark: this.benchmark, 58 | baseline: this.baseline, 59 | midline: this.midline, 60 | }; 61 | } 62 | 63 | public with(components: Partial) { 64 | const { benchmark = this.benchmark } = components; 65 | const { baseline = this.baseline } = components; 66 | const { midline = this.midline } = components; 67 | 68 | if ( 69 | benchmark === this.benchmark 70 | && baseline === this.baseline 71 | && midline === this.midline 72 | ) { 73 | return this; 74 | } 75 | 76 | return ValueComparison.create({ 77 | benchmark, 78 | baseline, 79 | midline, 80 | }); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/lineTickView.ts: -------------------------------------------------------------------------------- 1 | // import { padLeft, formatPercent, TimeSpan } from "@ts-perf/api"; 2 | // import { from, Lazy } from "iterable-query"; 3 | // import { Table } from "../../decorators"; 4 | // import { CpuProfile } from "./profile"; 5 | // import { CpuProfileView } from "./profileView"; 6 | // import { CpuProfileNodeView } from "./nodeView"; 7 | // import { CpuProfileLineTick } from "./lineTick"; 8 | // import chalk = require("chalk"); 9 | 10 | // interface TableContext { 11 | // readonly profile: CpuProfile; 12 | // readonly hitCount: number; 13 | // readonly duration: TimeSpan; 14 | // } 15 | 16 | // @Table({ 17 | // createContext: values => { 18 | // const profile = values[0].profile; 19 | // const hitCount = from(values).sum(node => node.ticks); 20 | // const duration = profile.averageSampleDuration.scale(hitCount); 21 | // return { profile, hitCount, duration }; 22 | // }, 23 | // headers: [ 24 | // { expression: ({ profile }) => `duration (total): ${profile.duration.totalMilliseconds.toFixed(1)} ms, ${profile.totalCount} samples` }, 25 | // { expression: ({ profile, hitCount, duration }) => `duration (selection): ${duration.totalMilliseconds.toFixed(1)} ms, ${hitCount} samples ${chalk.gray(`(${formatPercent(hitCount / profile.totalCount)} of total)`)}` } 26 | // ], 27 | // group: [ 28 | // { by: x => `${x.nodeView.functionName || `(anonymous function)`} ${chalk.gray(`(${x.nodeView.location})`)}` } 29 | // ], 30 | // columns: [ 31 | // { header: "line", 32 | // expression: x => x.location }, 33 | // { header: "function ticks", 34 | // expression: x => `${x.ticks} ${padLeft(chalk.gray(formatPercent(x.ticks / x.nodeView.lineTickCount)), 7)}`, 35 | // align: "right" }, 36 | // { header: "self time", 37 | // expression: (x, _, { hitCount }) => `${x.duration.totalMilliseconds.toFixed(1)} ms ${padLeft(chalk.gray(formatPercent(x.ticks / hitCount)), 7)}`, 38 | // align: "right" }, 39 | // ] 40 | // }) 41 | // export class CpuProfileLineTickView { 42 | // readonly profile: CpuProfile; 43 | // readonly profileView: CpuProfileView; 44 | // readonly nodeView: CpuProfileNodeView; 45 | // readonly lines: ReadonlyArray; 46 | // readonly lineNumber: number; 47 | // readonly ticks: number; 48 | // readonly duration: TimeSpan; 49 | 50 | // constructor(nodeView: CpuProfileNodeView, lines: Iterable) { 51 | // this.nodeView = nodeView; 52 | // this.profileView = nodeView.profileView; 53 | // this.profile = nodeView.profile; 54 | // this.lines = from(lines).toArray(); 55 | // if (this.lines.length === 0) { 56 | // this.lineNumber = -1; 57 | // this.ticks = 0; 58 | // } 59 | // else { 60 | // this.lineNumber = this.lines[0].lineNumber; 61 | // this.ticks = from(this.lines).sum(line => line.ticks); 62 | // } 63 | // this.duration = this.profile.averageSampleDuration.scale(this.ticks); 64 | // } 65 | 66 | // get location() { return `${this.nodeView.url}:${this.lineNumber}`; } 67 | // } 68 | -------------------------------------------------------------------------------- /ts-perf/packages/commands/src/analyze/model/profiler/eventRangeView.ts: -------------------------------------------------------------------------------- 1 | // import { from, Lazy } from "iterable-query"; 2 | // import { CpuProfileEventRangesView } from "./eventRangesView"; 3 | // import { CpuProfile } from "./profile"; 4 | // import { TimeSpan, padLeft, formatPercent } from "@ts-perf/api"; 5 | // import { Table } from "../../decorators"; 6 | // import chalk = require("chalk"); 7 | 8 | // interface CommonFields { 9 | // readonly startTime: TimeSpan; 10 | // readonly endTime: TimeSpan; 11 | // } 12 | 13 | // interface CpuProfileEventRangeViewTableContext { 14 | // readonly profile: CpuProfile; 15 | // } 16 | 17 | // @Table({ 18 | // createContext: ([{ profile }]) => ({ profile }), 19 | // headers: [ 20 | // { expression: ({ profile }) => `duration (total): ${profile.duration.totalMilliseconds.toFixed(1)} ms, ${profile.totalCount} samples` }, 21 | // ], 22 | // columns: [ 23 | // { header: "boundary", 24 | // expression: x => x.displayName }, 25 | // { header: "event range", 26 | // expression: x => x.startEventName ? `${x.startEventName}..${x.endEventName}` : "" }, 27 | // { header: "self time", 28 | // expression: (x, _, { profile }) => `${x.selfTime.totalMilliseconds.toFixed(1)} ms ${padLeft(chalk.gray(formatPercent(x.selfCount / profile.totalCount)), 7)}`, 29 | // align: "right" }, 30 | // ] 31 | // }) 32 | // export class CpuProfileEventRangeView { 33 | // readonly profile: CpuProfile; 34 | // readonly profileEventRangesView: CpuProfileEventRangesView; 35 | // readonly displayName: string; 36 | // readonly startEventName: string; 37 | // readonly endEventName: string; 38 | // readonly samples: ReadonlyArray; 39 | // readonly timestamps: ReadonlyArray; 40 | // readonly selfCount: number; 41 | // readonly selfTime: TimeSpan; 42 | 43 | // private _lazyCommonFields = Lazy.from(getCommonFields, this); 44 | 45 | // constructor(profileEventRangesView: CpuProfileEventRangesView, displayName: string, startEventName: string, endEventName: string, samplesAndTimestamps: ReadonlyArray<[number, TimeSpan]>) { 46 | // this.profileEventRangesView = profileEventRangesView; 47 | // this.profile = profileEventRangesView.profile; 48 | // this.displayName = displayName; 49 | // this.startEventName = startEventName; 50 | // this.endEventName = endEventName; 51 | // [this.samples = [], this.timestamps = []] = 52 | // from(samplesAndTimestamps) 53 | // .orderBy(pair => pair[1]) 54 | // .unzip(); 55 | // this.selfCount = samplesAndTimestamps.length; 56 | // this.selfTime = this.profile.averageSampleDuration.scale(this.selfCount); 57 | // } 58 | 59 | // get startTime(): TimeSpan { return this._lazyCommonFields.value.startTime; } 60 | // get endTime(): TimeSpan { return this._lazyCommonFields.value.endTime; } 61 | // } 62 | 63 | // function getCommonFields(view: CpuProfileEventRangeView): CommonFields { 64 | // const startTime = from(view.timestamps).first() || TimeSpan.NaN; 65 | // const endTime = from(view.timestamps).last() || TimeSpan.NaN; 66 | // return { startTime, endTime }; 67 | // } 68 | 69 | export {}; 70 | -------------------------------------------------------------------------------- /ts-perf/packages/core/src/pathComparer.ts: -------------------------------------------------------------------------------- 1 | import * as os from "node:os"; 2 | 3 | import { Comparer, Equaler } from "@esfx/equatable"; 4 | 5 | import { StringComparer } from "./stringComparer"; 6 | import { normalizeSlashes, removeWindowsLongPathPrefix, trimTrailingDirectorySeparator } from "./utils"; 7 | 8 | export class PathComparer implements Comparer, Equaler { 9 | public static readonly caseSensitive = new PathComparer(StringComparer.caseSensitiveNumeric); 10 | public static readonly caseInsensitive = new PathComparer(StringComparer.caseInsensitiveNumeric); 11 | public static readonly fileSystem = os.platform() === "win32" ? this.caseInsensitive : this.caseSensitive; 12 | 13 | private _comparer: Comparer & Equaler; 14 | 15 | constructor(comparerOrIgnoreCase?: boolean | Comparer & Equaler) { 16 | this._comparer = typeof comparerOrIgnoreCase === "object" ? comparerOrIgnoreCase 17 | : comparerOrIgnoreCase ? StringComparer.caseInsensitiveNumeric 18 | : StringComparer.caseInsensitiveNumeric; 19 | } 20 | 21 | public compare(x: string, y: string): number; 22 | public compare(x: string | undefined | null, y: string | undefined | null): number; 23 | public compare(x: string | undefined | null, y: string | undefined | null) { 24 | if (x === y) return 0; 25 | if (!x) return -1; 26 | if (!y) return +1; 27 | 28 | x = normalizeSlashes(x); 29 | x = trimTrailingDirectorySeparator(x); 30 | x = removeWindowsLongPathPrefix(x); 31 | // DOS drives are always case insensitive 32 | x = /^[a-z]:/i.test(x) ? `${x.slice(0, 2).toUpperCase()}${x.slice(2)}` : x; 33 | 34 | y = normalizeSlashes(y); 35 | y = trimTrailingDirectorySeparator(y); 36 | y = removeWindowsLongPathPrefix(y); 37 | // DOS drives are always case insensitive 38 | y = /^[a-z]:/i.test(y) ? `${y.slice(0, 2).toUpperCase()}${y.slice(2)}` : y; 39 | 40 | return this._comparer.compare(x, y); 41 | } 42 | 43 | public equals(x: string, y: string): boolean; 44 | public equals(x: string | undefined | null, y: string | undefined | null): boolean; 45 | public equals(x: string | undefined | null, y: string | undefined | null) { 46 | if (x === y) return true; 47 | if (!x) return false; 48 | if (!y) return false; 49 | 50 | x = normalizeSlashes(x); 51 | x = trimTrailingDirectorySeparator(x); 52 | x = removeWindowsLongPathPrefix(x); 53 | // DOS drives are always case insensitive 54 | x = /^[a-z]:/i.test(x) ? `${x.slice(0, 2).toUpperCase()}${x.slice(2)}` : x; 55 | 56 | y = normalizeSlashes(y); 57 | y = trimTrailingDirectorySeparator(y); 58 | y = removeWindowsLongPathPrefix(y); 59 | // DOS drives are always case insensitive 60 | y = /^[a-z]:/i.test(y) ? `${y.slice(0, 2).toUpperCase()}${y.slice(2)}` : y; 61 | 62 | return this._comparer.equals(x, y); 63 | } 64 | 65 | public hash(x: string): number { 66 | x = normalizeSlashes(x); 67 | x = trimTrailingDirectorySeparator(x); 68 | x = removeWindowsLongPathPrefix(x); 69 | // DOS drives are always case insensitive 70 | x = /^[a-z]:/i.test(x) ? `${x.slice(0, 2).toUpperCase()}${x.slice(2)}` : x; 71 | return this._comparer.hash(x); 72 | } 73 | } 74 | --------------------------------------------------------------------------------