Skip to content

ApiDOM performance whitepaper #385

Open
@char0n

Description

@char0n

This paper serves as a whitepaper for feasible performance optimizations proposals which can be performed on ApiDOM monorepo. Paper is divided into sections (single top level section represents one monorepo package) and each of these sections is further divided into sub-sections describing the actual performance optimization proposal.

Paper also contains references to various revisions. Keep in mind that code can change between specific revision and master branch as time goes on. This can render certain performance optimization proposal invalid.

apidom

Transcluder

For every use of transclude function all the parent edges needs to be computed.

Single transclution

It is more optimal to use single traversal run for this usecase. As soon as search element is found, it is transcluded with replace element and traversal is immediately stopped.

Multi transclution

This is a usecase where multiple search elements needs to be replaced by multiple replace elements. Again it is more optimal to use traversal to replace/transclude the nodes.

Repeated transclution

This is more a corner case - we want to transclude one or multiple elements during different points in time on the same ApiDOM structure. It's possible to use current implementation of transclution to cover this usecase.

All the fore-mentioned usecases are currently embedded in one single implementation which makes it less then optimal.

apidom-ast

Parallel visiting

Parallel visiting or megring of the visitors is implemented in a way where all the "merged" visitors are iterated in every enter or leave visitor function and appropriate visitFn is obtained and executed. This can be implemented in more performant way where static chain of visitor functions is constructed by merging the visitors before they're executed.

Parallel visiting (merging) is used in refractor layers in all the namespace packages.

apidom-ns-asyncapi-2-0

Refracting primitive fields

