asciidoctor / asciidoctor.js

:scroll: A JavaScript port of Asciidoctor, a modern implementation of AsciiDoc
https://asciidoctor.org
MIT License
739 stars 136 forks source link

Figure out how to speed up Asciidoctor.js #51

Closed anthonny closed 6 years ago

anthonny commented 10 years ago

Some tools : https://developer.chrome.com/devtools/docs/cpu-profiling

http://octane-benchmark.googlecode.com/svn/latest/index.html

mojavelinux commented 10 years ago

In general, we want to avoid having special code for JavaScript. The ideal strategy is to make Opal faster, or get it to generate more optimized JavaScript code. With that said, if we've identified a "hot spot" that's eating up a lot of time, we can replace the implementation of the method in Ruby with native JavaScript code.

You can see an example of how this is done in the opal_ext/file.rb class.

https://github.com/asciidoctor/asciidoctor/blob/master/lib/asciidoctor/opal_ext/file.rb#L98

Code in a %x() string or enclosed in backticks is passed directly into the compiled JavaScript code. Obvious places to put this code are areas where we are already using a guard block to isolate Opal-specific code, such as https://github.com/asciidoctor/asciidoctor/blob/master/lib/asciidoctor/substitutors.rb#L371

mojavelinux commented 10 years ago

Another idea is to stream the converted result to the DOM so that we write each section or block to the DOM as it's converted. That way, there isn't a large pause waiting for the browser to perform the innerHTML replacement. We could potentially hook into the Converter#convert method.

ggrossetie commented 10 years ago

Did a quick run with the Chrome CPU profiling and the winner is... $sub and $gsub:

cpu-profile-asciidoctorjs

Streaming the content to the DOM is an excellent idea (plus AMO don't like innerHTML) but I think this is not the current "hot spot".

lordofthejars commented 10 years ago

A test using Nashorn can be found at https://github.com/lordofthejars/asciidoctorj/blob/feature_189/src/test/java/org/asciidoctor/WhenAsciidoctorJIsUsedWithinNashorn.java#L28

mojavelinux commented 8 years ago

I noticed that the last version of v8 is getting faster and faster. Here's the timing loop for rendering the AsciiDoc Python user guide (which has been a benchmark for Asciidoctor since the beginning) using node.

node 0.12

Load scripts: 0.261s
Run #1: 1.217s
Run #2: 0.897s
Run #3: 0.766s
Run #4: 0.742s

node 5.3.0

Load scripts: 0.253s
Run #1: 1.08s
Run #2: 0.857s
Run #3: 0.673s
Run #4: 0.691s

(Good to know that Asciidoctor.js works with node v5.3.0).

In comparison, Asciidoctor running on Ruby 2.3.0 converts it in 0.18s.

We should probably create a benchmark folder in Asciidoctor.js so that we can easily get results to compare between versions. I have a script that I could commit. I'll propose it in a PR.

mojavelinux commented 8 years ago

Is it possible to profile using node? It seems like it would be a lot easier to automate.

mojavelinux commented 8 years ago

Here are the timings using jjs / nashorn 1.8.0_51.

Load scripts: 5.265s
Run #1: 30.995s
Run #2: 18.884s
Run #3: 13.255s
Run #4: 10.513s
mojavelinux commented 8 years ago

As promised, #161.

For some reason, phantomjs can't resolve the include directive, so I can't get results for phantom. I haven't been able to figure out why yet.

mojavelinux commented 8 years ago

Got it working with PhantomJS 1.9.8:

Load scripts: 0.085s
Run #1: 1.169s
Run #2: 1.146s
Run #3: 1.152s
Run #4: 1.169s
ggrossetie commented 6 years ago

Thanks to Dan we have a benchmark script (and on recent version of Node.js it's pretty to use the built-in profiler).

mojavelinux commented 6 years ago

:beers: