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(ast): reduce AST memory usage #5601

Closed
Boshen opened this issue Sep 8, 2024 · 2 comments
Closed

perf(ast): reduce AST memory usage #5601

Boshen opened this issue Sep 8, 2024 · 2 comments
Labels
C-enhancement Category - New feature or request C-performance Category - Solution not expected to change functional behavior, only performance

Comments

@Boshen
Copy link
Member

Boshen commented Sep 8, 2024

cargo binstall top-type-sizes
RUSTFLAGS=-Zprint-type-sizes cargo +nightly build -j 1 -p oxc > type-sizes.txt
top-type-sizes -s -w  -f oxc < type-sizes.txt

Structs / enums larget than 64 bytes should be reduced:

168 oxc_regular_expression::PatternParser<'_> align=8
     96 reader
     40 state
     16 source_text
      8 allocator
      4 span_factory

160 oxc_ast::ast::Class<'_> align=8
     32 decorators align=8
     32 id
     32 implements
     16 super_class
      8 span align=4
      8 type_parameters
      8 super_type_parameters
      8 body
      4 scope_id align=4
      1 type
      1 abstract
      1 declare

152 oxc_diagnostics::OxcDiagnosticInner align=8
     48 code
     24 message
     24 labels
     24 help
     24 url
      1 severity

152 oxc_ast::ast::ExportNamedDeclaration<'_> align=8
     64 with_clause align=8
     32 specifiers
     24 source
     16 declaration
      8 span
      1 export_kind

144 oxc_ast::ast::ExportAllDeclaration<'_> align=8
     64 with_clause
     40 exported
     24 source
      8 span
      1 export_kind

136 oxc_ast::ast::ImportDeclaration<'_> align=8
     64 with_clause
     32 specifiers
     24 source
      8 span
      1 import_kind

120 oxc_ast::ast::TSImportType<'_> align=8
     64 attributes
     16 parameter align=8
     16 qualifier
      8 span
      8 type_parameters
      1 is_type_of

112 std::result::Result<oxc_ast::ast::Program<'_>, oxc_diagnostics::OxcDiagnostic> align=8
    112 variant Ok
      8 variant Err

112 std::array::IntoIter<oxc_diagnostics::LabeledSpan, 2> align=8
     96 data
     16 alive

112 oxc_ast::ast::Program<'_> align=8
     32 directives
     32 body
     24 hashbang align=8
      8 span
      4 scope_id
      3 source_type

104 oxc_ast::ast::TaggedTemplateExpression<'_> align=8
     72 quasi
     16 tag
      8 span
      8 type_parameters

104 oxc_ast::ast::PropertyDefinition<'_> align=8
     32 decorators align=8
     16 key
     16 value
      8 span align=4
      8 type_annotation align=8
      1 type
      1 computed
      1 static
      1 declare
      1 override
      1 optional
      1 definite
      1 readonly
      1 accessibility

104 oxc_ast::ast::Function<'_> align=8
     32 id align=8
      8 span align=4
      8 type_parameters align=8
      8 this_param
      8 params
      8 return_type
      8 body
      4 scope_id
      1 type
      1 generator
      1 async
      1 declare

104 oxc_ast::ast::AccessorProperty<'_> align=8
     32 decorators align=8
     16 key
     16 value
      8 span align=4
      8 type_annotation align=8
      1 type
      1 computed
      1 static
      1 definite
      1 accessibility

96 std::result::Result<oxc_ast::ast::ExportSpecifier<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     96 variant Ok
      8 variant Err

96 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::ExportSpecifier<'_>> align=8
     96 variant Continue
      8 variant Break

96 oxc_regular_expression::body_parser::reader::Reader<'_> align=8
     24 u8_units
     24 u16_units
     16 source
     16 last_offset_indices
      8 index
      1 unicode_mode

96 oxc_ast::ast::TSInterfaceDeclaration<'_> align=8
     32 id
     32 extends
      8 span
      8 type_parameters
      8 body
      4 scope_id align=4
      1 declare

96 oxc_ast::ast::ExportSpecifier<'_> align=8
     40 local
     40 exported
      8 span
      1 export_kind