During refracting phase traversal is executed on every field of every Object Element or item of Array Element. This has potentially significant performance implications. We could device a more performant mechanism (let's call it visitor-shortcut) that would not run traversal on any field that we expect is going to be a primitive or generic element (String Element, Number Element, Object Element, etc...). Instead fields like those are going to be directly translated from generic form to semantic form by simple cloning.

Refracting primitive fields - utilize specification object

Currently every primitive field has it's own file even though it's using generic FallbackVisitor. We can eliminate those files and attach visitors directly in specification objects. By this we will save a lot of code and file imports and lower the overall size of resulting UMD bundles.

Refractor plugins

If refractor plugins are utilized, they require additional full traversal after the refracting phase has finished. It would be convenient to run refractor plugins without additional full traversal. Running plugins inside refracting phase is not feasible as refraction transforms generic ApiDOM into semantic progressively. If we would run refractor plugins inside refracting phase it would mean that plugins will receive either generic ApiDOM elements or semantic ones depending on the state of refracting at the point of refractor plugin intercepting it. One feasible solution would be to fold our build-in defaults plugins into refracting phase directly and if there would be need for additional ad-hoc plugins, person that attaches them to refractor must expect that there will be performance implication.

apidom-ns-openapi-3-1

Refracting primitive fields

During refracting phase traversal is executed on every field of every Object Element or item of Array Element. This has potentially significant performance implications. We could device a more performant mechanism (let's call it visitor-shortcut) that would not run traversal on any field that we expect is going to be a primitive or generic element (String Element, Number Element, Object Element, etc...). Instead fields like those are going to be directly translated from generic form to semantic form by simple cloning.

Refracting primitive fields - utilize specification object

Currently every primitive field has it's own file even though it's using generic FallbackVisitor. We can eliminate those files and attach visitors directly in specification objects. By this we will save a lot of code and file imports and lower the overall size of resulting UMD bundles.

Refractor plugins

If refractor plugins are utilized, they require additional full traversal after the refracting phase has finished. It would be convenient to run refractor plugins without additional full traversal. Running plugins inside refracting phase is not feasible as refraction transforms generic ApiDOM into semantic progressively. If we would run refractor plugins inside refracting phase it would mean that plugins will receive either generic ApiDOM elements or semantic ones depending on the state of refracting at the point of refractor plugin intercepting it. One feasible solution would be to fold our build-in defaults plugins into refracting phase directly and if there would be need for additional ad-hoc plugins, person that attaches them to refractor must expect that there will be performance implication.

apidom-parser

No feasible performance optimization are currently proposed for this package.

apidom-parser-adapter-json

Syntactical analysis

In order to parse source JSON string into generic ApiDOM following parsing phases are peformed:

  1. Lexical analysis (tree-sitter)

Source JSON string is parsed and tokenized. The result of these operations is a structure that technically categorizes as CST, but contains further APIs for AST like manipulation.

  1. Syntactical analysis

CST is transformed into JSON AST.

  1. Transform

During this phase JSON AST is transformed into generic ApiDOM.

We could possibly fold phase 2. and 3. into a single phase. By doing this we would avoid one full traversal and maintaining additional JSON AST structure in memory. Syntactical analysis phase doesn't contain any additional logic that couldn't be folded easily into Transform phase because JSON is very simple format to process.

apidom-parser-adapter-yaml-1-2

Syntactical analysis

In order to parse source YAML 1.2 string into generic ApiDOM following parsing phases are peformed:

  1. Lexical analysis (tree-sitter)

Source YAML string is parsed and tokenized. The result of these operations is a structure that technically categorizes as CST, but contains further APIs for AST like manipulation.

  1. Syntactical analysis

CST is transformed into YAML AST. These transformations includes resolving YAML anchors, processing YAML Schemas and creating surrogate AST nodes wherever they're missing.

  1. Transform

During this phase YAML AST is transformed into generic ApiDOM.

We could possibly fold phase 2. and 3. into a single phase. By doing this we would avoid one full traversal and maintaining additional YAML AST structure in memory. Unfortunately YAML 1.2 is pretty complex and folding the two phases would create complex code that would not be easy to maintain. IMHO in this case code readability and maintenance wins over performance. It is always possible to create additional YAML 1.2 adapter with folded phases in future.

apidom-parser-adapter-asyncapi-json-2-0

This is a hollow adapter composed of two main packages: apidom-parser-adapter-json and apidom-ns-asyncapi-2-0. All the performance optimizations that will be performed on these two main packages will inevitably increase performance of this adapter.

This adapter goes through following phases:

  1. Lexical analysis
  2. Syntactical analysis
  3. Transform
  4. Refracting

It's possible to create a super performant version of this adapter folding all the aforementioned phases into single one.

Transclution

We could avoid transclusion here completely or use one of the already optimized transcluder described in this paper.

apidom-parser-adapter-asyncapi-yaml-2-0

This is a hollow adapter composed of two main packages: apidom-parser-adapter-yaml-1-2 and apidom-ns-asyncapi-2-0. All the performance optimizations that will be performed on these two main packages will inevitably increase performance of this adapter.

This adapter goes through following phases:

  1. Lexical analysis
  2. Syntactical analysis
  3. Transform
  4. Refracting

It's possible to create a super performant version of this adapter folding all the aforementioned phases into single one.

Transclution

We could avoid transclusion here completely or use one of the already optimized transcluder described in this paper.

apidom-parser-adapter-openapi-json-3-1

This is a hollow adapter composed of two main packages: apidom-parser-adapter-json and apidom-ns-openapi-3-1. All the performance optimizations that will be performed on these two main packages will inevitably increase performance of this adapter.

This adapter goes through following phases:

  1. Lexical analysis
  2. Syntactical analysis
  3. Transform
  4. Refracting

It's possible to create a super performant version of this adapter folding all the aforementioned phases into single one.

Transclution

We could avoid transclusion here completely or use one of the already optimized transcluder described in this paper.

apidom-parser-adapter-openapi-yaml-3-1

This is a hollow adapter composed of two main packages: apidom-parser-adapter-yaml-1-2 and apidom-ns-openapi-3-1. All the performance optimizations that will be performed on these two main packages will inevitably increase performance of this adapter.

This adapter goes through following phases:

  1. Lexical analysis
  2. Syntactical analysis
  3. Transform
  4. Refracting

It's possible to create a super performant version of this adapter folding all the aforementioned phases into single one.

Transclution

We could avoid transclusion here completely or use one of the already optimized transcluder described in this paper.

apidom-reference

No feasible performance optimization are currently proposed for this package. The performance and optimal memory management were kept in check during all implementations.

Performance analytics

All performance analytics are performed using benchmark.js library. This library contains proper statistical model for performing analysis.

Resources

Performance optimizations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions