[go: up one dir, main page]

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

perf: Replacing "else if" with a "switch case" statement to improve Typescript performance #1142

Merged
merged 1 commit into from
Nov 28, 2024

Conversation

moufmouf
Copy link
Contributor

This is a follow-up (and solution) to #1135 and #1141

I generated a trace from the build process and using typescript-analyze-trace to analyze the hotspots.

It turns out that time is spent almost exclusively in this kind of code:

if (object.choice?.$case === "aNumber" && object.choice?.value !== undefined && object.choice?.value !== null) {
  message.choice = { $case: "aNumber", value: object.choice.value };
} else if (
  object.choice?.$case === "aString" && object.choice?.value !== undefined && object.choice?.value !== null
) {
  message.choice = { $case: "aString", value: object.choice.value };
} else if (
//...

The previous PR I opened adding "else if" does nothing regarding Typescript perf.

With "else if", my test file trace looks like this:

npx analyze-trace traceDir
Hot Spots
├─ Check file /home/dan/projects/ts-proto/integration/large/messages.ts (31108ms)
│  ├─ Check deferred node from (line 6267, char 3) to (line 6539, char 4) (13123ms)
│  ├─ Check deferred node from (line 15342, char 3) to (line 15591, char 4) (7092ms)
│  ├─ Check deferred node from (line 10849, char 3) to (line 11059, char 4) (4460ms)
│  ├─ Check deferred node from (line 17320, char 3) to (line 17496, char 4) (2146ms)
│  ├─ Check deferred node from (line 3720, char 3) to (line 3832, char 4) (610ms)
│  └─ Check deferred node from (line 8791, char 3) to (line 8915, char 4) (516ms)
└─ Check file /home/dan/projects/ts-proto/node_modules/typescript/lib/lib.dom.d.ts (1109ms)

Now, with this commit, I'm replace else if with a switch statement.

The analysis of the build looks like this:

Hot Spots
├─ Check file /home/dan/projects/ts-proto/integration/large/messages.ts (3139ms)
│  └─ Check deferred node from (line 6278, char 3) to (line 6573, char 4) (525ms)
└─ Check file /home/dan/projects/ts-proto/node_modules/typescript/lib/lib.dom.d.ts (617ms)

The biggest switch statement takes 525ms to analyze (down from 13seconds with else if)

Implementation-wise, the hardest part is knowing when to close the switch statement. I'm doing a test at the beginning of each loop and at the very end of the function.

@moufmouf moufmouf changed the title Replacing "else if" with a "switch case" statement to improve Typescript performance perf: Replacing "else if" with a "switch case" statement to improve Typescript performance Nov 28, 2024
…ipt performance

I generated a trace from the build process and using [typescript-analyze-trace](https://github.com/microsoft/typescript-analyze-trace) to analyze the hotspots.

It turns out that time is spent in this kind of code:

```
if (object.choice?.$case === "aNumber" && object.choice?.value !== undefined && object.choice?.value !== null) {
  message.choice = { $case: "aNumber", value: object.choice.value };
} else if (
  object.choice?.$case === "aString" && object.choice?.value !== undefined && object.choice?.value !== null
) {
  message.choice = { $case: "aString", value: object.choice.value };
} else if (
//...
```

The previous PR I opened adding "else if" does nothing regarding Typescript perf.

With "else if", my test file trace looks like this:

```
npx analyze-trace traceDir
Hot Spots
├─ Check file /home/dan/projects/ts-proto/integration/large/messages.ts (31108ms)
│  ├─ Check deferred node from (line 6267, char 3) to (line 6539, char 4) (13123ms)
│  ├─ Check deferred node from (line 15342, char 3) to (line 15591, char 4) (7092ms)
│  ├─ Check deferred node from (line 10849, char 3) to (line 11059, char 4) (4460ms)
│  ├─ Check deferred node from (line 17320, char 3) to (line 17496, char 4) (2146ms)
│  ├─ Check deferred node from (line 3720, char 3) to (line 3832, char 4) (610ms)
│  └─ Check deferred node from (line 8791, char 3) to (line 8915, char 4) (516ms)
└─ Check file /home/dan/projects/ts-proto/node_modules/typescript/lib/lib.dom.d.ts (1109ms)
```

Now, with this commit, I'm replace else if with switch statement.

The analysis of the build looks like this:

```
Hot Spots
├─ Check file /home/dan/projects/ts-proto/integration/large/messages.ts (3139ms)
│  └─ Check deferred node from (line 6278, char 3) to (line 6573, char 4) (525ms)
└─ Check file /home/dan/projects/ts-proto/node_modules/typescript/lib/lib.dom.d.ts (617ms)
```

The biggest switch statement takes 525ms to analyze (down from 13seconds with "else if")

Implementation-wise, the hardest part is knowning when to close the switch statement.
I'm doing a test at the beginning of each loop and at the very end of the function.
Copy link
Owner
@stephenh stephenh left a comment

Choose a reason for hiding this comment

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

Nice! Great PR @moufmouf , thank you! I get tracking when to close the switch is annoying, but your in-source comments made it very easy to follow what's going on.


// add a check for each incoming field
messageDesc.field.forEach((field) => {
const fieldName = getFieldName(field, options);
const messageProperty = getPropertyAccessor("message", fieldName);
const objectProperty = getPropertyAccessor("object", fieldName);

if (currentSwitchTarget && !isWithinOneOfThatShouldBeUnion(options, field)) {
// We are exiting a switch, we need to close it
Copy link
Owner

Choose a reason for hiding this comment

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

Nice, thanks for the in-source comment!

@stephenh stephenh merged commit de1a616 into stephenh:main Nov 28, 2024
6 checks passed
@moufmouf
Copy link
Contributor Author

Woah! Merged in 28 minutes. You are a hell of a maintainer. Thanks for all you are doing @stephenh !

@moufmouf moufmouf deleted the switchcase branch November 28, 2024 16:26
stephenh pushed a commit that referenced this pull request Nov 28, 2024
## [2.4.2](v2.4.1...v2.4.2) (2024-11-28)

### Performance Improvements

* Replacing "else if" with a "switch case" statement to improve Typescript performance ([#1142](#1142)) ([de1a616](de1a616)), closes [#1135](#1135) [#1141](#1141)
@stephenh
Copy link
Owner

🎉 This issue has been resolved in version 2.4.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

moufmouf added a commit to workadventure/workadventure that referenced this pull request Nov 28, 2024
This version contains a performance fix for Typescript 5.1+.

See stephenh/ts-proto#1142
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants