Skip to content

Conversation

liuxingbaoyu
Copy link
Member

@liuxingbaoyu liuxingbaoyu commented Sep 18, 2024

Q                       A
Fixed Issues? Fixes #1, Fixes #2
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

Ref: #15843
I was surprised that the second commit improved performance by nearly 40%.

PS F:\babel\benchmark\babel-types\builders> node .\stringLiteral.mjs
baseline stringLiteral builder: 33_969_770 ops/sec ±0.87% (0ms)
current stringLiteral builder: 233_913_245 ops/sec ±4.54% (0ms)
PS F:\babel\benchmark\babel-types\builders> node .\memberExpression.mjs
baseline memberExpression builder: 882_488 ops/sec ±0.2% (0.001ms)
current memberExpression builder: 15_058_197 ops/sec ±0.45% (0ms)

@babel-bot
Copy link
Collaborator

babel-bot commented Sep 18, 2024

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/57984

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Sep 18, 2024

I was surprised that the second commit improved performance by nearly 40%.

Maybe because it makes validate's first argument monomorphic (the new objects all have the same shape). It'd be good to have a benchmark that calls multiple different validators.

});
};
const defs = NODE_FIELDS.AssignmentExpression;
validate(defs.operator, node, "operator", operator);
Copy link
Member

Choose a reason for hiding this comment

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

Can you check we need to pass the last parameter, or can validate read it from node["operator"]? From a perf perspective.

Copy link
Member Author

Choose a reason for hiding this comment

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

When I remove the last argument and access node, there is also a difference of nearly 40%, which I suspect is for the same reason as the second commit improving performance.
Perhaps obj.prop can be optimized better than obj[propName].

PS F:\babel\benchmark\babel-types\builders> node .\memberExpression.mjs
baseline memberExpression builder: 854_712 ops/sec ±3.47% (0.001ms)
current memberExpression builder: 11_459_581 ops/sec ±0.53% (0ms)

@liuxingbaoyu
Copy link
Member Author

liuxingbaoyu commented Sep 18, 2024

It'd be good to have a benchmark that calls multiple different validators.

I added a new benchmark, but something even stranger seems to be happening. 😅
Below are two benchmarks that I consider equivalent, but they give different results. 🤦‍♂️

(in use-cjs)

import baseline from "@babel-baseline/types";
import current from "@babel/types";
import { Benchmark } from "../../util.mjs";

const bench = new Benchmark();

function benchCases(implementations) {
  for (const version in implementations) {
    const t = implementations[version];
    const func = t.stringLiteral;
    const func2 = t.memberExpression;
    const func3 = t.assignmentExpression;
    const func4 = t.binaryExpression;

    const id = t.identifier("id");
    const id2 = t.identifier("id2");
    bench.add(`${version} builder`, () => {
      func("bar");
      func2(id, id2, /*computed?*/ false /*, optional? missing*/);
      func3("=", id, id2);
      func4("+", id, id2);
    });
  }
}

benchCases({ baseline, current });

bench.run();
PS F:\babel\benchmark\babel-types\builders> node .\multiple.mjs
baseline builder: 252_117 ops/sec ±0.19% (0.004ms)
current builder: 2_729_772 ops/sec ±0.48% (0ms)

and

import { Benchmark, baselineTypes, currentTypes } from "../../util.mjs";

const bench = new Benchmark();

function benchCases(implementations) {
  for (const version in implementations) {
    const t = implementations[version];
    const func = t.stringLiteral;
    const func2 = t.memberExpression;
    const func3 = t.assignmentExpression;
    const func4 = t.binaryExpression;

    const id = t.identifier("id");
    const id2 = t.identifier("id2");
    bench.add(`${version} builder`, () => {
      func("bar");
      func2(id, id2, /*computed?*/ false /*, optional? missing*/);
      func3("=", id, id2);
      func4("+", id, id2);
    });
  }
}

benchCases({ baselineTypes, currentTypes });

bench.run();
PS F:\babel\benchmark\babel-types\builders> node .\multiple.mjs
baselineTypes builder: 232_489 ops/sec ±0.3% (0.004ms)
currentTypes builder: 4_012_689 ops/sec ±0.31% (0ms)

@nicolo-ribaudo
Copy link
Member

nicolo-ribaudo commented Sep 23, 2024

@liuxingbaoyu The only difference I see is the second one is is importing with import * as baselineTypes from "@babel-baseline/types";, while the first one with import baselineTypes from "@babel-baseline/types";. Maybe check if aligning them makes a difference.

@nicolo-ribaudo nicolo-ribaudo added the PR: Performance 🏃‍♀️ A type of pull request used for our changelog categories label Sep 23, 2024
@liuxingbaoyu
Copy link
Member Author

I remember I tried it and the results were still different.

But today when I tried it again, I found that all benchmarks gave the same results. 🤦‍♂️

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo left a comment

Choose a reason for hiding this comment

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

I strongly prefer this PR to the other one

@nicolo-ribaudo nicolo-ribaudo merged commit ebe4b7c into babel:main Sep 23, 2024
52 checks passed
@nicolo-ribaudo nicolo-ribaudo changed the title perf: Improve @babel/types builders 2 perf: Improve @babel/types builders Sep 23, 2024
zemnmez-renovate-bot added a commit to zemn-me/monorepo that referenced this pull request Oct 2, 2024
##### [`v7.25.7](https://github.com/babel/babel/blob/HEAD/CHANGELOG.md#v7257-2024-10-02)

##### 🐛 Bug Fix

-   `babel-helper-validator-identifier`
    -   [#16825](babel/babel#16825) fix: update identifier to unicode 16 ([@JLHwung](https://github.com/JLHwung))
-   `babel-traverse`
    -   [#16814](babel/babel#16814) fix: issue with node path keys updated on unrelated paths ([@DylanPiercey](https://github.com/DylanPiercey))
-   `babel-plugin-transform-classes`
    -   [#16797](babel/babel#16797) Use an inclusion rather than exclusion list for `super()` check ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-generator`
    -   [#16788](babel/babel#16788) Fix printing of TS `infer` in compact mode ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
    -   [#16785](babel/babel#16785) Print TS type annotations for destructuring in assignment pattern ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
    -   [#16778](babel/babel#16778) Respect `[no LineTerminator here]` after nodes ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))

##### 💅 Polish

-   `babel-types`
    -   [#16852](babel/babel#16852) Add deprecated JSDOC for fields ([@liuxingbaoyu](https://github.com/liuxingbaoyu))

##### 🏠 Internal

-   `babel-core`
    -   [#16820](babel/babel#16820) Allow sync loading of ESM when `--experimental-require-module` ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-helper-compilation-targets`, `babel-helper-plugin-utils`, `babel-preset-env`
    -   [#16858](babel/babel#16858) Add browserslist config to external dependency ([@JLHwung](https://github.com/JLHwung))
-   `babel-plugin-proposal-destructuring-private`, `babel-plugin-syntax-decimal`, `babel-plugin-syntax-import-reflection`, `babel-standalone`
    -   [#16809](babel/babel#16809) Archive syntax-import-reflection and syntax-decimal ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-generator`
    -   [#16779](babel/babel#16779) Simplify logic for `[no LineTerminator here]` before nodes ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))

##### 🏃‍♀️ Performance

-   `babel-plugin-transform-typescript`
    -   [#16875](babel/babel#16875) perf: Avoid extra cloning of namespaces ([@liuxingbaoyu](https://github.com/liuxingbaoyu))
-   `babel-types`
    -   [#16842](babel/babel#16842) perf: Improve [@babel/types](https://github.com/babel/types) builders ([@liuxingbaoyu](https://github.com/liuxingbaoyu))
    -   [#16828](babel/babel#16828) Only access `BABEL_TYPES_8_BREAKING` at startup ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
github-merge-queue bot pushed a commit to zemn-me/monorepo that referenced this pull request Oct 2, 2024
##### [`v7.25.7](https://github.com/babel/babel/blob/HEAD/CHANGELOG.md#v7257-2024-10-02)

##### 🐛 Bug Fix

-   `babel-helper-validator-identifier`
    -   [#16825](babel/babel#16825) fix: update identifier to unicode 16 ([@JLHwung](https://github.com/JLHwung))
-   `babel-traverse`
    -   [#16814](babel/babel#16814) fix: issue with node path keys updated on unrelated paths ([@DylanPiercey](https://github.com/DylanPiercey))
-   `babel-plugin-transform-classes`
    -   [#16797](babel/babel#16797) Use an inclusion rather than exclusion list for `super()` check ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-generator`
    -   [#16788](babel/babel#16788) Fix printing of TS `infer` in compact mode ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
    -   [#16785](babel/babel#16785) Print TS type annotations for destructuring in assignment pattern ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
    -   [#16778](babel/babel#16778) Respect `[no LineTerminator here]` after nodes ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))

##### 💅 Polish

-   `babel-types`
    -   [#16852](babel/babel#16852) Add deprecated JSDOC for fields ([@liuxingbaoyu](https://github.com/liuxingbaoyu))

##### 🏠 Internal

-   `babel-core`
    -   [#16820](babel/babel#16820) Allow sync loading of ESM when `--experimental-require-module` ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-helper-compilation-targets`, `babel-helper-plugin-utils`, `babel-preset-env`
    -   [#16858](babel/babel#16858) Add browserslist config to external dependency ([@JLHwung](https://github.com/JLHwung))
-   `babel-plugin-proposal-destructuring-private`, `babel-plugin-syntax-decimal`, `babel-plugin-syntax-import-reflection`, `babel-standalone`
    -   [#16809](babel/babel#16809) Archive syntax-import-reflection and syntax-decimal ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
-   `babel-generator`
    -   [#16779](babel/babel#16779) Simplify logic for `[no LineTerminator here]` before nodes ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))

##### 🏃‍♀️ Performance

-   `babel-plugin-transform-typescript`
    -   [#16875](babel/babel#16875) perf: Avoid extra cloning of namespaces ([@liuxingbaoyu](https://github.com/liuxingbaoyu))
-   `babel-types`
    -   [#16842](babel/babel#16842) perf: Improve [@babel/types](https://github.com/babel/types) builders ([@liuxingbaoyu](https://github.com/liuxingbaoyu))
    -   [#16828](babel/babel#16828) Only access `BABEL_TYPES_8_BREAKING` at startup ([@nicolo-ribaudo](https://github.com/nicolo-ribaudo))
@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Dec 24, 2024
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue pkg: types PR: Performance 🏃‍♀️ A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants