Skip to content

Make NodeId and SymbolId into uint64s, fix up KeyBuilder #243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 11, 2025

Conversation

jakebailey
Copy link
Member

In looking at these structs, I realized that these IDs can be uint64s without affecting any sizing at all. This would make me a lot less afraid of us overflowing on these shared resources.

goos: linux
goarch: amd64
pkg: github.com/microsoft/typescript-go/internal/binder
cpu: Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz
                                                     │   old.txt    │               new.txt               │
                                                     │    sec/op    │    sec/op     vs base               │
Bind/empty.ts-20                                       580.8n ± 10%   625.5n ± 11%       ~ (p=0.218 n=10)
Bind/checker.ts-20                                     20.51m ±  3%   20.69m ±  5%       ~ (p=0.684 n=10)
Bind/dom.generated.d.ts-20                             8.072m ±  6%   7.845m ±  8%       ~ (p=0.912 n=10)
Bind/Herebyfile.mjs-20                                 332.9µ ±  2%   324.5µ ±  6%       ~ (p=0.739 n=10)
Bind/jsxComplexSignatureHasApplicabilityError.tsx-20   157.7µ ±  6%   160.9µ ±  5%       ~ (p=0.481 n=10)
geomean                                                347.2µ         350.6µ        +0.98%

                                                     │   old.txt    │                new.txt                │
                                                     │     B/op     │     B/op      vs base                 │
Bind/empty.ts-20                                         816.0 ± 0%     816.0 ± 0%       ~ (p=1.000 n=10) ¹
Bind/checker.ts-20                                     8.041Mi ± 0%   8.041Mi ± 0%       ~ (p=0.796 n=10)
Bind/dom.generated.d.ts-20                             5.363Mi ± 0%   5.363Mi ± 0%       ~ (p=0.315 n=10)
Bind/Herebyfile.mjs-20                                 172.0Ki ± 0%   172.0Ki ± 0%       ~ (p=0.643 n=10)
Bind/jsxComplexSignatureHasApplicabilityError.tsx-20   117.0Ki ± 0%   117.0Ki ± 0%       ~ (p=0.641 n=10)
geomean                                                235.6Ki        235.6Ki       +0.00%
¹ all samples are equal

                                                     │   old.txt   │               new.txt                │
                                                     │  allocs/op  │  allocs/op   vs base                 │
Bind/empty.ts-20                                        3.000 ± 0%    3.000 ± 0%       ~ (p=1.000 n=10) ¹
Bind/checker.ts-20                                     13.68k ± 0%   13.68k ± 0%       ~ (p=0.373 n=10)
Bind/dom.generated.d.ts-20                             15.30k ± 0%   15.30k ± 0%       ~ (p=0.619 n=10)
Bind/Herebyfile.mjs-20                                  310.0 ± 0%    310.0 ± 0%       ~ (p=1.000 n=10) ¹
Bind/jsxComplexSignatureHasApplicabilityError.tsx-20    259.0 ± 0%    259.0 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                 550.2         550.2       -0.00%
¹ all samples are equal

pkg: github.com/microsoft/typescript-go/internal/parser
                                                      │   old.txt   │              new.txt               │
                                                      │   sec/op    │   sec/op     vs base               │
Parse/empty.ts-20                                       754.8n ± 1%   756.5n ± 1%       ~ (p=0.754 n=10)
Parse/checker.ts-20                                     46.05m ± 2%   46.16m ± 3%       ~ (p=0.353 n=10)
Parse/dom.generated.d.ts-20                             15.28m ± 2%   14.94m ± 1%  -2.22% (p=0.005 n=10)
Parse/Herebyfile.mjs-20                                 634.8µ ± 1%   639.4µ ± 2%       ~ (p=0.105 n=10)
Parse/jsxComplexSignatureHasApplicabilityError.tsx-20   258.3µ ± 1%   261.7µ ± 1%  +1.35% (p=0.023 n=10)
geomean                                                 613.7µ        614.1µ       +0.06%

                                                      │   old.txt    │                new.txt                │
                                                      │     B/op     │     B/op      vs base                 │
