Skip to content

Write path normalization without array allocations - #60812

Merged
Andrew Branch (andrewbranch) merged 5 commits into
microsoft:mainfrom
andrewbranch:perf/normalizePath
Jan 9, 2025
Merged

Write path normalization without array allocations#60812
Andrew Branch (andrewbranch) merged 5 commits into
microsoft:mainfrom
andrewbranch:perf/normalizePath

Conversation

@andrewbranch

@andrewbranchAndrew Branch (andrewbranch) commented Dec 18, 2024

Copy link
Copy Markdown
Member

Related: #60633
Alternative to #60755

Despite the good benchmarks, I didn’t see any measurable impact in real-world updateGraphWorker duration on my M2 Mac Mini. However, since that was a GC hot spot for Dirk Bäumer (@dbaeumer) and #60755 improved things some, this may do even better for him.

bench.js
constts=require("./built/local/typescript");constts_old=require("./node_modules/typescript");const{ Suite }=require("bench-node");constsuite=newSuite();suite.add("normalizePath_old",()=>{runScenarios(ts_old.normalizePath);});suite.add("normalizePath_new",()=>{runScenarios(ts.normalizePath);});suite.add("getNormalizedAbsolutePath_old",()=>{runScenarios(ts_old.getNormalizedAbsolutePath);});suite.add("getNormalizedAbsolutePath_new",()=>{runScenarios(ts.getNormalizedAbsolutePath);});suite.run();functionrunScenarios(normalize){normalize("/","");normalize("/.","");normalize("/./","");normalize("/../","");normalize("/a","");normalize("/a/","");normalize("/a/.","");normalize("/a/foo.","");normalize("/a/./","");normalize("/a/./b","");normalize("/a/./b/","");normalize("/a/..","");normalize("/a/../","");normalize("/a/../","");normalize("/a/../b","");normalize("/a/../b/","");normalize("/a/..","");normalize("/a/..","/");normalize("/a/..","b/");normalize("/a/..","/b");normalize("/a/.","b");normalize("/a/.",".");// Tests as above, but with backslashes.normalize("\\","");normalize("\\.","");normalize("\\.\\","");normalize("\\..\\","");normalize("\\a\\.\\","");normalize("\\a\\.\\b","");normalize("\\a\\.\\b\\","");normalize("\\a\\..","");normalize("\\a\\..\\","");normalize("\\a\\..\\","");normalize("\\a\\..\\b","");normalize("\\a\\..\\b\\","");normalize("\\a\\..","");normalize("\\a\\..","\\");normalize("\\a\\..","b\\");normalize("\\a\\..","\\b");normalize("\\a\\.","b");normalize("\\a\\.",".");// Relative paths on an empty currentDirectory.normalize("","");normalize(".","");normalize("./","");normalize("./a","");// Strangely, these do not normalize to the empty string.normalize("..","");normalize("../","");normalize("../..","");normalize("../../","");normalize("./..","");normalize("../../a/..","");// Interaction between relative paths and currentDirectory.normalize("","/home");normalize(".","/home");normalize("./","/home");normalize("..","/home");normalize("../","/home");normalize("a","b");normalize("a","b/c");// Base names starting or ending with a dot do not affect normalization.normalize(".a","");normalize("..a","");normalize("a.","");normalize("a..","");normalize("/base/./.a","");normalize("/base/../.a","");normalize("/base/./..a","");normalize("/base/../..a","");normalize("/base/./..a/b","");normalize("/base/../..a/b","");normalize("/base/./a.","");normalize("/base/../a.","");normalize("/base/./a..","");normalize("/base/../a..","");normalize("/base/./a../b","");normalize("/base/../a../b","");// Consecutive intermediate slashes are normalized to a single slash.normalize("a//b","");normalize("a///b","");normalize("a/b//c","");normalize("/a/b//c","");normalize("//a/b//c","");// Backslashes are converted to slashes,// and then consecutive intermediate slashes are normalized to a single slashnormalize("a\\\\b","");normalize("a\\\\\\b","");normalize("a\\b\\\\c","");normalize("\\a\\b\\\\c","");normalize("\\\\a\\b\\\\c","");// The same occurs for mixed slashes.normalize("a/\\b","");normalize("a\\/b","");normalize("a\\/\\b","");normalize("a\\b//c","");normalize("\\a\\b\\\\c","");normalize("\\\\a\\b\\\\c","");}
npm i --no-save bench-node
npm run build
node --allow-natives-syntax bench.js normalizePath_old x 49,990 ops/sec (13 runs sampled) v8-never-optimize=true min..max=(19.15us...20.48us)
normalizePath_new x 125,800 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(7.80us...8.27us)
getNormalizedAbsolutePath_old x 55,493 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(17.17us...18.45us)
getNormalizedAbsolutePath_new x 125,567 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(7.90us...8.03us)

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

TypeScript Bot (@typescript-bot) perf test this

@typescript-bot

TypeScript Bot (typescript-bot) commented Dec 18, 2024

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
perf test this✅ Started👀 Results

Comment threadsrc/compiler/path.ts
/** @internal */
export function getNormalizedAbsolutePath(fileName: string, currentDirectory: string | undefined): string {
return getPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory));
export function getNormalizedAbsolutePath(path: string, currentDirectory: string | undefined): string {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if currentDirectory is almost always normalized.

@typescript-bot

Copy link
Copy Markdown
Contributor

Andrew Branch (@andrewbranch)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-Unions - node (v18.15.0, x64)
Errors3434~~~p=1.000 n=6
Symbols62,36362,363~~~p=1.000 n=6
Types50,39550,395~~~p=1.000 n=6
Memory used195,362k (± 1.01%)196,140k (± 0.73%)~193,230k196,885kp=0.230 n=6
Parse Time1.59s (± 1.19%)1.61s (± 1.01%)+0.02s (+ 1.47%)1.60s1.64sp=0.048 n=6
Bind Time0.87s (± 1.62%)0.86s (± 1.47%)~0.85s0.88sp=0.249 n=6
Check Time11.73s (± 0.48%)11.79s (± 0.56%)~11.71s11.87sp=0.261 n=6
Emit Time3.46s (± 3.38%)3.33s (± 2.58%)~3.26s3.50sp=0.063 n=6
Total Time17.65s (± 0.66%)17.60s (± 0.75%)~17.45s17.77sp=0.471 n=6
angular-1 - node (v18.15.0, x64)
Errors3737~~~p=1.000 n=6
Symbols947,936947,936~~~p=1.000 n=6
Types410,955410,955~~~p=1.000 n=6
Memory used1,226,014k (± 0.00%)1,225,733k (± 0.00%)-281k (- 0.02%)1,225,632k1,225,785kp=0.005 n=6
Parse Time8.01s (± 0.80%)8.21s (± 0.87%)+0.19s (+ 2.41%)8.11s8.27sp=0.006 n=6
Bind Time2.29s (± 1.01%)2.30s (± 0.45%)~2.28s2.31sp=0.220 n=6
Check Time38.28s (± 0.44%)38.60s (± 0.41%)+0.32s (+ 0.84%)38.38s38.82sp=0.013 n=6
Emit Time18.34s (± 0.77%)19.85s (± 0.82%)🔻+1.51s (+ 8.24%)19.70s20.14sp=0.005 n=6
Total Time66.92s (± 0.44%)68.96s (± 0.29%)+2.04s (+ 3.05%)68.72s69.22sp=0.005 n=6
mui-docs - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols2,449,1722,449,172~~~p=1.000 n=6
Types896,410896,410~~~p=1.000 n=6
Memory used2,321,055k (± 0.00%)2,320,238k (± 0.01%)-817k (- 0.04%)2,319,979k2,320,359kp=0.005 n=6
Parse Time11.39s (± 0.39%)11.77s (± 1.44%)+0.38s (+ 3.31%)11.66s12.11sp=0.005 n=6
Bind Time2.68s (± 0.28%)2.66s (± 0.97%)~2.62s2.70sp=0.118 n=6
Check Time88.08s (± 0.61%)90.77s (± 1.75%)+2.69s (+ 3.06%)88.98s93.25sp=0.005 n=6
Emit Time0.35s (± 4.04%)0.36s (± 2.84%)~0.35s0.38sp=0.118 n=6
Total Time102.50s (± 0.51%)105.56s (± 1.45%)+3.06s (+ 2.99%)103.84s108.01sp=0.005 n=6
self-build-src - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8801,226,894+14 (+ 0.00%)~~p=0.001 n=6
Types266,745266,772+27 (+ 0.01%)~~p=0.001 n=6
Memory used2,846,394k (±13.21%)2,847,042k (±13.14%)~2,363,411k3,089,147kp=0.689 n=6
Parse Time6.75s (± 2.20%)6.76s (± 1.67%)~6.61s6.89sp=1.000 n=6
Bind Time2.16s (± 2.08%)2.18s (± 1.77%)~2.12s2.23sp=0.810 n=6
Check Time42.75s (± 0.52%)42.96s (± 0.53%)~42.64s43.31sp=0.230 n=6
Emit Time3.49s (± 3.25%)3.46s (± 3.04%)~3.31s3.64sp=0.470 n=6
Total Time55.15s (± 0.57%)55.35s (± 0.58%)~54.85s55.82sp=0.297 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8801,226,894+14 (+ 0.00%)~~p=0.001 n=6
Types266,745266,772+27 (+ 0.01%)~~p=0.001 n=6
Memory used3,032,595k (± 9.77%)3,033,234k (± 9.76%)~2,428,371k3,155,346kp=0.378 n=6
Parse Time8.65s (± 1.54%)8.71s (± 1.29%)~8.49s8.79sp=0.093 n=6
Bind Time2.65s (± 1.51%)2.64s (± 1.19%)~2.59s2.68sp=0.810 n=6
Check Time53.24s (± 0.37%)53.40s (± 0.13%)~53.31s53.47sp=0.128 n=6
Emit Time4.39s (± 2.24%)4.32s (± 2.25%)~4.20s4.44sp=0.378 n=6
Total Time68.93s (± 0.28%)69.07s (± 0.14%)~68.94s69.21sp=0.172 n=6
self-compiler - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols262,439262,453+14 (+ 0.01%)~~p=0.001 n=6
Types106,628106,629+1 (+ 0.00%)~~p=0.001 n=6
Memory used440,184k (± 0.01%)440,500k (± 0.01%)+316k (+ 0.07%)440,436k440,550kp=0.005 n=6
Parse Time3.52s (± 1.10%)3.58s (± 0.82%)+0.06s (+ 1.66%)3.55s3.63sp=0.028 n=6
Bind Time1.32s (± 0.83%)1.32s (± 1.75%)~1.29s1.35sp=0.870 n=6
Check Time18.90s (± 0.44%)19.06s (± 0.27%)+0.15s (+ 0.82%)18.97s19.11sp=0.010 n=6
Emit Time1.52s (± 0.69%)1.53s (± 0.34%)~1.53s1.54sp=0.142 n=6
Total Time25.26s (± 0.42%)25.49s (± 0.24%)+0.22s (+ 0.89%)25.38s25.55sp=0.006 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors7070~~~p=1.000 n=6
Symbols226,062226,062~~~p=1.000 n=6
Types94,48894,488~~~p=1.000 n=6
Memory used371,576k (± 0.02%)371,654k (± 0.03%)~371,558k371,896kp=0.261 n=6
Parse Time2.91s (± 0.77%)2.91s (± 1.20%)~2.86s2.95sp=0.517 n=6
Bind Time1.58s (± 0.84%)1.59s (± 1.92%)~1.55s1.63sp=0.464 n=6
Check Time16.54s (± 0.54%)16.53s (± 0.32%)~16.45s16.61sp=0.936 n=6
Emit Time0.00s (±244.70%)0.00s~~~p=0.405 n=6
Total Time21.03s (± 0.38%)21.04s (± 0.41%)~20.91s21.16sp=1.000 n=6
vscode - node (v18.15.0, x64)
Errors33~~~p=1.000 n=6
Symbols3,222,3863,222,386~~~p=1.000 n=6
Types1,108,4931,108,493~~~p=1.000 n=6
Memory used3,288,091k (± 0.01%)3,287,870k (± 0.01%)~3,287,518k3,288,482kp=0.298 n=6
Parse Time14.21s (± 0.33%)14.80s (± 2.89%)🔻+0.60s (+ 4.21%)14.49s15.66sp=0.005 n=6
Bind Time4.53s (± 0.57%)4.62s (± 2.79%)~4.52s4.81sp=0.225 n=6
Check Time88.99s (± 3.43%)90.52s (± 2.98%)~89.09s96.01sp=0.230 n=6
Emit Time27.20s (± 7.39%)31.85s (± 6.12%)🔻+4.65s (+17.09%)27.93s33.04sp=0.013 n=6
Total Time134.93s (± 2.20%)141.81s (± 0.69%)🔻+6.88s (+ 5.10%)140.77s143.06sp=0.005 n=6
webpack - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols291,468291,468~~~p=1.000 n=6
Types118,921118,921~~~p=1.000 n=6
Memory used445,188k (± 0.02%)445,209k (± 0.03%)~445,042k445,409kp=0.810 n=6
Parse Time4.04s (± 0.72%)4.09s (± 1.05%)~4.02s4.14sp=0.091 n=6
Bind Time1.76s (± 0.78%)1.76s (± 0.86%)~1.75s1.79sp=1.000 n=6
Check Time18.74s (± 0.48%)18.76s (± 0.51%)~18.66s18.89sp=0.936 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time24.54s (± 0.41%)24.62s (± 0.44%)~24.52s24.78sp=0.378 n=6
xstate-main - node (v18.15.0, x64)
Errors55~~~p=1.000 n=6
Symbols552,233552,233~~~p=1.000 n=6
Types184,971184,971~~~p=1.000 n=6
Memory used492,315k (± 0.02%)492,202k (± 0.01%)-113k (- 0.02%)492,163k492,254kp=0.031 n=6
Parse Time2.76s (± 0.15%)2.80s (± 0.27%)+0.04s (+ 1.33%)2.79s2.81sp=0.003 n=6
Bind Time0.96s0.96s~~~p=1.000 n=6
Check Time16.16s (± 0.27%)16.20s (± 0.28%)~16.16s16.27sp=0.261 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time19.88s (± 0.21%)19.97s (± 0.21%)+0.09s (+ 0.44%)19.93s20.03sp=0.006 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

tsserver

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,312ms (± 0.59%)2,342ms (± 0.35%)+30ms (+ 1.30%)2,327ms2,349msp=0.005 n=6
Req 2 - geterr5,287ms (± 0.30%)5,332ms (± 0.22%)+45ms (+ 0.85%)5,320ms5,347msp=0.005 n=6
Req 3 - references263ms (± 1.58%)267ms (± 1.56%)~261ms270msp=0.076 n=6
Req 4 - navto227ms (± 0.53%)227ms (± 0.54%)~226ms229msp=0.788 n=6
Req 5 - completionInfo count1,3571,357~~~p=1.000 n=6
Req 5 - completionInfo77ms (± 3.88%)81ms (± 9.55%)~76ms91msp=0.208 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,456ms (± 1.59%)2,464ms (± 1.27%)~2,420ms2,499msp=0.689 n=6
Req 2 - geterr4,056ms (± 0.50%)4,071ms (± 0.44%)~4,053ms4,093msp=0.173 n=6
Req 3 - references284ms (± 0.48%)284ms (± 0.29%)~283ms285msp=0.934 n=6
Req 4 - navto228ms (± 0.18%)228ms~~~p=0.405 n=6
Req 5 - completionInfo count1,5191,519~~~p=1.000 n=6
Req 5 - completionInfo85ms (± 3.28%)87ms (± 1.19%)~86ms88msp=0.542 n=6
xstate-main-1-tsserver - node (v18.15.0, x64)
Req 1 - updateOpen5,311ms (± 0.26%)5,367ms (± 0.25%)+56ms (+ 1.06%)5,350ms5,384msp=0.005 n=6
Req 2 - geterr1,149ms (± 0.80%)1,168ms (± 0.97%)+19ms (+ 1.67%)1,155ms1,183msp=0.020 n=6
Req 3 - references83ms78ms (± 0.66%)🟩-5ms (- 6.43%)77ms78msp=0.002 n=6
Req 4 - navto450ms (± 0.27%)454ms (± 0.62%)+3ms (+ 0.74%)451ms458msp=0.027 n=6
Req 5 - completionInfo count3,4503,450~~~p=1.000 n=6
Req 5 - completionInfo853ms (± 1.86%)838ms (± 1.19%)~821ms850msp=0.199 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstate-main-1-tsserver - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

startup

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
tsc-startup - node (v18.15.0, x64)
Execution time161.64ms (± 0.22%)161.69ms (± 0.18%)+0.06ms (+ 0.04%)160.53ms164.00msp=0.005 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time233.15ms (± 0.15%)235.26ms (± 0.85%)+2.12ms (+ 0.91%)231.65ms267.00msp=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time232.11ms (± 0.15%)231.93ms (± 0.16%)-0.18ms (- 0.08%)230.45ms238.24msp=0.000 n=600
typescript-startup - node (v18.15.0, x64)
Execution time227.99ms (± 0.19%)227.82ms (± 0.16%)-0.17ms (- 0.08%)226.47ms232.88msp=0.000 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

Comment threadsrc/compiler/path.ts Outdated
Comment on lines +633 to +636
const root = path.substring(0, rootLength);
const normalizedRoot = root && normalizeSlashes(root);
// `normalized` is only initialized once `path` is determined to be non-normalized
let normalized = normalizedRoot === root ? undefined : normalizedRoot;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just use lastIndexOf to see if altDirectorySeparator occurs. That way you can avoid creating a substring for root at all.

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

I’m puzzled by the perf results

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

Changing the scenarios to have long paths that are already normalized shows the old normalizePath regex fast path to be the winner. The scenarios being benchmarked are the tests, which skew heavily toward needing normalization, whereas real-world usage usually results in a no-op. Probably using the regex to test, new function to modify, is going to be the best combination.

@andrewbranchAndrew Branch (andrewbranch) changed the title Write path normalization without array allocations or regexesWrite path normalization without array allocationsDec 19, 2024
@andrewbranch

Copy link
Copy Markdown
MemberAuthor

TypeScript Bot (@typescript-bot) perf test

@typescript-bot

TypeScript Bot (typescript-bot) commented Dec 19, 2024

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
perf test✅ Started👀 Results

Comment threadsrc/compiler/path.ts Outdated
Comment on lines +661 to +662
const sepIndex = path.indexOf(directorySeparator, index + 1);
const altSepIndex = path.indexOf(altDirectorySeparator, index + 1);

@DanielRosenwasserDaniel Rosenwasser (DanielRosenwasser)Dec 19, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quadratic because you have to find at least one of the other kinds of slashes over and over. You should just tight-loop on !isAnyDirectorySeparator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or use findIndex(path, isAnyDirectorySeparator, index + 1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern with findIndex is that it might not optimize well it passed in both arrays and strings. Maybe I'm superstitious.

Comment threadsrc/compiler/path.ts Outdated
// At beginning of segment
segmentStart = index;
let ch = path.charCodeAt(index);
while (isAnyDirectorySeparator(ch) && index + 1 < path.length) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a bit to see why this works, but it's because index starts immediately after the root, or after the first separator following the prior segment. Figuring out if one of those is a backslash is handled below.

Comment threadsrc/compiler/path.ts
normalizedUpTo = index + 2;
}
}
else if (normalized === undefined) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that in this branch it is technically possible for you to avoid extra substrings by adjusting normalizedUpTo instead of initializing normalized.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it matters since you'd still need to allocate a substring when returning.

@typescript-bot

Copy link
Copy Markdown
Contributor

Andrew Branch (@andrewbranch)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-Unions - node (v18.15.0, x64)
Errors3434~~~p=1.000 n=6
Symbols62,36362,363~~~p=1.000 n=6
Types50,39550,395~~~p=1.000 n=6
Memory used195,042k (± 1.01%)196,764k (± 0.09%)~196,453k196,962kp=0.298 n=6
Parse Time1.61s (± 1.30%)1.60s (± 1.84%)~1.56s1.64sp=0.373 n=6
Bind Time0.88s (± 2.14%)0.87s (± 0.60%)~0.86s0.87sp=0.452 n=6
Check Time11.74s (± 0.14%)11.76s (± 0.66%)~11.67s11.90sp=1.000 n=6
Emit Time3.28s (± 1.20%)3.31s (± 3.47%)~3.24s3.54sp=0.936 n=6
Total Time17.50s (± 0.42%)17.53s (± 0.61%)~17.40s17.66sp=0.687 n=6
angular-1 - node (v18.15.0, x64)
Errors3737~~~p=1.000 n=6
Symbols947,936947,936~~~p=1.000 n=6
Types410,955410,955~~~p=1.000 n=6
Memory used1,226,032k (± 0.00%)1,225,726k (± 0.01%)-306k (- 0.02%)1,225,636k1,225,853kp=0.005 n=6
Parse Time8.10s (± 0.81%)8.05s (± 0.49%)~8.02s8.11sp=0.198 n=6
Bind Time2.28s (± 0.95%)2.29s (± 0.24%)~2.29s2.30sp=0.101 n=6
Check Time38.17s (± 0.32%)38.11s (± 0.36%)~37.94s38.31sp=0.423 n=6
Emit Time18.36s (± 0.39%)18.21s (± 0.22%)-0.15s (- 0.81%)18.17s18.29sp=0.008 n=6
Total Time66.91s (± 0.24%)66.67s (± 0.22%)~66.48s66.87sp=0.066 n=6
mui-docs - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols2,449,1722,449,172~~~p=1.000 n=6
Types896,410896,410~~~p=1.000 n=6
Memory used2,321,084k (± 0.00%)2,320,392k (± 0.01%)-693k (- 0.03%)2,320,197k2,320,555kp=0.005 n=6
Parse Time14.06s (± 0.95%)13.92s (± 0.61%)-0.14s (- 1.00%)13.76s14.00sp=0.031 n=6
Bind Time3.29s (± 0.51%)3.29s (± 0.45%)~3.27s3.31sp=0.934 n=6
Check Time108.54s (± 2.20%)108.26s (± 1.40%)~107.06s110.72sp=0.688 n=6
Emit Time0.43s (± 1.97%)0.51s (±41.02%)~0.41s0.94sp=0.548 n=6
Total Time126.31s (± 1.99%)125.98s (± 1.24%)~124.69s128.19sp=0.575 n=6
self-build-src - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8801,226,898+18 (+ 0.00%)~~p=0.001 n=6
Types266,745266,773+28 (+ 0.01%)~~p=0.001 n=6
Memory used2,967,103k (±10.01%)2,725,331k (±14.65%)~2,360,476k3,091,267kp=0.689 n=6
Parse Time6.81s (± 1.59%)6.68s (± 1.40%)-0.12s (- 1.79%)6.58s6.79sp=0.031 n=6
Bind Time2.16s (± 1.60%)2.16s (± 1.70%)~2.11s2.19sp=0.872 n=6
Check Time42.90s (± 0.20%)42.78s (± 0.30%)~42.53s42.87sp=0.093 n=6
Emit Time3.49s (± 2.72%)3.48s (± 3.20%)~3.37s3.63sp=0.936 n=6
Total Time55.35s (± 0.24%)55.11s (± 0.42%)~54.73s55.39sp=0.066 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8801,226,898+18 (+ 0.00%)~~p=0.001 n=6
Types266,745266,773+28 (+ 0.01%)~~p=0.001 n=6
Memory used3,032,854k (± 9.77%)3,033,179k (± 9.74%)~2,429,601k3,154,501kp=1.000 n=6
Parse Time6.98s (± 1.03%)6.95s (± 0.81%)~6.85s7.00sp=0.297 n=6
Bind Time2.17s (± 1.22%)2.16s (± 1.21%)~2.13s2.19sp=0.517 n=6
Check Time42.93s (± 0.45%)42.77s (± 0.38%)~42.52s42.93sp=0.092 n=6
Emit Time3.53s (± 6.37%)3.52s (± 2.33%)~3.39s3.60sp=0.378 n=6
Total Time55.61s (± 0.23%)55.39s (± 0.46%)~54.92s55.63sp=0.065 n=6
self-compiler - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols262,439262,457+18 (+ 0.01%)~~p=0.001 n=6
Types106,628106,630+2 (+ 0.00%)~~p=0.001 n=6
Memory used440,209k (± 0.01%)440,509k (± 0.02%)+300k (+ 0.07%)440,407k440,692kp=0.005 n=6
Parse Time3.56s (± 0.61%)3.54s (± 1.17%)~3.51s3.61sp=0.255 n=6
Bind Time1.32s (± 0.92%)1.32s (± 1.05%)~1.30s1.34sp=0.802 n=6
Check Time18.90s (± 0.11%)19.09s (± 0.92%)+0.19s (+ 0.98%)18.95s19.44sp=0.005 n=6
Emit Time1.53s (± 0.76%)1.54s (± 0.82%)~1.53s1.56sp=0.278 n=6
Total Time25.31s (± 0.13%)25.48s (± 0.84%)+0.17s (+ 0.68%)25.28s25.88sp=0.037 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors7070~~~p=1.000 n=6
Symbols226,062226,062~~~p=1.000 n=6
Types94,48894,488~~~p=1.000 n=6
Memory used371,665k (± 0.03%)371,718k (± 0.05%)~371,533k372,071kp=0.689 n=6
Parse Time2.90s (± 0.72%)2.88s (± 1.23%)~2.83s2.92sp=0.460 n=6
Bind Time1.60s (± 1.25%)1.58s (± 0.53%)~1.57s1.59sp=0.276 n=6
Check Time16.47s (± 0.33%)16.49s (± 0.27%)~16.43s16.56sp=0.423 n=6
Emit Time0.00s (±244.70%)0.00s~~~p=0.405 n=6
Total Time20.97s (± 0.43%)20.95s (± 0.33%)~20.85s21.05sp=0.936 n=6
vscode - node (v18.15.0, x64)
Errors33~~~p=1.000 n=6
Symbols3,222,8153,222,815~~~p=1.000 n=6
Types1,108,6561,108,656~~~p=1.000 n=6
Memory used3,288,263k (± 0.01%)3,288,265k (± 0.01%)~3,287,962k3,288,511kp=0.810 n=6
Parse Time11.59s (± 0.17%)11.52s (± 0.17%)-0.07s (- 0.62%)11.50s11.55sp=0.005 n=6
Bind Time3.78s (± 0.72%)3.85s (± 2.67%)~3.75s3.99sp=0.139 n=6
Check Time73.69s (± 0.27%)73.34s (± 0.14%)-0.35s (- 0.47%)73.23s73.50sp=0.016 n=6
Emit Time23.75s (± 1.18%)23.27s (± 0.63%)-0.47s (- 1.99%)23.09s23.44sp=0.005 n=6
Total Time112.80s (± 0.39%)111.98s (± 0.20%)-0.82s (- 0.73%)111.70s112.28sp=0.008 n=6
webpack - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols291,468291,468~~~p=1.000 n=6
Types118,921118,921~~~p=1.000 n=6
Memory used445,276k (± 0.03%)445,259k (± 0.04%)~444,963k445,471kp=0.873 n=6
Parse Time4.11s (± 0.40%)4.10s (± 1.13%)~4.04s4.15sp=0.747 n=6
Bind Time1.77s (± 1.36%)1.77s (± 0.97%)~1.74s1.79sp=0.625 n=6
Check Time18.78s (± 0.51%)18.83s (± 0.60%)~18.69s18.97sp=0.470 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time24.68s (± 0.38%)24.69s (± 0.52%)~24.56s24.84sp=1.000 n=6
xstate-main - node (v18.15.0, x64)
Errors55~~~p=1.000 n=6
Symbols552,233552,233~~~p=1.000 n=6
Types184,971184,971~~~p=1.000 n=6
Memory used492,390k (± 0.00%)492,333k (± 0.01%)~492,252k492,398kp=0.128 n=6
Parse Time3.40s (± 0.31%)3.42s (± 0.57%)~3.40s3.45sp=0.119 n=6
Bind Time1.17s (± 0.64%)1.19s (± 1.89%)~1.16s1.21sp=0.216 n=6
Check Time19.41s (± 0.26%)19.44s (± 0.30%)~19.38s19.54sp=0.378 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time23.98s (± 0.23%)24.05s (± 0.29%)~23.97s24.17sp=0.109 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

tsserver

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,326ms (± 0.58%)2,333ms (± 0.34%)~2,326ms2,345msp=0.468 n=6
Req 2 - geterr5,321ms (± 0.57%)5,349ms (± 0.39%)~5,320ms5,383msp=0.173 n=6
Req 3 - references265ms (± 1.53%)267ms (± 1.44%)~263ms270msp=0.666 n=6
Req 4 - navto227ms (± 0.46%)228ms (± 0.58%)~226ms229msp=0.116 n=6
Req 5 - completionInfo count1,3571,357~~~p=1.000 n=6
Req 5 - completionInfo79ms (± 8.26%)81ms (±10.15%)~76ms92msp=0.652 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,437ms (± 1.50%)2,443ms (± 1.02%)~2,399ms2,467msp=0.873 n=6
Req 2 - geterr4,004ms (± 0.20%)3,996ms (± 0.37%)~3,976ms4,017msp=0.258 n=6
Req 3 - references280ms (± 1.23%)280ms (± 1.26%)~273ms282msp=0.623 n=6
Req 4 - navto227ms (± 0.18%)227ms (± 0.18%)~226ms227msp=1.000 n=6
Req 5 - completionInfo count1,5191,519~~~p=1.000 n=6
Req 5 - completionInfo83ms (± 5.12%)83ms (± 5.08%)~75ms86msp=0.517 n=6
xstate-main-1-tsserver - node (v18.15.0, x64)
Req 1 - updateOpen5,314ms (± 0.18%)5,319ms (± 0.79%)~5,277ms5,400msp=0.630 n=6
Req 2 - geterr1,150ms (± 0.81%)1,156ms (± 0.64%)~1,146ms1,167msp=0.295 n=6
Req 3 - references83ms76ms🟩-7ms (- 8.43%)~~p=0.001 n=6
Req 4 - navto452ms (± 1.07%)450ms (± 0.33%)~448ms452msp=0.568 n=6
Req 5 - completionInfo count3,4503,450~~~p=1.000 n=6
Req 5 - completionInfo855ms (± 1.39%)849ms (± 1.08%)~834ms861msp=0.421 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstate-main-1-tsserver - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

startup

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
tsc-startup - node (v18.15.0, x64)
Execution time158.93ms (± 0.21%)158.98ms (± 0.20%)~157.74ms162.13msp=0.086 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time236.48ms (± 0.15%)236.51ms (± 0.17%)~234.87ms243.71msp=0.586 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time232.29ms (± 0.16%)232.22ms (± 0.16%)~230.84ms237.70msp=0.058 n=600
typescript-startup - node (v18.15.0, x64)
Execution time228.14ms (± 0.17%)228.22ms (± 0.16%)+0.08ms (+ 0.03%)226.88ms230.59msp=0.035 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

// the root is `file://Users/`
assert.strictEqual(ts.getNormalizedAbsolutePath("file://Users/matb/projects/san/../../../../../../typings/@epic/Core.d.ts", ""), "file://Users/typings/@epic/Core.d.ts");
// this is real
assert.strictEqual(ts.getNormalizedAbsolutePath("file:///Users/matb/projects/san/../../../../../../typings/@epic/Core.d.ts", ""), "file:///typings/@epic/Core.d.ts");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk if we want to preserve specific examples in these, but that might be fine.

Maybe we should have tests on untitled:?

Comment threadsrc/compiler/path.ts Outdated
return path;
}
// Some paths only require cleanup of `/./` or leading `./`
const simplified = path.replace(/\/\.\//g, "/").replace(/^\.\//, "");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're already here, I'd also recommend

Suggested change
constsimplified=path.replace(/\/\.\//g,"/").replace(/^\.\//,"");
letsimplified=path.replace(/\/\.\//g,"/");
if(simplified.startsWith("./"){
simplified=simplified.slice(2);
}

@andrewbranchAndrew Branch (andrewbranch)Jan 9, 2025

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed a small but measurable improvement. Nice!

Comment threadsrc/compiler/path.ts Outdated
Comment threadsrc/compiler/path.ts
normalized = path.substring(0, normalizedUpTo);
}
}
else if (segmentLength === 2 && path.charCodeAt(index) === CharacterCodes.dot && path.charCodeAt(index + 1) === CharacterCodes.dot) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit: If the previous segmentLength was 1, but the segment was not ., this performs an unnecessary recheck of segmentLength === 2.

Comment threadsrc/compiler/path.ts Outdated
Comment threadsrc/compiler/path.ts Outdated
Comment threadsrc/compiler/path.ts Outdated
Comment threadsrc/compiler/path.ts
Comment threadsrc/compiler/path.ts Outdated
Comment on lines +661 to +662
const sepIndex = path.indexOf(directorySeparator, index + 1);
const altSepIndex = path.indexOf(altDirectorySeparator, index + 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or use findIndex(path, isAnyDirectorySeparator, index + 1)

@andrewbranch

Andrew Branch (andrewbranch) commented Dec 20, 2024

Copy link
Copy Markdown
MemberAuthor

From instrumenting the compilation of VS Code, I learned two things:

  1. The number of normalizePath calls outweighs getNormalizedAbsolutePath by ~300x.
  2. 99% of all calls to either function end up being a no-op.

Optimizing getNormalizedAbsolutePath is unlikely to make a measurable difference.

I'm going to repeat the instrumentation for a TS Server program update and see if the ratios are similar.

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

During a TS Server update, literally every call is a no-op.

{
initialize: {
normalizePath: {
total: 108354,
noop: 108026,
slashes: 0,
fastReplace: 0,
full: 328
},
getNormalizedAbsolutePath: {
total: 1978,
noop: 1958
}
},
update: {
normalizePath: {
total: 7839,
noop: 7839,
slashes: 0,
fastReplace: 0,
full: 0
},
getNormalizedAbsolutePath: {
total: 467,
noop: 467
}
}
}

@DanielRosenwasser

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) pack this

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 8, 2025

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
pack this✅ Started❌ Results

@typescript-bot

Copy link
Copy Markdown
Contributor

Hey Daniel Rosenwasser (@DanielRosenwasser), something went wrong when looking for the build artifact. (You can check the log here).

@DanielRosenwasser

Copy link
Copy Markdown
Member

TypeScript Bot (@typescript-bot) pack this

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 8, 2025

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
pack this✅ Started✅ Results

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 8, 2025

Copy link
Copy Markdown
Contributor

Hey Daniel Rosenwasser (@DanielRosenwasser), I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:

{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/164499/artifacts?artifactName=tgz&fileId=C363503DDC9CF8EDD088ADAB07110C96DF6B54D1E2E2CDD0508EAC13AAB8CE4D02&fileName=/typescript-5.8.0-insiders.20250108.tgz"
}
}

and then running npm install.


There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/pr-build@5.8.0-pr-60812-15".;

@andrewbranch

Andrew Branch (andrewbranch) commented Jan 9, 2025

Copy link
Copy Markdown
MemberAuthor
ts - getNormalizedAbsolutePath - non-normalized inputs x 312,203 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.13us...3.35us)
new - getNormalizedAbsolutePath - non-normalized inputs x 470,033 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(2.12us...2.14us)
ts - normalizePath - non-normalized inputs x 279,383 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.51us...3.74us)
new - normalizePath - non-normalized inputs x 317,772 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.13us...3.17us)
ts - getNormalizedAbsolutePath - normalized inputs x 1,351,618 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(727.40ns...753.29ns)
new - getNormalizedAbsolutePath - normalized inputs x 9,384,673 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(105.79ns...106.60ns)
ts - normalizePath - normalized inputs x 11,299,524 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(87.34ns...89.66ns)
new - normalizePath - normalized inputs x 11,162,477 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(88.69ns...90.97ns)
ts - getNormalizedAbsolutePath - normalized inputs (long) x 239,527 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.13us...4.22us)
new - getNormalizedAbsolutePath - normalized inputs (long) x 3,004,483 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(331.61ns...333.89ns)
ts - normalizePath - normalized inputs (long) x 3,221,628 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(307.32ns...315.50ns)
new - normalizePath - normalized inputs (long) x 3,213,039 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(310.61ns...312.85ns)
ts - tsc-vscode-macos.json x 2.44 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(406.30ms...414.83ms)
new - tsc-vscode-macos.json x 2.45 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(404.74ms...414.85ms)
ts - tsc-vscode-windows.json x 2.63 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(373.04ms...389.78ms)
new - tsc-vscode-windows.json x 2.74 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(363.90ms...367.53ms)
ts - tsserver-edit-vscode-macos.json x 2,220 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(437.21us...457.24us)
new - tsserver-edit-vscode-macos.json x 4,930 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(200.00us...203.69us)
ts - tsserver-edit-vscode-windows.json x 2,521 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(380.36us...405.09us)
new - tsserver-edit-vscode-windows.json x 5,392 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(182.71us...187.61us)
ts - tsserver-startup-vscode-macos.json x 219 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(4.44ms...4.57ms)
new - tsserver-startup-vscode-macos.json x 256 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.85ms...4.00ms)
ts - tsserver-startup-vscode-windows.json x 256 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(3.88ms...3.93ms)
new - tsserver-startup-vscode-windows.json x 294 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.36ms...3.47ms)

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

After latest commit:

ts - getNormalizedAbsolutePath - non-normalized inputs x 302,861 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(3.21us...3.45us)
new - getNormalizedAbsolutePath - non-normalized inputs x 536,370 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(1.79us...1.91us)
ts - normalizePath - non-normalized inputs x 237,263 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(3.59us...3.80us)
new - normalizePath - non-normalized inputs x 383,873 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(2.54us...2.68us)
ts - getNormalizedAbsolutePath - normalized inputs x 1,303,039 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(749.03ns...839.55ns)
new - getNormalizedAbsolutePath - normalized inputs x 8,795,269 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(111.05ns...114.70ns)
ts - normalizePath - normalized inputs x 10,916,299 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(89.41ns...95.17ns)
new - normalizePath - normalized inputs x 10,677,227 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(90.96ns...98.74ns)
ts - getNormalizedAbsolutePath - normalized inputs (long) x 231,771 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(4.17us...4.59us)
new - getNormalizedAbsolutePath - normalized inputs (long) x 2,899,659 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(337.72ns...360.04ns)
ts - normalizePath - normalized inputs (long) x 2,996,074 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(310.80ns...332.25ns)
new - normalizePath - normalized inputs (long) x 3,096,857 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(312.29ns...328.02ns)
ts - tsc-vscode-macos.json x 2.39 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(406.07ms...418.08ms)
new - tsc-vscode-macos.json x 2.45 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(401.52ms...422.69ms)
ts - tsc-vscode-windows.json x 2.62 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(379.20ms...386.33ms)
new - tsc-vscode-windows.json x 2.77 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(358.76ms...361.70ms)
ts - tsserver-edit-vscode-macos.json x 2,232 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(444.66us...453.18us)
new - tsserver-edit-vscode-macos.json x 4,895 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(202.00us...208.18us)
ts - tsserver-edit-vscode-windows.json x 2,536 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(390.12us...400.87us)
new - tsserver-edit-vscode-windows.json x 5,320 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(186.94us...189.56us)
ts - tsserver-startup-vscode-macos.json x 216 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.54ms...4.71ms)
new - tsserver-startup-vscode-macos.json x 247 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.02ms...4.11ms)
ts - tsserver-startup-vscode-windows.json x 247 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.95ms...4.17ms)
new - tsserver-startup-vscode-windows.json x 291 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(3.36ms...3.54ms)

and just comparing the last commit to the one before it:

old - getNormalizedAbsolutePath - non-normalized inputs x 449,445 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(2.20us...2.27us)
new - getNormalizedAbsolutePath - non-normalized inputs x 564,347 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(1.74us...1.79us)
old - normalizePath - non-normalized inputs x 307,495 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(3.22us...3.27us)
new - normalizePath - non-normalized inputs x 396,067 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(2.49us...2.55us)

@andrewbranch

Copy link
Copy Markdown
MemberAuthor

TypeScript Bot (@typescript-bot) perf test

@typescript-bot

TypeScript Bot (typescript-bot) commented Jan 9, 2025

Copy link
Copy Markdown
Contributor

Starting jobs; this comment will be updated as builds start and complete.

CommandStatusResults
perf test✅ Started👀 Results

@typescript-bot

Copy link
Copy Markdown
Contributor

Andrew Branch (@andrewbranch)
The results of the perf run you requested are in!

Here they are:

tsc

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-Unions - node (v18.15.0, x64)
Errors3434~~~p=1.000 n=6
Symbols62,36362,363~~~p=1.000 n=6
Types50,39550,395~~~p=1.000 n=6
Memory used196,108k (± 0.85%)195,616k (± 0.94%)~193,218k196,876kp=0.810 n=6
Parse Time1.59s (± 1.80%)1.60s (± 1.52%)~1.55s1.62sp=0.936 n=6
Bind Time0.88s (± 0.92%)0.88s (± 1.33%)~0.86s0.89sp=0.498 n=6
Check Time11.72s (± 0.54%)11.78s (± 0.49%)~11.71s11.87sp=0.146 n=6
Emit Time3.34s (± 3.62%)3.32s (± 0.78%)~3.28s3.36sp=0.371 n=6
Total Time17.54s (± 0.74%)17.57s (± 0.27%)~17.51s17.64sp=0.336 n=6
angular-1 - node (v18.15.0, x64)
Errors3737~~~p=1.000 n=6
Symbols947,936947,936~~~p=1.000 n=6
Types410,955410,955~~~p=1.000 n=6
Memory used1,226,002k (± 0.01%)1,225,798k (± 0.00%)-204k (- 0.02%)1,225,740k1,225,885kp=0.005 n=6
Parse Time8.10s (± 0.67%)8.05s (± 0.88%)~7.91s8.11sp=0.335 n=6
Bind Time2.28s (± 0.78%)2.30s (± 0.93%)~2.27s2.32sp=0.144 n=6
Check Time38.20s (± 0.36%)38.18s (± 0.66%)~37.78s38.48sp=1.000 n=6
Emit Time18.29s (± 0.62%)18.32s (± 0.53%)~18.15s18.45sp=0.260 n=6
Total Time66.86s (± 0.27%)66.84s (± 0.22%)~66.55s66.99sp=0.629 n=6
mui-docs - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols2,446,5672,446,567~~~p=1.000 n=6
Types897,081897,081~~~p=1.000 n=6
Memory used2,311,488k (± 0.01%)2,310,658k (± 0.00%)-829k (- 0.04%)2,310,514k2,310,767kp=0.005 n=6
Parse Time10.85s (± 0.58%)10.82s (± 0.55%)~10.74s10.89sp=0.466 n=6
Bind Time2.53s (± 0.20%)2.54s (± 0.73%)~2.52s2.57sp=0.079 n=6
Check Time88.46s (± 1.46%)88.74s (± 2.36%)~87.22s91.82sp=1.000 n=6
Emit Time0.71s (±122.70%)0.35s (± 2.55%)~0.34s0.36sp=0.345 n=6
Total Time102.54s (± 1.40%)102.45s (± 2.03%)~100.88s105.44sp=1.000 n=6
self-build-src - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8521,226,867+15 (+ 0.00%)~~p=0.001 n=6
Types266,743266,771+28 (+ 0.01%)~~p=0.001 n=6
Memory used2,724,030k (±14.65%)3,088,546k (± 0.02%)~3,087,714k3,089,454kp=0.298 n=6
Parse Time6.72s (± 1.89%)6.76s (± 0.53%)~6.72s6.82sp=0.575 n=6
Bind Time2.13s (± 2.64%)2.16s (± 0.96%)~2.14s2.19sp=0.421 n=6
Check Time42.83s (± 0.62%)42.88s (± 0.17%)~42.77s42.99sp=0.378 n=6
Emit Time3.61s (± 5.13%)3.52s (± 2.12%)~3.41s3.63sp=0.378 n=6
Total Time55.30s (± 0.60%)55.31s (± 0.32%)~55.09s55.62sp=0.378 n=6
self-build-src-public-api - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols1,226,8521,226,867+15 (+ 0.00%)~~p=0.001 n=6
Types266,743266,771+28 (+ 0.01%)~~p=0.001 n=6
Memory used3,032,791k (± 9.75%)2,671,369k (±13.99%)~2,428,147k3,154,401kp=0.689 n=6
Parse Time8.58s (± 1.42%)8.56s (± 1.37%)~8.44s8.74sp=0.630 n=6
Bind Time2.67s (± 1.55%)2.65s (± 1.87%)~2.60s2.73sp=0.630 n=6
Check Time53.23s (± 0.32%)53.06s (± 0.65%)~52.63s53.58sp=0.298 n=6
Emit Time4.38s (± 1.62%)4.34s (± 2.41%)~4.23s4.53sp=0.298 n=6
Total Time68.87s (± 0.43%)68.61s (± 0.65%)~68.09s69.14sp=0.298 n=6
self-compiler - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols262,441262,456+15 (+ 0.01%)~~p=0.001 n=6
Types106,628106,630+2 (+ 0.00%)~~p=0.001 n=6
Memory used440,204k (± 0.02%)440,475k (± 0.01%)+271k (+ 0.06%)440,425k440,604kp=0.005 n=6
Parse Time3.54s (± 1.06%)3.53s (± 0.69%)~3.51s3.57sp=0.677 n=6
Bind Time1.31s (± 1.08%)1.31s (± 0.92%)~1.30s1.33sp=0.743 n=6
Check Time19.00s (± 0.46%)18.94s (± 0.56%)~18.75s19.07sp=0.470 n=6
Emit Time1.53s (± 0.53%)1.54s (± 1.28%)~1.52s1.57sp=0.655 n=6
Total Time25.37s (± 0.45%)25.32s (± 0.45%)~25.12s25.43sp=0.575 n=6
ts-pre-modules - node (v18.15.0, x64)
Errors7070~~~p=1.000 n=6
Symbols226,062226,062~~~p=1.000 n=6
Types94,48894,488~~~p=1.000 n=6
Memory used371,681k (± 0.04%)371,591k (± 0.01%)~371,560k371,640kp=0.173 n=6
Parse Time2.89s (± 1.18%)2.91s (± 0.78%)~2.89s2.94sp=0.250 n=6
Bind Time1.59s (± 0.73%)1.61s (± 0.85%)~1.59s1.62sp=0.084 n=6
Check Time16.51s (± 0.24%)16.50s (± 0.33%)~16.44s16.58sp=0.747 n=6
Emit Time0.00s (±244.70%)0.00s~~~p=0.405 n=6
Total Time20.99s (± 0.34%)21.01s (± 0.20%)~20.97s21.07sp=0.810 n=6
vscode - node (v18.15.0, x64)
Errors33~~~p=1.000 n=6
Symbols3,233,9513,233,951~~~p=1.000 n=6
Types1,113,6471,113,647~~~p=1.000 n=6
Memory used3,298,660k (± 0.01%)3,298,448k (± 0.01%)~3,297,993k3,298,967kp=0.378 n=6
Parse Time14.20s (± 0.54%)14.05s (± 0.47%)-0.15s (- 1.07%)13.97s14.17sp=0.013 n=6
Bind Time4.61s (± 3.06%)4.91s (±15.83%)~4.51s6.49sp=0.470 n=6
Check Time87.28s (± 0.80%)88.36s (± 3.99%)~84.18s94.92sp=0.471 n=6
Emit Time28.34s (± 2.78%)27.61s (± 8.42%)~23.18s29.35sp=1.000 n=6
Total Time134.42s (± 0.96%)134.93s (± 1.28%)~132.09s136.63sp=0.378 n=6
webpack - node (v18.15.0, x64)
Errors00~~~p=1.000 n=6
Symbols291,562291,562~~~p=1.000 n=6
Types118,971118,971~~~p=1.000 n=6
Memory used445,141k (± 0.01%)445,144k (± 0.01%)~445,080k445,218kp=0.936 n=6
Parse Time3.31s (± 0.23%)3.29s (± 0.46%)-0.02s (- 0.75%)3.27s3.31sp=0.017 n=6
Bind Time1.49s (± 0.55%)1.47s (± 1.03%)-0.02s (- 1.46%)1.45s1.49sp=0.025 n=6
Check Time15.65s (± 0.31%)15.60s (± 0.36%)~15.54s15.69sp=0.149 n=6
Emit Time0.00s0.00s~~~p=1.000 n=6
Total Time20.45s (± 0.22%)20.35s (± 0.29%)-0.10s (- 0.47%)20.29s20.44sp=0.019 n=6
xstate-main - node (v18.15.0, x64)
Errors55~~~p=1.000 n=6
Symbols555,017555,017~~~p=1.000 n=6
Types186,115186,115~~~p=1.000 n=6
Memory used493,923k (± 0.01%)493,829k (± 0.00%)-94k (- 0.02%)493,786k493,850kp=0.005 n=6
Parse Time2.77s (± 0.15%)2.77s (± 0.20%)~2.76s2.77sp=0.282 n=6
Bind Time0.95s (± 0.57%)0.96s (± 0.43%)~0.95s0.96sp=0.282 n=6
Check Time16.29s (± 0.13%)16.26s (± 0.23%)~16.22s16.33sp=0.126 n=6
Emit Time0.00s0.00s (±244.70%)~0.00s0.01sp=0.405 n=6
Total Time20.01s (± 0.12%)19.99s (± 0.20%)~19.94s20.06sp=0.103 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • Compiler-Unions - node (v18.15.0, x64)
  • angular-1 - node (v18.15.0, x64)
  • mui-docs - node (v18.15.0, x64)
  • self-build-src - node (v18.15.0, x64)
  • self-build-src-public-api - node (v18.15.0, x64)
  • self-compiler - node (v18.15.0, x64)
  • ts-pre-modules - node (v18.15.0, x64)
  • vscode - node (v18.15.0, x64)
  • webpack - node (v18.15.0, x64)
  • xstate-main - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

tsserver

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
Compiler-UnionsTSServer - node (v18.15.0, x64)
Req 1 - updateOpen2,328ms (± 0.54%)2,325ms (± 0.40%)~2,311ms2,338msp=0.378 n=6
Req 2 - geterr5,304ms (± 0.47%)5,321ms (± 0.37%)~5,292ms5,341msp=0.258 n=6
Req 3 - references261ms (± 1.58%)268ms (± 1.11%)+7ms (+ 2.81%)262ms270msp=0.015 n=6
Req 4 - navto228ms (± 0.36%)226ms (± 0.66%)~225ms228msp=0.087 n=6
Req 5 - completionInfo count1,3571,357~~~p=1.000 n=6
Req 5 - completionInfo80ms (± 2.50%)76ms (± 0.54%)🟩-4ms (- 5.21%)75ms76msp=0.009 n=6
CompilerTSServer - node (v18.15.0, x64)
Req 1 - updateOpen3,005ms (± 0.74%)2,985ms (± 0.39%)~2,962ms2,994msp=0.261 n=6
Req 2 - geterr5,393ms (±11.95%)4,991ms (± 9.34%)~4,733ms5,939msp=0.261 n=6
Req 3 - references432ms (± 8.89%)410ms (± 9.85%)~350ms445msp=0.378 n=6
Req 4 - navto373ms (± 8.18%)358ms (± 9.53%)~314ms395msp=0.378 n=6
Req 5 - completionInfo count1,5191,519~~~p=1.000 n=6
Req 5 - completionInfo113ms (± 6.32%)111ms (±18.34%)~87ms135msp=1.000 n=6
xstate-main-1-tsserver - node (v18.15.0, x64)
Req 1 - updateOpen5,272ms (± 0.18%)5,282ms (± 0.21%)~5,268ms5,296msp=0.198 n=6
Req 2 - geterr1,155ms (± 0.76%)1,156ms (± 2.08%)~1,115ms1,180msp=0.748 n=6
Req 3 - references83ms (± 0.62%)77ms (± 4.19%)🟩-6ms (- 7.46%)75ms83msp=0.022 n=6
Req 4 - navto450ms (± 0.26%)448ms (± 0.73%)~444ms453msp=0.369 n=6
Req 5 - completionInfo count3,4503,450~~~p=1.000 n=6
Req 5 - completionInfo843ms (± 1.52%)830ms (± 1.41%)-14ms (- 1.60%)816ms851msp=0.045 n=6
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • CompilerTSServer - node (v18.15.0, x64)
  • Compiler-UnionsTSServer - node (v18.15.0, x64)
  • xstate-main-1-tsserver - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

startup

Comparison Report - baseline..pr
MetricbaselineprDeltaBestWorstp-value
tsc-startup - node (v18.15.0, x64)
Execution time159.39ms (± 0.22%)159.36ms (± 0.19%)~158.24ms161.98msp=0.937 n=600
tsserver-startup - node (v18.15.0, x64)
Execution time233.53ms (± 0.16%)234.06ms (± 0.80%)+0.53ms (+ 0.23%)231.86ms267.23msp=0.000 n=600
tsserverlibrary-startup - node (v18.15.0, x64)
Execution time229.44ms (± 0.16%)229.33ms (± 0.14%)-0.11ms (- 0.05%)227.85ms232.51msp=0.011 n=600
typescript-startup - node (v18.15.0, x64)
Execution time229.66ms (± 0.17%)229.66ms (± 0.15%)~227.88ms234.49msp=0.543 n=600
System info unknown
Hosts
  • node (v18.15.0, x64)
Scenarios
  • tsc-startup - node (v18.15.0, x64)
  • tsserver-startup - node (v18.15.0, x64)
  • tsserverlibrary-startup - node (v18.15.0, x64)
  • typescript-startup - node (v18.15.0, x64)
BenchmarkNameIterations
Currentpr6
Baselinebaseline6

Developer Information:

Download Benchmarks

Comment threadsrc/compiler/path.ts
path = normalizeSlashes(path);
}

const simpleNormalized = simpleNormalizePath(path);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simpleNormalizePath also calls normalizeSlashes on the first line of the function, which is redundant. I'd suggest you remove the line from simpleNormalizePath and just ensure its other callers normalize slashes before calling.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, that was my intention, good catch!

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benchmarks I shared already reflect that; I just made a copy/paste error updating this PR.

@andrewbranch
Andrew Branch (andrewbranch) merged commit e973805 into microsoft:mainJan 9, 2025
@andrewbranch
Andrew Branch (andrewbranch) deleted the perf/normalizePath branch January 9, 2025 19:36
@dbaeumer

Copy link
Copy Markdown
Member

Thanks!!

@dsherret

Copy link
Copy Markdown
Contributor

Sweet. Thanks! We noticed this in Deno in TS 5.7 and I was just about to investigate opening a PR to fix it.

@microsoftMicrosoft (microsoft) locked as resolved and limited conversation to collaborators Oct 15, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Author: TeamFor Uncommitted BugPR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

@andrewbranch@typescript-bot@DanielRosenwasser@dbaeumer@dsherret@rbuckton@sandersn