88 oxc_ast::ast::ImportSpecifier<'_> align=8
     40 imported
     32 local
      8 span
      1 import_kind

80 std::result::Result<oxc_ast::ast::TSTypeParameter<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     80 variant Ok
      8 variant Err

80 std::result::Result<oxc_ast::ast::FormalParameter<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     80 variant Ok
      8 variant Err

80 std::result::Result<oxc_ast::ast::ArrayAssignmentTarget<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     80 variant Ok
      8 variant Err

80 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::TSTypeParameter<'_>> align=8
     80 variant Continue
      8 variant Break

80 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::FormalParameter<'_>> align=8
     80 variant Continue
      8 variant Break

80 oxc_ast::ast::TSTypeParameter<'_> align=8
     32 name
     16 constraint
     16 default
      8 span
      1 in
      1 out
      1 const

80 oxc_ast::ast::TSEnumDeclaration<'_> align=8
     32 id
     32 members
      8 span
      4 scope_id align=4
      1 const
      1 declare

80 oxc_ast::ast::TSConditionalType<'_> align=8
     16 check_type
     16 extends_type
     16 true_type
     16 false_type
      8 span
      4 scope_id

80 oxc_ast::ast::MethodDefinition<'_> align=8
     32 decorators align=8
     16 key
      8 span align=4
      8 value
      1 type
      1 kind
      1 computed
      1 static
      1 override
      1 optional
      1 accessibility

80 oxc_ast::ast::FormalParameter<'_> align=8
     32 decorators
     32 pattern
      8 span
      1 accessibility
      1 readonly
      1 override

80 oxc_ast::ast::ForStatement<'_> align=8
     16 init
     16 test
     16 update
     16 body
      8 span
      4 scope_id

80 oxc_ast::ast::ArrayAssignmentTarget<'_> align=8
     32 elements
     24 rest
     12 trailing_comma
      8 span

72 std::result::Result<std::option::Option<oxc_ast::ast::WithClause<'_>>, oxc_diagnostics::OxcDiagnostic> align=8
      8 <discriminant>
     64 variant Ok
      8 variant Err

72 std::result::Result<oxc_ast::ast::VariableDeclarator<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     72 variant Ok
      8 variant Err

72 std::result::Result<oxc_ast::ast::TemplateLiteral<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     72 variant Ok
      8 variant Err

72 std::result::Result<(std::option::Option<oxc_allocator::Vec<'_, (oxc_ast::ast::Expression<'_>, std::option::Option<oxc_allocator::Box<'_, oxc_ast::ast::TSTypeParameterInstantiation<'_>>>, oxc_span::Span)>>, std::option::Option<oxc_allocator::Vec<'_, oxc_ast::ast::TSClassImplements<'_>>>), oxc_diagnostics::OxcDiagnostic> align=8
      8 <discriminant>
     64 variant Ok
      8 variant Err

72 std::result::Result<(oxc_allocator::Vec<'_, std::option::Option<oxc_ast::ast::BindingPattern<'_>>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>), oxc_diagnostics::OxcDiagnostic> align=8
     72 variant Ok
      8 variant Err

72 std::result::Result<(oxc_allocator::Vec<'_, oxc_ast::ast::FormalParameter<'_>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>), oxc_diagnostics::OxcDiagnostic> align=8
     72 variant Ok
      8 variant Err

72 std::result::Result<(oxc_allocator::Vec<'_, oxc_ast::ast::BindingProperty<'_>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>), oxc_diagnostics::OxcDiagnostic> align=8
     72 variant Ok
      8 variant Err

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, std::option::Option<oxc_ast::ast::WithClause<'_>>> align=8
      8 <discriminant>
     64 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::VariableDeclarator<'_>> align=8
     72 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::TemplateLiteral<'_>> align=8
     72 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, (std::option::Option<oxc_allocator::Vec<'_, (oxc_ast::ast::Expression<'_>, std::option::Option<oxc_allocator::Box<'_, oxc_ast::ast::TSTypeParameterInstantiation<'_>>>, oxc_span::Span)>>, std::option::Option<oxc_allocator::Vec<'_, oxc_ast::ast::TSClassImplements<'_>>>)> align=8
      8 <discriminant>
     64 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, (oxc_allocator::Vec<'_, std::option::Option<oxc_ast::ast::BindingPattern<'_>>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>)> align=8
     72 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, (oxc_allocator::Vec<'_, oxc_ast::ast::FormalParameter<'_>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>)> align=8
     72 variant Continue
      8 variant Break

72 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, (oxc_allocator::Vec<'_, oxc_ast::ast::BindingProperty<'_>>, std::option::Option<oxc_ast::ast::BindingRestElement<'_>>)> align=8
     72 variant Continue
      8 variant Break

72 oxc_regular_expression::ast::RegularExpression<'_> align=8
     48 pattern
     16 flags
      8 span

72 oxc_ast::ast::VariableDeclarator<'_> align=8
     32 id align=8
     16 init
      8 span
      1 kind
      1 definite

72 oxc_ast::ast::TemplateLiteral<'_> align=8
     32 quasis
     32 expressions
      8 span

72 oxc_ast::ast::TSTypeAliasDeclaration<'_> align=8
     32 id
     16 type_annotation
      8 span
      8 type_parameters
      4 scope_id align=4
      1 declare

72 oxc_ast::ast::TSTemplateLiteralType<'_> align=8
     32 quasis
     32 types
      8 span

72 oxc_ast::ast::TSModuleBlock<'_> align=8
     32 directives
     32 body
      8 span

72 oxc_ast::ast::TSMethodSignature<'_> align=8
     16 key
      8 span
      8 this_param align=8
      8 params
      8 return_type
      8 type_parameters
      4 scope_id
      1 computed
      1 optional
      1 kind

72 oxc_ast::ast::ObjectProperty<'_> align=8
     16 key align=8
     16 value
     16 init
      8 span
      1 kind
      1 method
      1 shorthand
      1 computed

72 oxc_ast::ast::JSXOpeningElement<'_> align=8
     32 attributes
     16 name align=8
      8 span
      8 type_parameters
      1 self_closing

72 oxc_ast::ast::FunctionBody<'_> align=8
     32 directives
     32 statements
      8 span

72 oxc_ast::ast::ForOfStatement<'_> align=8
     16 left align=8
     16 right
     16 body
      8 span
      4 scope_id
      1 await

72 oxc_ast::ast::CallExpression<'_> align=8
     32 arguments
     16 callee
      8 span
      8 type_parameters
      1 optional

64 std::result::Result<oxc_ast::ast::TSImportAttributes<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     64 variant Ok
      8 variant Err

64 std::result::Result<oxc_ast::ast::ObjectAssignmentTarget<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     64 variant Ok
      8 variant Err

64 std::result::Result<oxc_ast::ast::ImportAttribute<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     64 variant Ok
      8 variant Err

64 std::result::Result<oxc_ast::ast::BindingProperty<'_>, oxc_diagnostics::OxcDiagnostic> align=8
     64 variant Ok
      8 variant Err

64 std::result::Result<(oxc_allocator::Vec<'_, oxc_ast::ast::Directive<'_>>, oxc_allocator::Vec<'_, oxc_ast::ast::Statement<'_>>), oxc_diagnostics::OxcDiagnostic> align=8
     64 variant Ok
     16 variant Err

64 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::TSImportAttributes<'_>> align=8
     64 variant Continue
      8 variant Break

64 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::ImportAttribute<'_>> align=8
     64 variant Continue
      8 variant Break

64 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, oxc_ast::ast::BindingProperty<'_>> align=8
     64 variant Continue
      8 variant Break

64 std::ops::ControlFlow<std::result::Result<std::convert::Infallible, oxc_diagnostics::OxcDiagnostic>, (oxc_allocator::Vec<'_, oxc_ast::ast::Directive<'_>>, oxc_allocator::Vec<'_, oxc_ast::ast::Statement<'_>>)> align=8
     64 variant Continue
     16 variant Break

64 std::iter::Chain<std::vec::IntoIter<oxc_diagnostics::OxcDiagnostic>, std::vec::IntoIter<oxc_diagnostics::OxcDiagnostic>> align=8
     32 a
     32 b

64 oxc_regular_expression::ast::Quantifier<'_> align=8
     24 body align=8
     16 max
      8 span
      8 min
      1 greedy

64 oxc_regular_expression::ast::CapturingGroup<'_> align=8
     40 body
     16 name
      8 span

64 oxc_ast::ast::WithClause<'_> align=8
     32 with_entries
     24 attributes_keyword
      8 span

64 oxc_ast::ast::TSModuleDeclaration<'_> align=8
     32 id
     16 body
      8 span
      4 scope_id align=4
      1 kind
      1 declare

64 oxc_ast::ast::TSImportEqualsDeclaration<'_> align=8
     32 id
     16 module_reference
      8 span
      1 import_kind

64 oxc_ast::ast::TSImportAttributes<'_> align=8
     32 elements
     24 attributes_keyword
      8 span

64 oxc_ast::ast::TSCallSignatureDeclaration<'_> align=8
     32 this_param
      8 span
      8 params
      8 return_type
      8 type_parameters

64 oxc_ast::ast::SwitchStatement<'_> align=8
     32 cases
     16 discriminant
      8 span
      4 scope_id

64 oxc_ast::ast::ObjectAssignmentTarget<'_> align=8
     32 properties
     24 rest
      8 span

64 oxc_ast::ast::NewExpression<'_> align=8
     32 arguments
     16 callee
      8 span
      8 type_parameters

64 oxc_ast::ast::ImportAttribute<'_> align=8
     32 key
     24 value
      8 span

64 oxc_ast::ast::ForInStatement<'_> align=8
     16 left
     16 right
     16 body
      8 span
      4 scope_id

64 oxc_ast::ast::ExportDefaultDeclaration<'_> align=8
     40 exported
     16 declaration
      8 span

64 oxc_ast::ast::CatchClause<'_> align=8
     40 param
      8 span
      8 body
      4 scope_id

64 oxc_ast::ast::BindingProperty<'_> align=8
     32 value
     16 key
      8 span
      1 shorthand
      1 computed
@Boshen Boshen added C-enhancement Category - New feature or request C-performance Category - Solution not expected to change functional behavior, only performance labels Sep 8, 2024
@Boshen Boshen changed the title perf(ast): reduce ast memory usage perf(ast): reduce AST memory usage Sep 8, 2024
@overlookmotel
Copy link
Contributor

There is a value to reducing memory usage. But is there a gain to reducing types to under 64 bytes? Some types are just inherently big, as they contain a lot of info (e.g. Class). Is there a benefit to breaking up such a type into separate allocations by Box-ing parts of it? Yes, that'd reduce the size of Class, but that data still has to be stored somewhere so it won't save memory overall.

In my opinion, the fields which we should consider boxing are either:

  1. Large and wrapped in a Option, which is often None.
  2. Vecs which are commonly empty.

e.g.:

  • Class::decorators (most classes aren't decorated, so this Vec is usually empty).
  • FormalParameter::decorators (ditto)
  • FunctionBody::directives (most functions don't have any directives)
  • ArrayAssignmentTarget::rest ([a, b] = arr is more common than [a, ...b] = arr, so rest is usually None)

I imagine that the majority of code that Oxc will run against will be plain JS (when bundling an application, the volume of library code in node_modules will likely dwarf the application code written in TS). Therefore I think we should optimize the AST to be as memory-efficient as possible for JS, by boxing large TS-only fields.

Also: We can expect Vec to be reduced to 16 bytes in future, which will reduce the size of a lot of types. oxc-project/backlog#18

@Boshen
Copy link
Member Author

Boshen commented Sep 10, 2024

I boxed a few attributes in the PR stack #5679, everything else looks fine.

@Boshen Boshen closed this as completed Sep 10, 2024
Boshen pushed a commit that referenced this issue Sep 12, 2024
…asi` by `Boxing` it (#5679) (#5715)

As discussed in #5601, there is little benefit to reducing type sizes for the sake of it. In this case, the `quasi` field in not in an `Option`, so putting it in a `Box` does not save data, only moves where that data is stored, and introduces pointer-indirection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category - New feature or request C-performance Category - Solution not expected to change functional behavior, only performance
Projects
None yet
Development

No branches or pull requests

2 participants