Discussion:
[dart-misc] Operator inlining in Dart VM vs V8
Frank Rollpin
2016-05-04 20:20:26 UTC
Permalink
Hi, I am running a computationally-intensive web application in regular
Chrome (built by dart2js), and noticed that on many occasions, certain
routines are 2-10 times slower in JavaScript, compared to the Dart version.
Further investigation traced some of the difference to the way operators
are (not) inlined in JavaScript. At least this is how it appears to me. In
the code below, both methods (testSetOperator and testInlinedSet) are
equally fast under Dart VM (65ms), then there is an expected 25% penalty
when testInlinedSet is executed in JavaScript, but JavaScript's
testSetOperator is more than 3 times slower.

Not sure if this is a bug? Will it be addressed in the later versions of
dart2js? Is there an alternative way to write this code to make the
inlining happen, or force it?

On a similar subject, are there any guidelines, recommendations, or any
other resources related to the Dart performance, especially related to the
performance of the JavaScript code?

Environment:
Dart SDK 1.15
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/50.0.2661.94 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/45.0.2454.0 (Dart) Safari/537.36
Windows x64


class BitSetPerfTest {
static const int size = 1000000;
Uint32List _data = new Uint32List(size);

bool operator [] (int pos) => ((_data[pos ~/ 0x20] & (1 << (pos & 0x1f)))
!= 0);

void operator []= (int pos, bool value) {
if (value)
_data[pos ~/ 0x20] |= 1 << (pos & 0x1f);
else
_data[pos ~/ 0x20] &= ~(1 << (pos & 0x1f));
}

// 257ms
void testSetOperator() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++)
this[i] = i % 2 == 0;
}

// 81 ms
void testInlinedSet() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++) {
bool v = i % 2 == 0;
if (v)
_data[i ~/ 0x20] |= 1 << (i & 0x1f);
else
_data[i ~/ 0x20] &= ~(1 << (i & 0x1f));
}
}
}
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
'Kevin Moore' via Dart Misc
2016-05-04 21:02:03 UTC
Permalink
Stephen would be a great person to talk to about this...
Post by Frank Rollpin
Hi, I am running a computationally-intensive web application in regular
Chrome (built by dart2js), and noticed that on many occasions, certain
routines are 2-10 times slower in JavaScript, compared to the Dart version.
Further investigation traced some of the difference to the way operators
are (not) inlined in JavaScript. At least this is how it appears to me. In
the code below, both methods (testSetOperator and testInlinedSet) are
equally fast under Dart VM (65ms), then there is an expected 25% penalty
when testInlinedSet is executed in JavaScript, but JavaScript's
testSetOperator is more than 3 times slower.
Not sure if this is a bug? Will it be addressed in the later versions of
dart2js? Is there an alternative way to write this code to make the
inlining happen, or force it?
On a similar subject, are there any guidelines, recommendations, or any
other resources related to the Dart performance, especially related to the
performance of the JavaScript code?
Dart SDK 1.15
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/50.0.2661.94 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/45.0.2454.0 (Dart) Safari/537.36
Windows x64
class BitSetPerfTest {
static const int size = 1000000;
Uint32List _data = new Uint32List(size);
bool operator [] (int pos) => ((_data[pos ~/ 0x20] & (1 << (pos &
0x1f))) != 0);
void operator []= (int pos, bool value) {
if (value)
_data[pos ~/ 0x20] |= 1 << (pos & 0x1f);
else
_data[pos ~/ 0x20] &= ~(1 << (pos & 0x1f));
}
// 257ms
void testSetOperator() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++)
this[i] = i % 2 == 0;
}
// 81 ms
void testInlinedSet() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++) {
bool v = i % 2 == 0;
if (v)
_data[i ~/ 0x20] |= 1 << (i & 0x1f);
else
_data[i ~/ 0x20] &= ~(1 << (i & 0x1f));
}
}
}
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
'Stephen Adams' via Dart Misc
2016-05-04 21:34:34 UTC
Permalink
You can expect JavaScript to be slower than the Dart VM because the JS VM
has to guard against crazy things like overwriting the 'class' methods in
the middle of execution.

I get the same code for both functions:

testSetOperator$0: function() {
var t1, n, i, t2, t3;
for (t1 = this._data, n = 0; n < 10; ++n)
for (i = 0; i < 1000000; ++i) {
t2 = i & 31;
if (C.JSInt_methods.$mod(i, 2) === 0) {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] | C.JSInt_methods._shlPositive$1(1, t2)) >>>
0;
} else {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] & ~C.JSInt_methods._shlPositive$1(1, t2))
Post by 'Kevin Moore' via Dart Misc
Post by Frank Rollpin
0;
}
}
},


So I'm not sure why you are seeing a difference.
If you share the whole program I might be able to see what is going on.

Things you can do:

use* i.remainder(2) == 0* or *i.isEven* instead of i % 2. In Dart, *%* is
modulo, not remainder.
use * i >> 5* instead of *i ~/ 0x20*.

That gets me down to ~35ms.
If I hand edit the output remove all dart2js overhead I get ~30ms, so ~35ms
is reasonable good.

Note that you should test performance in the running app.
In a micro-benchmark, compilers and VMs (dart or v8) can 'see' that the
program is simple.
For example, dart2js might inline a big function if it can see that it is
only used once.
Post by 'Kevin Moore' via Dart Misc
Stephen would be a great person to talk to about this...
Post by Frank Rollpin
Hi, I am running a computationally-intensive web application in regular
Chrome (built by dart2js), and noticed that on many occasions, certain
routines are 2-10 times slower in JavaScript, compared to the Dart version.
Further investigation traced some of the difference to the way operators
are (not) inlined in JavaScript. At least this is how it appears to me. In
the code below, both methods (testSetOperator and testInlinedSet) are
equally fast under Dart VM (65ms), then there is an expected 25% penalty
when testInlinedSet is executed in JavaScript, but JavaScript's
testSetOperator is more than 3 times slower.
Not sure if this is a bug? Will it be addressed in the later versions of
dart2js? Is there an alternative way to write this code to make the
inlining happen, or force it?
On a similar subject, are there any guidelines, recommendations, or any
other resources related to the Dart performance, especially related to the
performance of the JavaScript code?
Dart SDK 1.15
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/50.0.2661.94 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/45.0.2454.0 (Dart) Safari/537.36
Windows x64
class BitSetPerfTest {
static const int size = 1000000;
Uint32List _data = new Uint32List(size);
bool operator [] (int pos) => ((_data[pos ~/ 0x20] & (1 << (pos &
0x1f))) != 0);
void operator []= (int pos, bool value) {
if (value)
_data[pos ~/ 0x20] |= 1 << (pos & 0x1f);
else
_data[pos ~/ 0x20] &= ~(1 << (pos & 0x1f));
}
// 257ms
void testSetOperator() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++)
this[i] = i % 2 == 0;
}
// 81 ms
void testInlinedSet() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++) {
bool v = i % 2 == 0;
if (v)
_data[i ~/ 0x20] |= 1 << (i & 0x1f);
else
_data[i ~/ 0x20] &= ~(1 << (i & 0x1f));
}
}
}
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Frank Rollpin
2016-05-05 03:54:23 UTC
Permalink
Stephen, thanks for the answer, and for the hints regarding >> and
i.remander! I understand that JavaScript will almost always be slower than
Dart - and I will accept 30% degradation, but 500% is way too much. Below
is the JavaScript code for both functions, and on my platform
testSetOperator is 4 times slower (256ms vs 83ms). Somehow, the index
operator did not get inlined. I run benchmarks often, and it's not just the
micro-benchmarks, you can clearly see that sort of slowing down in the real
app.

Could it be that I am doing something silly, like using debug mode? I have
to admit that I do not have experience with profiling the JavaScript code,
so any tips on that subject are appreciated, too!

testSetOperator$0: function() {
var n, i;
for (n = 0; n < 10; ++n)
for (i = 0; i < 1000000; ++i)
this.$indexSet(0, i, C.JSInt_methods.$mod(i, 2) === 0);
}
testInlinedSet$0: function() {
var t1, n, i, t2, t3;
for (t1 = this._ddt_benchmark$_data, n = 0; n < 10; ++n)
for (i = 0; i < 1000000; ++i) {
t2 = i & 31;
if (C.JSInt_methods.$mod(i, 2) === 0) {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] | C.JSInt_methods._shlPositive$1(1, t2)) >>>
0;
} else {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] & ~C.JSInt_methods._shlPositive$1(1, t2))
Post by 'Stephen Adams' via Dart Misc
Post by 'Kevin Moore' via Dart Misc
Post by Frank Rollpin
0;
}
}
}
Post by 'Stephen Adams' via Dart Misc
You can expect JavaScript to be slower than the Dart VM because the JS VM
has to guard against crazy things like overwriting the 'class' methods in
the middle of execution.
testSetOperator$0: function() {
var t1, n, i, t2, t3;
for (t1 = this._data, n = 0; n < 10; ++n)
for (i = 0; i < 1000000; ++i) {
t2 = i & 31;
if (C.JSInt_methods.$mod(i, 2) === 0) {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] | C.JSInt_methods._shlPositive$1(1, t2))
Post by 'Kevin Moore' via Dart Misc
Post by Frank Rollpin
0;
} else {
t3 = C.JSInt_methods._tdivFast$1(i, 32);
if (t3 >= 1000000)
return H.ioore(t1, t3);
t1[t3] = (t1[t3] & ~C.JSInt_methods._shlPositive$1(1, t2))
Post by 'Kevin Moore' via Dart Misc
Post by Frank Rollpin
0;
}
}
},
So I'm not sure why you are seeing a difference.
If you share the whole program I might be able to see what is going on.
use* i.remainder(2) == 0* or *i.isEven* instead of i % 2. In Dart, *%* is
modulo, not remainder.
use * i >> 5* instead of *i ~/ 0x20*.
That gets me down to ~35ms.
If I hand edit the output remove all dart2js overhead I get ~30ms, so
~35ms is reasonable good.
Note that you should test performance in the running app.
In a micro-benchmark, compilers and VMs (dart or v8) can 'see' that the
program is simple.
For example, dart2js might inline a big function if it can see that it is
only used once.
Post by 'Kevin Moore' via Dart Misc
Stephen would be a great person to talk to about this...
Post by Frank Rollpin
Hi, I am running a computationally-intensive web application in regular
Chrome (built by dart2js), and noticed that on many occasions, certain
routines are 2-10 times slower in JavaScript, compared to the Dart version.
Further investigation traced some of the difference to the way operators
are (not) inlined in JavaScript. At least this is how it appears to me. In
the code below, both methods (testSetOperator and testInlinedSet) are
equally fast under Dart VM (65ms), then there is an expected 25% penalty
when testInlinedSet is executed in JavaScript, but JavaScript's
testSetOperator is more than 3 times slower.
Not sure if this is a bug? Will it be addressed in the later versions of
dart2js? Is there an alternative way to write this code to make the
inlining happen, or force it?
On a similar subject, are there any guidelines, recommendations, or any
other resources related to the Dart performance, especially related to the
performance of the JavaScript code?
Dart SDK 1.15
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/50.0.2661.94 Safari/537.36
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like
Gecko) Chrome/45.0.2454.0 (Dart) Safari/537.36
Windows x64
class BitSetPerfTest {
static const int size = 1000000;
Uint32List _data = new Uint32List(size);
bool operator [] (int pos) => ((_data[pos ~/ 0x20] & (1 << (pos &
0x1f))) != 0);
void operator []= (int pos, bool value) {
if (value)
_data[pos ~/ 0x20] |= 1 << (pos & 0x1f);
else
_data[pos ~/ 0x20] &= ~(1 << (pos & 0x1f));
}
// 257ms
void testSetOperator() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++)
this[i] = i % 2 == 0;
}
// 81 ms
void testInlinedSet() {
for (int n = 0; n < 10; n++)
for (int i = 0; i < size; i++) {
bool v = i % 2 == 0;
if (v)
_data[i ~/ 0x20] |= 1 << (i & 0x1f);
else
_data[i ~/ 0x20] &= ~(1 << (i & 0x1f));
}
}
}
--
For other discussions, see https://groups.google.com/a/dartlang.org/

For HOWTO questions, visit http://stackoverflow.com/tags/dart

To file a bug report or feature request, go to http://www.dartbug.com/new
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+***@dartlang.org.
Loading...