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

I ported this library in dart #25

Closed
edwardez opened this issue Jun 23, 2019 · 5 comments
Closed

I ported this library in dart #25

edwardez opened this issue Jun 23, 2019 · 5 comments
Labels
question Further information is requested

Comments

@edwardez
Copy link

edwardez commented Jun 23, 2019

Hi @JiLiZART,

Just FYI, I happened to need a bbcode parser in dart but there are no available libraries so I decided to port bbob at https://github.com/edwardez/bbob_dart , now parser has been ported.

Thanks for creating this awesome library!

Regards,
Edward

@JiLiZART
Copy link
Owner

Hi @edwardez can you provide some benchmarks? Is this faster than JS version? :)
You can use this stub for example https://github.com/JiLiZART/bbob/blob/master/benchmark/test/stub.js

And of course, I add a link to this lib to Readme in footer :)

@edwardez
Copy link
Author

I did some tests but the result is somewhat confusing.

Test procedure

Tested on a 2.6GHz i7 mac laptop.

1. Test js

regex/parser x 12.14 ops/sec ±8.04% (34 runs sampled)
xbbcode/parser x 107 ops/sec ±1.26% (78 runs sampled)
@bbob/parser x 108 ops/sec ±1.74% (79 runs sampled)
Fastest is xbbcode/parser,@bbob/parser

~ 9 ms?

2. Test dart

Code is under
https://github.com/edwardez/bbob_dart/tree/master/benchmark
(input.dart is changed to the same content as https://github.com/JiLiZART/bbob/blob/master/benchmark/test/stub.js before testing, and validTags: {'ch'} is added to the input parameters.)

Result:

image

image

Dart JIT
> dart benchmark.dart
Best: 20.36ms 
Worst: 21.66ms 

Dart AOT(compile to native code)

dart2aot benchmark.dart benchmark.dart.aot
dartaotruntime benchmark.dart.aot
Best: 18.88ms
Worst: 19.84ms

Here's the interesting part.
Dart2JS (compile dart code to js)

>  dart2js -O3 -o benchmark.js benchmark.dart
>  node benchmark.js
Best: 4.96ms 
Worst: 6.00ms
# paste code in browser console then execute
Best: 5.16ms
Worst: 5.66ms

Tl:dr:

Original JS: 9ms, dart ~ 19ms, compile dart to js : 5ms

It's kind of counter-intuitive as the fatest version is dart2js. I opened a aws t2.micro with AMI2, and tried again.

@bbob/parser x 48.83 ops/sec ±6.23% (64 runs sampled) ~21ms
dart 37ms
dart2js 10ms

Not sure if I'm missing something here...

@JiLiZART
Copy link
Owner

Wow, interesting results. Maybe Dart needs other approaches. Anyway thanks!

@JiLiZART JiLiZART added the question Further information is requested label Jun 25, 2019
@mraleph
Copy link

mraleph commented Jun 29, 2019

@edwardez this is the same issue that was described here for less.dart. tl;dr version is that JavaScript engines usually optimize substring by introducing sliced string representation, while Dart VM does not.

The problem is quite obvious in the Observatory, because you can see most of the time (60%) is spent creating substring in CharGrabber.rest

Screenshot 2019-06-29 at 11 49 18

Try remeasuring with this simple patch:

diff --git a/lib/src/bbob_parser/utils.dart b/lib/src/bbob_parser/utils.dart
index 430659e..8e1d038 100644
--- a/lib/src/bbob_parser/utils.dart
+++ b/lib/src/bbob_parser/utils.dart
@@ -22,9 +22,6 @@ class CharGrabber {
   /// Whether [CharGrabber] is at the end of [_source].
   bool get isLast => _index == _source.length - 1;

-  /// Returns rest of the [_source] starting from current position.
-  String get rest => _source.substring(_index);
-
   /// Gets character that's at the current scan [_index].
   String get current => _index >= _source.length ? null : _source[_index];

@@ -49,11 +46,10 @@ class CharGrabber {

   /// Grabs rest of string until [CharGrabber] finds [char].
   String substringUntil(String char) {
-    final rest = this.rest;
-    final indexOfChar = rest.indexOf(char);
+    final indexOfChar = _source.indexOf(char, _index);

     if (indexOfChar >= 0) {
-      return rest.substring(0, indexOfChar);
+      return _source.substring(_index, indexOfChar);
     }

     return '';

I am getting 7ms with this patch and 22ms without.

This also explains dart2js vs VM difference - because dart2js benefits from JS engine implementation of the substrings.

(In general if you find any sort of puzzling Dart performance issues - just don't hesitate to contact me directly, we'll take a look).

@edwardez
Copy link
Author

edwardez commented Jun 29, 2019

@edwardez this is the same issue that was described here for less.dart. tl;dr version is that JavaScript engines usually optimize substring by introducing sliced string representation, while Dart VM does not.

The problem is quite obvious in the Observatory, because you can see most of the time (60%) is spent creating substring in CharGrabber.rest

Screenshot 2019-06-29 at 11 49 18

Try remeasuring with this simple patch:

diff --git a/lib/src/bbob_parser/utils.dart b/lib/src/bbob_parser/utils.dart
index 430659e..8e1d038 100644
--- a/lib/src/bbob_parser/utils.dart
+++ b/lib/src/bbob_parser/utils.dart
@@ -22,9 +22,6 @@ class CharGrabber {
   /// Whether [CharGrabber] is at the end of [_source].
   bool get isLast => _index == _source.length - 1;

-  /// Returns rest of the [_source] starting from current position.
-  String get rest => _source.substring(_index);
-
   /// Gets character that's at the current scan [_index].
   String get current => _index >= _source.length ? null : _source[_index];

@@ -49,11 +46,10 @@ class CharGrabber {

   /// Grabs rest of string until [CharGrabber] finds [char].
   String substringUntil(String char) {
-    final rest = this.rest;
-    final indexOfChar = rest.indexOf(char);
+    final indexOfChar = _source.indexOf(char, _index);

     if (indexOfChar >= 0) {
-      return rest.substring(0, indexOfChar);
+      return _source.substring(_index, indexOfChar);
     }

     return '';

I am getting 7ms with this patch and 22ms without.

This also explains dart2js vs VM difference - because dart2js benefits from JS engine implementation of the substrings.

(In general if you find any sort of puzzling Dart performance issues - just don't hesitate to contact me directly, we'll take a look).

Thanks for looking into it! I tried to profile using observatory but it showed up a blank page on firefox, I thought some special setup is needed then got stuck(just realized I cannot use firefox dart-lang/sdk#34107 ).

I just tried to open observatory in chrome and can confirm the same behavior. After reducing usage of frequently creating substring, amazing! I'm getting 8ms for parsing all tags and 6ms for parsing with validTags: {'ch'} only. Thanks again for the detailed explanation.

edwardez added a commit to edwardez/bbob_dart that referenced this issue Jun 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants