Skip to content
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

Performance regression in react-hook-form from 4.4 to 4.5 #46948

Closed
andrewbranch opened this issue Nov 29, 2021 · 12 comments
Closed

Performance regression in react-hook-form from 4.4 to 4.5 #46948

andrewbranch opened this issue Nov 29, 2021 · 12 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@andrewbranch
Copy link
Member

andrewbranch commented Nov 29, 2021

I'm experiencing the same issue. With 4.5.2 it takes 2 minutes to simply load a type hint on hover (Controller from react-hook-form in this particular case). Our project is indeed huge, but the same operation with vs code's built-in 4.4.3 is instant.

I have no idea what's happening under the hood, but these are the two things from the server log that look very slow in 4.52:

  • "command":"geterr" - almost two minutes until "event":"requestCompleted" against ~10ms for 4.4.3
  • 44::encodedSemanticClassifications-full: elapsed time (in milliseconds) 109280.8950 against less than 1s first time and less than 10ms later for 4.4.3
Part of TS 4.5.2 server log
Info 2001 [19:47:33.826] request:
    {"seq":41,"type":"request","command":"geterr","arguments":{"delay":0,"files":["/Users/aleksei.tsikov/git/project/src/Component.tsx"]}}
Perf 2002 [19:47:33.827] 41::geterr: async elapsed time (in milliseconds) 0.3917
Info 2003 [19:47:33.828] event:
    {"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","diagnostics":[]}}
Info 2004 [19:49:29.994] event:
    {"seq":0,"type":"event","event":"requestCompleted","body":{"request_seq":41}}
Info 2005 [19:49:29.996] request:
    {"seq":42,"type":"request","command":"getApplicableRefactors","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","startLine":1,"startOffset":1,"endLine":1,"endOffset":1}}
Perf 2006 [19:49:30.009] 42::getApplicableRefactors: elapsed time (in milliseconds) 13.2598
Info 2007 [19:49:30.009] response:
    {"seq":0,"type":"response","command":"getApplicableRefactors","request_seq":42,"success":true,"body":[{"name":"Convert export","description":"Convert default export to named export","actions":[{"name":"Convert default export to named export","description":"Convert default export to named export","kind":"refactor.rewrite.export.named","notApplicableReason":"Could not find export statement"},{"name":"Convert named export to default export","description":"Convert named export to default export","kind":"refactor.rewrite.export.default","notApplicableReason":"Could not find export statement"}]},{"name":"Convert import","description":"Convert namespace import to named imports","actions":[{"name":"Convert namespace import to named imports","description":"Convert namespace import to named imports","kind":"refactor.rewrite.import.named","notApplicableReason":"Selection is not an import declaration."}]},{"name":"Convert import","description":"Convert named imports to namespace import","actions":[{"name":"Convert named imports to namespace import","description":"Convert named imports to namespace import","kind":"refactor.rewrite.import.namespace","notApplicableReason":"Selection is not an import declaration."}]},{"name":"Extract Symbol","description":"Extract function","actions":[{"name":"Extract Function","description":"Extract function","kind":"refactor.extract.function","notApplicableReason":"Cannot extract empty range."}]},{"name":"Extract Symbol","description":"Extract constant","actions":[{"name":"Extract Constant","description":"Extract constant","kind":"refactor.extract.constant","notApplicableReason":"Cannot extract empty range."}]},{"name":"Extract type","description":"Extract type","actions":[{"name":"Extract to typedef","description":"Extract to typedef","kind":"refactor.extract.typedef","notApplicableReason":"Selection is not a valid type node"},{"name":"Extract to type alias","description":"Extract to type alias","kind":"refactor.extract.type","notApplicableReason":"Selection is not a valid type node"},{"name":"Extract to interface","description":"Extract to interface","kind":"refactor.extract.interface","notApplicableReason":"Selection is not a valid type node"}]},{"name":"Move to a new file","description":"Move to a new file","actions":[{"name":"Move to a new file","description":"Move to a new file","kind":"refactor.move.newFile","notApplicableReason":"Selection is not a valid statement or statements"}]},{"name":"Add or remove braces in an arrow function","description":"Add or remove braces in an arrow function","actions":[{"name":"Add braces to arrow function","description":"Add braces to arrow function","kind":"refactor.rewrite.arrow.braces.add","notApplicableReason":"Could not find a containing arrow function"},{"name":"Remove braces from arrow function","description":"Remove braces from arrow function","kind":"refactor.rewrite.arrow.braces.remove","notApplicableReason":"Could not find a containing arrow function"}]},{"name":"Convert to template string","description":"Convert to template string","actions":[{"name":"Convert to template string","description":"Convert to template string","kind":"refactor.rewrite.string","notApplicableReason":"Can only convert string concatenation"}]},{"name":"Infer function return type","description":"Infer function return type","actions":[{"name":"Infer function return type","description":"Infer function return type","kind":"refactor.rewrite.function.returnType","notApplicableReason":"Return type must be inferred from a function"}]}]}
Info 2008 [19:49:30.009] request:
    {"seq":43,"type":"request","command":"projectInfo","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","needFileNameList":false}}
Perf 2009 [19:49:30.009] 43::projectInfo: elapsed time (in milliseconds) 0.1021
Info 2010 [19:49:30.009] response:
    {"seq":0,"type":"response","command":"projectInfo","request_seq":43,"success":true,"body":{"configFileName":"/Users/aleksei.tsikov/git/project/tsconfig.json","languageServiceDisabled":false}}
Info 2011 [19:49:30.011] request:
    {"seq":44,"type":"request","command":"encodedSemanticClassifications-full","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","start":1277,"length":3642,"format":"2020"}}
Perf 2012 [19:51:19.295] 44::encodedSemanticClassifications-full: elapsed time (in milliseconds) 109280.8950
Info 2013 [19:51:19.295] response:
    {"seq":0,"type":"response","command":"encodedSemanticClassifications-full","request_seq":44,"success":true,"body":{"spans":[1281,8,2561,1312,6,2561,1342,8,2561,1368,6,2561,1403,29,2825,1436,11,1793,1449,11,1536,1463,17,1544,1496,11,1792,1678,11,1792,1702,5,1537,1712,5,2561,1720,4,1536,1728,15,2561,1769,16,2057,1787,3,1536,1791,5,1536,1803,5,1793,1810,15,1793,1844,5,2857,1851,12,2857,1865,7,2089,1874,8,2857,1887,7,2816,1895,10,1536,1913,13,2561,1936,9,2561,1947,15,1792,1970,8,2561,1980,8,2816,1989,10,2816,2004,4,272,2023,6,2561,2031,10,2816,2046,4,272,2066,4,2561,2100,11,2560,2113,5,2857,2120,4,2089,2126,6,2089,2137,11,2816,2150,6,1793,2158,10,1536,2177,3,2056,2181,4,2560,2186,23,3072,2218,9,2561,2229,6,1792,2236,9,2560,2253,8,2561,2263,6,1792,2270,8,2560,2279,7,3088,2296,6,2561,2304,6,1792,2311,6,2560,2318,7,3088,2350,12,2089,2365,4,2088,2371,4,2560,2393,11,2089,2406,19,2089,2430,13,2816,2444,12,2088,2467,11,2089,2481,7,2816,2501,5,1792,2514,3,3088,2518,8,1793,2533,5,2561,2540,8,1792,2549,3,2560,2554,5,2561,2561,8,1792,2570,5,2560,2586,5,1792,2607,9,2089,2619,5,2856,2646,8,2089,2657,5,2856,2800,15,1792,2868,7,2088,2933,5,1793,3044,11,2088,3288,7,2088,3348,5,1793,3475,5,1792,3481,5,2560,3514,5,1793,3549,8,2089,3560,10,2816,3571,5,1792,3598,5,1792,3604,8,3072,3613,8,2088,3641,8,2856,3660,7,2816,3668,8,2088,3789,7,2088,3847,5,1793,3999,6,2561,4007,8,2088,4035,5,2561,4042,8,2816,4051,8,2088,4107,5,1792,4113,5,2560,4146,5,1793,4175,5,1792,4181,8,3072,4190,10,2816,4201,5,1792,4381,12,2856,4394,10,1793,4408,5,2856,4414,10,1792,4475,9,2088,4618,29,2824,4648,6,2088,4673,11,2088,4705,7,2056,4754,6,2088,4865,19,2088],"endOfLineState":0}}
Info 2014 [19:51:19.297] request:
    {"seq":47,"type":"request","command":"provideInlayHints","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","start":714,"length":4205}}
Perf 2015 [19:51:19.350] 47::provideInlayHints: elapsed time (in milliseconds) 52.9589
Info 2016 [19:51:19.350] response:
    {"seq":0,"type":"response","command":"provideInlayHints","request_seq":47,"success":true,"body":[{"text":": PropsWithChildren<CellProps...","position":{"line":36,"offset":21},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":36,"offset":22},"kind":"Type","whitespaceBefore":true},{"text":"date:","position":{"line":36,"offset":56},"kind":"Parameter","whitespaceAfter":true},{"text":": PropsWithChildren<CellProps...","position":{"line":49,"offset":21},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":49,"offset":22},"kind":"Type","whitespaceBefore":true},{"text":"value:","position":{"line":50,"offset":34},"kind":"Parameter","whitespaceAfter":true},{"text":": (queryStatus: QueryStatus) ...","position":{"line":63,"offset":36},"kind":"Type","whitespaceBefore":true},{"text":": Props","position":{"line":79,"offset":72},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":79,"offset":73},"kind":"Type","whitespaceBefore":true},{"text":"props:","position":{"line":80,"offset":74},"kind":"Parameter","whitespaceAfter":true},{"text":"date:","position":{"line":83,"offset":26},"kind":"Parameter","whitespaceAfter":true},{"text":"amount:","position":{"line":83,"offset":50},"kind":"Parameter","whitespaceAfter":true},{"text":"date:","position":{"line":83,"offset":37},"kind":"Parameter","whitespaceAfter":true},{"text":"date:","position":{"line":84,"offset":26},"kind":"Parameter","whitespaceAfter":true},{"text":"mutationFn:","position":{"line":89,"offset":60},"kind":"Parameter","whitespaceAfter":true},{"text":": AxiosPromise<RevPTransactio...","position":{"line":89,"offset":80},"kind":"Type","whitespaceBefore":true},{"text":": RevPTransaction[]","position":{"line":97,"offset":21},"kind":"Type","whitespaceBefore":true},{"text":"data:","position":{"line":99,"offset":62},"kind":"Parameter","whitespaceAfter":true},{"text":": { label: string; value: str...","position":{"line":101,"offset":20},"kind":"Type","whitespaceBefore":true},{"text":"factory:","position":{"line":102,"offset":5},"kind":"Parameter","whitespaceAfter":true},{"text":"deps:","position":{"line":103,"offset":5},"kind":"Parameter","whitespaceAfter":true},{"text":": { label: string; value: str...","position":{"line":102,"offset":7},"kind":"Type","whitespaceBefore":true},{"text":"callbackfn:","position":{"line":102,"offset":29},"kind":"Parameter","whitespaceAfter":true},{"text":": Card","position":{"line":102,"offset":37},"kind":"Type","whitespaceBefore":true},{"text":": string","position":{"line":106,"offset":18},"kind":"Type","whitespaceBefore":true},{"text":"name:","position":{"line":106,"offset":27},"kind":"Parameter","whitespaceAfter":true},{"text":": Date","position":{"line":107,"offset":17},"kind":"Type","whitespaceBefore":true},{"text":"name:","position":{"line":107,"offset":26},"kind":"Parameter","whitespaceAfter":true},{"text":": { field: ControllerRenderPr...","position":{"line":117,"offset":33},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":117,"offset":34},"kind":"Type","whitespaceBefore":true},{"text":": { field: ControllerRenderPr...","position":{"line":132,"offset":31},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":132,"offset":32},"kind":"Type","whitespaceBefore":true},{"text":": Date | null","position":{"line":137,"offset":32},"kind":"Type","whitespaceBefore":true},{"text":": Date","position":{"line":138,"offset":33},"kind":"Type","whitespaceBefore":true},{"text":"date:","position":{"line":138,"offset":47},"kind":"Parameter","whitespaceAfter":true},{"text":"...event:","position":{"line":140,"offset":34},"kind":"Parameter","whitespaceAfter":true},{"text":"name:","position":{"line":141,"offset":28},"kind":"Parameter","whitespaceAfter":true},{"text":"value:","position":{"line":141,"offset":38},"kind":"Parameter","whitespaceAfter":true},{"text":"date:","position":{"line":141,"offset":46},"kind":"Parameter","whitespaceAfter":true},{"text":"amount:","position":{"line":141,"offset":56},"kind":"Parameter","whitespaceAfter":true},{"text":": { field: ControllerRenderPr...","position":{"line":149,"offset":31},"kind":"Type","whitespaceBefore":true},{"text":": Element","position":{"line":149,"offset":32},"kind":"Type","whitespaceBefore":true},{"text":"date:","position":{"line":155,"offset":35},"kind":"Parameter","whitespaceAfter":true},{"text":"amount:","position":{"line":155,"offset":45},"kind":"Parameter","whitespaceAfter":true},{"text":": Date | null","position":{"line":158,"offset":32},"kind":"Type","whitespaceBefore":true},{"text":"...event:","position":{"line":159,"offset":34},"kind":"Parameter","whitespaceAfter":true},{"text":"date:","position":{"line":159,"offset":45},"kind":"Parameter","whitespaceAfter":true},{"text":"onValid:","position":{"line":168,"offset":35},"kind":"Parameter","whitespaceAfter":true},{"text":": { cardToken: string; dateFr...","position":{"line":168,"offset":45},"kind":"Type","whitespaceBefore":true},{"text":"variables:","position":{"line":168,"offset":55},"kind":"Parameter","whitespaceAfter":true},{"text":"queryStatus:","position":{"line":178,"offset":55},"kind":"Parameter","whitespaceAfter":true}]}
Info 2017 [19:51:19.350] request:
    {"seq":48,"type":"request","command":"getApplicableRefactors","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","startLine":126,"startOffset":17,"endLine":126,"endOffset":17}}
Perf 2018 [19:51:19.352] 48::getApplicableRefactors: elapsed time (in milliseconds) 2.1181
Info 2019 [19:51:19.352] response:
    {"seq":0,"type":"response","command":"getApplicableRefactors","request_seq":48,"success":true,"body":[{"name":"Convert export","description":"Convert default export to named export","actions":[{"name":"Convert default export to named export","description":"Convert default export to named export","kind":"refactor.rewrite.export.named","notApplicableReason":"Could not find export statement"},{"name":"Convert named export to default export","description":"Convert named export to default export","kind":"refactor.rewrite.export.default","notApplicableReason":"Could not find export statement"}]},{"name":"Convert import","description":"Convert namespace import to named imports","actions":[{"name":"Convert namespace import to named imports","description":"Convert namespace import to named imports","kind":"refactor.rewrite.import.named","notApplicableReason":"Selection is not an import declaration."}]},{"name":"Convert import","description":"Convert named imports to namespace import","actions":[{"name":"Convert named imports to namespace import","description":"Convert named imports to namespace import","kind":"refactor.rewrite.import.namespace","notApplicableReason":"Selection is not an import declaration."}]},{"name":"Extract Symbol","description":"Extract function","actions":[{"name":"Extract Function","description":"Extract function","kind":"refactor.extract.function","notApplicableReason":"Cannot extract empty range."}]},{"name":"Extract Symbol","description":"Extract constant","actions":[{"name":"Extract Constant","description":"Extract constant","kind":"refactor.extract.constant","notApplicableReason":"Cannot extract empty range."}]},{"name":"Extract type","description":"Extract type","actions":[{"name":"Extract to typedef","description":"Extract to typedef","kind":"refactor.extract.typedef","notApplicableReason":"Selection is not a valid type node"},{"name":"Extract to type alias","description":"Extract to type alias","kind":"refactor.extract.type","notApplicableReason":"Selection is not a valid type node"},{"name":"Extract to interface","description":"Extract to interface","kind":"refactor.extract.interface","notApplicableReason":"Selection is not a valid type node"}]},{"name":"Generate 'get' and 'set' accessors","description":"Generate 'get' and 'set' accessors","actions":[{"name":"Generate 'get' and 'set' accessors","description":"Generate 'get' and 'set' accessors","kind":"refactor.rewrite.property.generateAccessors","notApplicableReason":"Could not find property for which to generate accessor"}]},{"name":"Move to a new file","description":"Move to a new file","actions":[{"name":"Move to a new file","description":"Move to a new file","kind":"refactor.move.newFile","notApplicableReason":"Selection is not a valid statement or statements"}]},{"name":"Convert to template string","description":"Convert to template string","actions":[{"name":"Convert to template string","description":"Convert to template string","kind":"refactor.rewrite.string","notApplicableReason":"Can only convert string concatenation"}]},{"name":"Infer function return type","description":"Infer function return type","actions":[{"name":"Infer function return type","description":"Infer function return type","kind":"refactor.rewrite.function.returnType","notApplicableReason":"Return type must be inferred from a function"}]}]}
Info 2020 [19:51:19.353] request:
    {"seq":50,"type":"request","command":"quickinfo","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","line":129,"offset":16}}
Perf 2021 [19:51:19.364] 50::quickinfo: elapsed time (in milliseconds) 11.1055
Info 2022 [19:51:19.364] response:
    {"seq":0,"type":"response","command":"quickinfo","request_seq":50,"success":true,"body":{"kind":"alias","kindModifiers":"declare","start":{"line":129,"offset":12},"end":{"line":129,"offset":22},"displayString":"(alias) const Controller: <TFieldValues extends FieldValues = FieldValues, TName extends Path<TFieldValues> = Path<TFieldValues>>(props: ControllerProps<TFieldValues, TName>) => import(\"react\").ReactElement<any, string | import(\"react\").JSXElementConstructor<any>>\nimport Controller","documentation":[],"tags":[]}}
Info 2023 [19:51:19.364] request:
    {"seq":51,"type":"request","command":"geterr","arguments":{"delay":0,"files":["/Users/aleksei.tsikov/git/project/src/Component.tsx"]}}
Perf 2024 [19:51:19.364] 51::geterr: async elapsed time (in milliseconds) 0.4231
Info 2025 [19:51:19.366] event:
    {"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","diagnostics":[]}}
Info 2026 [19:51:19.825] event:
    {"seq":0,"type":"event","event":"requestCompleted","body":{"request_seq":51}}
Info 2027 [19:51:19.827] request:
    {"seq":52,"type":"request","command":"quickinfo","arguments":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","line":129,"offset":16}}
Perf 2028 [19:51:19.839] 52::quickinfo: elapsed time (in milliseconds) 11.8457
Info 2029 [19:51:19.839] response:
    {"seq":0,"type":"response","command":"quickinfo","request_seq":52,"success":true,"body":{"kind":"alias","kindModifiers":"declare","start":{"line":129,"offset":12},"end":{"line":129,"offset":22},"displayString":"(alias) const Controller: <TFieldValues extends FieldValues = FieldValues, TName extends Path<TFieldValues> = Path<TFieldValues>>(props: ControllerProps<TFieldValues, TName>) => import(\"react\").ReactElement<any, string | import(\"react\").JSXElementConstructor<any>>\nimport Controller","documentation":[],"tags":[]}}
Info 2030 [19:51:19.839] request:
    {"seq":53,"type":"request","command":"geterr","arguments":{"delay":0,"files":["/Users/aleksei.tsikov/git/project/src/Component.tsx"]}}
Perf 2031 [19:51:19.840] 53::geterr: async elapsed time (in milliseconds) 0.1562
Info 2032 [19:51:19.841] event:
    {"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"/Users/aleksei.tsikov/git/project/src/Component.tsx","diagnostics":[]}}

...

Here's the minimal repro (basically, only react and react-hook-form) https://github.com/atsikov/ts-4.5.2-perf-issue

I've found out that this issue is reproducible with react-hook-form < 7.17.2. In react-hook-form/react-hook-form@85097ae types were improved, so with >= 7.17.2 type hints and autocomplete work as expected.

...

4.5.2 created 30 times more (intermediate?) types and consumed 8 times more memory.

TS 4.4.4 extended diagnostics
Files:                         50
Lines of Library:           26160
Lines of Definitions:       24762
Lines of TypeScript:           14
Lines of JavaScript:            0
Lines of JSON:                  0
Lines of Other:                 0
Nodes of Library:          112958
Nodes of Definitions:       60457
Nodes of TypeScript:           55
Nodes of JavaScript:            0
Nodes of JSON:                  0
Nodes of Other:                 0
Identifiers:                58865
Symbols:                    39464
Types:                      28967
Instantiations:             86282
Memory used:               93470K
Assignability cache size:   17107
Identity cache size:           62
Subtype cache size:             0
Strict subtype cache size:      0
I/O Read time:              0.01s
Parse time:                 0.48s
ResolveModule time:         0.02s
ResolveTypeReference time:  0.00s
Program time:               0.53s
Bind time:                  0.21s
Check time:                 0.64s
printTime time:             0.00s
Emit time:                  0.00s
Total time:                 1.39s
TS 4.5.2 extended diagnostics
Files:                          50
Lines of Library:            25009
Lines of Definitions:        24762
Lines of TypeScript:            14
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Nodes of Library:           112478
Nodes of Definitions:        60453
Nodes of TypeScript:            55
Nodes of JavaScript:             0
Nodes of JSON:                   0
Nodes of Other:                  0
Identifiers:                 58582
Symbols:                     39008
Types:                     1048793
Instantiations:             135356
Memory used:               724704K
Assignability cache size:  7007111
Identity cache size:            27
Subtype cache size:              0
Strict subtype cache size:       0
I/O Read time:               0.03s
Parse time:                  0.49s
ResolveModule time:          0.02s
ResolveTypeReference time:   0.00s
Program time:                0.57s
Bind time:                   0.22s
Check time:                 93.30s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                 94.09s

Originally posted by @atsikov in #46735 (comment)

@andrewbranch
Copy link
Member Author

andrewbranch commented Nov 29, 2021

More context and a larger repro from @kmoschcau:

Hi, I hope I can give some additional helpful info. I maintain a repo with some fairly complex generic types and I can see a huge performance difference in both tsc and tsserver between 4.4.4 and 4.5.2.

Also I don't think this is really related to the VSCode plugin, because I use (Neo)Vim and a language client plugin in there to talk to tsserver. The autocompletion with 4.4.4 is there in less than a second while 4.5.2 sometimes takes longer than 5 seconds. (My client just lets it time out then.) Another thing I observed is that the hover comes up fairly quickly, but autocompletion does not. When the repo files are freshly changed both take a really long time to come up.

Here is the repo: https://github.com/League-of-Foundry-Developers/foundry-vtt-types
You should be able to compile it with both typescript versions by just cloning it, running npm ci and then tsc in the root. I ran both versions with --extendedDiagnostics on this repo and here are the stats for both runs. (Especially of note are the tripled amount of types and the more than doubled check time.)

4.4.4
tsc --extendedDiagnostics
Files:                         478
Lines of Library:            27589
Lines of Definitions:       146444
Lines of TypeScript:             0
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Nodes of Library:           114619
Nodes of Definitions:       341949
Nodes of TypeScript:             0
Nodes of JavaScript:             0
Nodes of JSON:                   0
Nodes of Other:                  0
Identifiers:                168963
Symbols:                    196745
Types:                       80541
Instantiations:             176586
Memory used:               266118K
Assignability cache size:    38755
Identity cache size:           302
Subtype cache size:              3
Strict subtype cache size:       1
I/O Read time:               0.03s
Parse time:                  1.70s
ResolveModule time:          0.09s
ResolveTypeReference time:   0.01s
Program time:                1.89s
Bind time:                   1.03s
Check time:                  5.49s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                  8.40s
4.5.2
tsc --extendedDiagnostics
Files:                         478
Lines of Library:            26543
Lines of Definitions:       146444
Lines of TypeScript:             0
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Nodes of Library:           114494
Nodes of Definitions:       341871
Nodes of TypeScript:             0
Nodes of JavaScript:             0
Nodes of JSON:                   0
Nodes of Other:                  0
Identifiers:                168741
Symbols:                    196841
Types:                      264674
Instantiations:             178696
Memory used:               328640K
Assignability cache size:    76679
Identity cache size:           301
Subtype cache size:              3
Strict subtype cache size:       2
I/O Read time:               0.03s
Parse time:                  1.75s
ResolveModule time:          0.09s
ResolveTypeReference time:   0.01s
Program time:                1.98s
Bind time:                   0.94s
Check time:                 12.92s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                 15.84s

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Nov 29, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.6.0 milestone Nov 29, 2021
@andrewbranch
Copy link
Member Author

Manually bisecting between 4.4.4 and 4.5.2:

  • 4.5.0-beta (Oct 1): 11s, errors out with src/Form.tsx:7:7 - error TS2589: Type instantiation is excessively deep and possibly infinite.
  • typescript@4.5.0-dev.20210907: good, same as 4.4
  • typescript@4.5.0-dev.20210919: good, same as 4.4
  • typescript@4.5.0-dev.20210925: good, same as 4.4
  • typescript@4.5.0-dev.20210928: good, same as 4.4
  • typescript@4.5.0-dev.20210930: good, same as 4.4
  • typescript@4.5.0-dev.20211001: bad, same as 4.5.0-beta

  • 4.5.1-rc (Nov 2): 86s, no error, same as 4.5.2
  • typescript@4.5.0-dev.20211109: error, same as beta
  • typescript@4.6.0-dev.20211113: fast, no error, close to 4.4 behavior ❓
  • Skipping ahead to latest nightly: also fast
  • typescript@4.6.0-dev.20211111: fast, same as nightly
  • There is no nightly from 11/10

Uh, ok, so:

  • typescript@4.5.0-dev.20211001 was the first “bad” version, but bad in a different way than 4.5.2 is bad
  • typescript@4.6.0-dev.20211111 fixed that but was not ported into the 4.5 release
  • I still don’t know where we went from the “excessively deep” error to no error but super long check time—seems like the transition to the error behavior and to the fast no-error behavior happened between 11/09 and 11/11 but only the former got ported into the release??

The good news is this seems to be fixed in the nightly, but if the fix looks safe, we should try to port it to a 4.5 patch, because the perf difference here is bananas.

@andrewbranch
Copy link
Member Author

The fix is #46599, which never got ported to release-4.5. @DanielRosenwasser recalls this being probably intentional for safety—that could be, but (a) I don’t recall that, and (b) I don’t think we knew that it fixed a regression introduced around 4.5-beta.

@andrewbranch
Copy link
Member Author

@kmoschcau I haven’t tried your repo yet—does typescript@next perform better for you?

@kmoschcau
Copy link

@andrewbranch Oh yes it does! Back to the old performance of 4.4.4.

tsc --extendedDiagnostics
Files:                         478
Lines of Library:            26543
Lines of Definitions:       146444
Lines of TypeScript:             0
Lines of JavaScript:             0
Lines of JSON:                   0
Lines of Other:                  0
Nodes of Library:           114499
Nodes of Definitions:       341871
Nodes of TypeScript:             0
Nodes of JavaScript:             0
Nodes of JSON:                   0
Nodes of Other:                  0
Identifiers:                168742
Symbols:                    196841
Types:                       76513
Instantiations:             170952
Memory used:               271909K
Assignability cache size:    37232
Identity cache size:           301
Subtype cache size:              3
Strict subtype cache size:       2
I/O Read time:               0.22s
Parse time:                  1.69s
ResolveModule time:          0.11s
ResolveTypeReference time:   0.01s
Program time:                2.11s
Bind time:                   0.97s
Check time:                  5.30s
printTime time:              0.00s
Emit time:                   0.00s
Total time:                  8.38s

@kmoschcau
Copy link

Also next fixes the performance problems with tsserver as well.

@DanielRosenwasser
Copy link
Member

We should definitely investigate adding an older version of react-hook-form to the perf suite.

@atsikov
Copy link

atsikov commented Dec 11, 2021

Thanks for releasing the fix in 4.5.3, it's definitely much better now.
However at that react-hook-form example, type check with 4.5.3 is 5-6 times slower than 4.4.4 .

Extended diagnostics
Version 4.4.4 4.5.3 4.6.0-dev.20211211
Files: 50 50 50
Lines of Library: 26160 25009 25009
Lines of Definitions: 24762 24762 24762
Lines of TypeScript: 14 14 14
Lines of JavaScript: 0 0 0
Lines of JSON: 0 0 0
Lines of Other: 0 0 0
Nodes of Library: 112958 112482 112483
Nodes of Definitions: 60457 60453 60453
Nodes of TypeScript: 55 55 55
Nodes of JavaScript: 0 0 0
Nodes of JSON: 0 0 0
Nodes of Other: 0 0 0
Identifiers: 58865 58583 58584
Symbols: 39464 38003 38003
Types: 28967 20676 20676
Instantiations: 86282 46765 46765
Memory used: 93923K 101820K 102211K
Assignability cache size: 17107 79595 79595
Identity cache size: 62 27 27
Subtype cache size: 0 0 0
Strict subtype cache size: 0 0 0
I/O Read time: 0.03s 0.02s 0.02s
Parse time: 0.49s 0.46s 0.47s
ResolveModule time: 0.03s 0.02s 0.02s
ResolveTypeReference time: 0.00s 0.00s 0.00s
Program time: 0.57s 0.53s 0.53s
Bind time: 0.22s 0.21s 0.21s
Check time: 0.66s 3.73s 3.62s
printTime time: 0.00s 0.00s 0.00s
Emit time: 0.00s 0.00s 0.00s
Total time: 1.45s 4.47s 4.36s

@andrewbranch
Copy link
Member Author

I’m not 100% sure this is what’s going on, but I believe what’s happening is that 4.4 was giving up while resolving deep constraints (mistakenly thinking the constraints were infinitely deep), whereas 4.5+ recognizes that those constraints are not infinite, just deeper than 5 levels, and so it gets farther with actually checking correctness.

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label May 13, 2022
@andrewbranch
Copy link
Member Author

I’m able to cut the time down from 4.66s to 1.19s by adding variance annotations to just ControllerFieldState 😄

@andrewbranch
Copy link
Member Author

I’m pretty sure the slowdown is caused by #41821—we are just able to get deeper into structural comparisons for variance computations, which ultimately are fruitless for these recursive types, but in general fixed bugs. We added variance annotations for exactly this case, and it looks like they’re going to work incredibly well here. I doubt there’s anything else actionable for us (except perhaps to help react-hook-form add variance annotations—I haven’t checked whether the problem still exists in their latest/alpha versions), but am going to get a second opinion on that tomorrow with @amcasey.

@andrewbranch
Copy link
Member Author

I’m going to go ahead and close this—the performance of the library is much better in react-hook-form@beta, and also adding the variance annotations to the one type fixes the regression, so I think that’s an outcome we’re ok with.

@andrewbranch andrewbranch closed this as not planned Won't fix, can't repro, duplicate, stale Jun 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

No branches or pull requests

5 participants