Parse/empty.ts-20                                       2.328Ki ± 0%   2.328Ki ± 0%       ~ (p=1.000 n=10) ¹
Parse/checker.ts-20                                     24.31Mi ± 0%   24.30Mi ± 0%       ~ (p=0.631 n=10)
Parse/dom.generated.d.ts-20                             8.617Mi ± 0%   8.617Mi ± 0%       ~ (p=0.247 n=10)
Parse/Herebyfile.mjs-20                                 359.2Ki ± 0%   359.5Ki ± 0%  +0.07% (p=0.023 n=10)
Parse/jsxComplexSignatureHasApplicabilityError.tsx-20   157.1Ki ± 0%   157.3Ki ± 0%  +0.09% (p=0.023 n=10)
geomean                                                 492.1Ki        492.3Ki       +0.03%
¹ all samples are equal

                                                      │   old.txt   │               new.txt                │
                                                      │  allocs/op  │  allocs/op   vs base                 │
Parse/empty.ts-20                                        6.000 ± 0%    6.000 ± 0%       ~ (p=1.000 n=10) ¹
Parse/checker.ts-20                                     156.0k ± 0%   156.0k ± 0%       ~ (p=0.303 n=10)
Parse/dom.generated.d.ts-20                             72.32k ± 0%   72.32k ± 0%       ~ (p=0.162 n=10)
Parse/Herebyfile.mjs-20                                 2.598k ± 0%   2.599k ± 0%       ~ (p=0.350 n=10)
Parse/jsxComplexSignatureHasApplicabilityError.tsx-20    917.0 ± 0%    917.0 ± 0%       ~ (p=1.000 n=10) ¹
geomean                                                 2.764k        2.764k       +0.00%
¹ all samples are equal

The only other places these IDs would be used in map keys, but even if a map contained a million entries, the amount of memory used for the keys would only increase by 4MB. And, we're honestly more likely to use node pointers as keys anyhow.

I did not touch type IDs, which are local to a checker, and I think less likely to overflow because of that.

@@ -11211,19 +11211,31 @@ var base64chars = []byte{
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '$', '%',
}

func (b *KeyBuilder) WriteInt(value int) {
func (b *KeyBuilder) WriteUint64(value uint64) {
for value != 0 {
Copy link
Member Author

Choose a reason for hiding this comment

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

This code is subtly wrong thanks to sign extension, so when we cast to int outside it's possible we break. But we wouldn't have observed it yet because we haven't gotten up to MaxInt in any test so far (but would in a build mode, editor, etc)

@ahejlsberg
Copy link
Member

ahejlsberg commented Jan 21, 2025

Hmm, I don't know about this. Each symbol consumes 120 bytes just for the struct itself, plus what it references. That's at least 500Gb of allocated symbols for which we have to request IDs before an overflow occurs (but more likely multiple terabytes). Nodes are similar. In fact, the checker rarely asks for node IDs. I really don't think we need this. I'd sooner expand NodeFlags and SymbolFlags, or at least keep the space around for that.

@jakebailey
Copy link
Member Author

For batch compilation, I generally agree, but for long-running processes like tsserver or the API, I don't think it's entirely impossible for it to get to this point after a lot of typing and no restarting. That's the main concern I'm having.

(That's why I'm not concerned about checkers, since those are tossed on every change)

@RyanCavanaugh
Copy link
Member

tsc in src/compiler (Strada) generates 262,426 symbols, so barring other caching, we'd hit 232 in only 16,000 edits (6 hours of active typing at a leisurely 40 WPM). For a week-long session it'd be very easy to hit that limit

@RyanCavanaugh RyanCavanaugh requested a review from Copilot February 6, 2025 00:27
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 6 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • internal/ast/ids.go: Evaluated as low risk

@jakebailey jakebailey requested a review from Copilot February 13, 2025 00:08
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot reviewed 5 out of 6 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • internal/checker/checker.go: Evaluated as low risk

@jakebailey jakebailey requested a review from ahejlsberg March 4, 2025 21:51
@jakebailey jakebailey added this pull request to the merge queue Mar 11, 2025
Merged via the queue into main with commit d508afb Mar 11, 2025
17 checks passed
@jakebailey jakebailey deleted the jabaile/64bitid branch March 12, 2025 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants