summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Browning <bbrownin@redhat.com>2014-12-16 10:12:10 -0500
committerBen Browning <bbrownin@redhat.com>2014-12-16 10:12:10 -0500
commiteaac48419d196e909fcdf526c4e3dbec2cc3d19b (patch)
tree1f851077f62e776de524e731a3b092f4b5b6a782
parent17fe8e72f484e65e0c36670946934d1f8696e37b (diff)
downloadjson-eaac48419d196e909fcdf526c4e3dbec2cc3d19b.tar.gz
Improve JRuby perf. by removing source of multithreaded contention
The RuntimeInfo.forRuntime method synchronizes all invocations and ParserSession#parseString was calling this many times when parsing large JSON strings. Thus, when running in a heavily multithreaded environment, threads were spending a large portion of their time waiting on that synchronization instead of doing work parsing the JSON. This fix simply passes in the RuntimeInfo object to the ParserSession when it's instantiated, since the RuntimeInfo is already known and we've already incurred the synchronization cost at that time. Using the test script at https://gist.github.com/bbrowning/0b89580b03a5f19e7a9f, I get the following results before and after this fix on my machine: Before: $ jruby ~/tmp/json_contention.rb 337.920000 0.570000 338.490000 ( 57.955000) After: $ jruby ~/tmp/json_contention.rb 326.400000 0.580000 326.980000 ( 43.084000) That's a 25% reduction in processing time for parsing the same JSON on my quad core machine. I'd expect an even higher percentage improvement on a machine with more CPUs.
-rw-r--r--java/src/json/ext/Parser.java171
-rw-r--r--java/src/json/ext/Parser.rl9
2 files changed, 91 insertions, 89 deletions
diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/Parser.java
index 6cb5886..37423f5 100644
--- a/java/src/json/ext/Parser.java
+++ b/java/src/json/ext/Parser.java
@@ -130,7 +130,7 @@ public class Parser extends RubyObject {
*
* <dt><code>:create_additions</code>
* <dd>If set to <code>false</code>, the Parser doesn't create additions
- * even if a matchin class and <code>create_id</code> was found. This option
+ * even if a matching class and <code>create_id</code> was found. This option
* defaults to <code>true</code>.
*
* <dt><code>:object_class</code>
@@ -248,7 +248,7 @@ public class Parser extends RubyObject {
*/
@JRubyMethod
public IRubyObject parse(ThreadContext context) {
- return new ParserSession(this, context).parse();
+ return new ParserSession(this, context, info).parse();
}
/**
@@ -304,6 +304,7 @@ public class Parser extends RubyObject {
private static class ParserSession {
private final Parser parser;
private final ThreadContext context;
+ private final RuntimeInfo info;
private final ByteList byteList;
private final ByteList view;
private final byte[] data;
@@ -315,9 +316,10 @@ public class Parser extends RubyObject {
// no idea about the origins of this value, ask Flori ;)
private static final int EVIL = 0x666;
- private ParserSession(Parser parser, ThreadContext context) {
+ private ParserSession(Parser parser, ThreadContext context, RuntimeInfo info) {
this.parser = parser;
this.context = context;
+ this.info = info;
this.byteList = parser.checkAndGetSource().getByteList();
this.data = byteList.unsafeBytes();
this.view = new ByteList(data, false);
@@ -337,11 +339,11 @@ public class Parser extends RubyObject {
}
-// line 363 "Parser.rl"
+// line 365 "Parser.rl"
-// line 345 "Parser.java"
+// line 347 "Parser.java"
private static byte[] init__JSON_value_actions_0()
{
return new byte [] {
@@ -455,7 +457,7 @@ static final int JSON_value_error = 0;
static final int JSON_value_en_main = 1;
-// line 469 "Parser.rl"
+// line 471 "Parser.rl"
void parseValue(ParserResult res, int p, int pe) {
@@ -463,14 +465,14 @@ static final int JSON_value_en_main = 1;
IRubyObject result = null;
-// line 467 "Parser.java"
+// line 469 "Parser.java"
{
cs = JSON_value_start;
}
-// line 476 "Parser.rl"
+// line 478 "Parser.rl"
-// line 474 "Parser.java"
+// line 476 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -496,13 +498,13 @@ case 1:
while ( _nacts-- > 0 ) {
switch ( _JSON_value_actions[_acts++] ) {
case 9:
-// line 454 "Parser.rl"
+// line 456 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 506 "Parser.java"
+// line 508 "Parser.java"
}
}
@@ -565,25 +567,25 @@ case 1:
switch ( _JSON_value_actions[_acts++] )
{
case 0:
-// line 371 "Parser.rl"
+// line 373 "Parser.rl"
{
result = getRuntime().getNil();
}
break;
case 1:
-// line 374 "Parser.rl"
+// line 376 "Parser.rl"
{
result = getRuntime().getFalse();
}
break;
case 2:
-// line 377 "Parser.rl"
+// line 379 "Parser.rl"
{
result = getRuntime().getTrue();
}
break;
case 3:
-// line 380 "Parser.rl"
+// line 382 "Parser.rl"
{
if (parser.allowNaN) {
result = getConstant(CONST_NAN);
@@ -593,7 +595,7 @@ case 1:
}
break;
case 4:
-// line 387 "Parser.rl"
+// line 389 "Parser.rl"
{
if (parser.allowNaN) {
result = getConstant(CONST_INFINITY);
@@ -603,7 +605,7 @@ case 1:
}
break;
case 5:
-// line 394 "Parser.rl"
+// line 396 "Parser.rl"
{
if (pe > p + 9 - (parser.quirksMode ? 1 : 0) &&
absSubSequence(p, p + 9).equals(JSON_MINUS_INFINITY)) {
@@ -632,7 +634,7 @@ case 1:
}
break;
case 6:
-// line 420 "Parser.rl"
+// line 422 "Parser.rl"
{
parseString(res, p, pe);
if (res.result == null) {
@@ -645,7 +647,7 @@ case 1:
}
break;
case 7:
-// line 430 "Parser.rl"
+// line 432 "Parser.rl"
{
currentNesting++;
parseArray(res, p, pe);
@@ -660,7 +662,7 @@ case 1:
}
break;
case 8:
-// line 442 "Parser.rl"
+// line 444 "Parser.rl"
{
currentNesting++;
parseObject(res, p, pe);
@@ -674,7 +676,7 @@ case 1:
}
}
break;
-// line 678 "Parser.java"
+// line 680 "Parser.java"
}
}
}
@@ -694,7 +696,7 @@ case 5:
break; }
}
-// line 477 "Parser.rl"
+// line 479 "Parser.rl"
if (cs >= JSON_value_first_final && result != null) {
res.update(result, p);
@@ -704,7 +706,7 @@ case 5:
}
-// line 708 "Parser.java"
+// line 710 "Parser.java"
private static byte[] init__JSON_integer_actions_0()
{
return new byte [] {
@@ -803,7 +805,7 @@ static final int JSON_integer_error = 0;
static final int JSON_integer_en_main = 1;
-// line 496 "Parser.rl"
+// line 498 "Parser.rl"
void parseInteger(ParserResult res, int p, int pe) {
@@ -821,15 +823,15 @@ static final int JSON_integer_en_main = 1;
int cs = EVIL;
-// line 825 "Parser.java"
+// line 827 "Parser.java"
{
cs = JSON_integer_start;
}
-// line 513 "Parser.rl"
+// line 515 "Parser.rl"
int memo = p;
-// line 833 "Parser.java"
+// line 835 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -910,13 +912,13 @@ case 1:
switch ( _JSON_integer_actions[_acts++] )
{
case 0:
-// line 490 "Parser.rl"
+// line 492 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 920 "Parser.java"
+// line 922 "Parser.java"
}
}
}
@@ -936,7 +938,7 @@ case 5:
break; }
}
-// line 515 "Parser.rl"
+// line 517 "Parser.rl"
if (cs < JSON_integer_first_final) {
return -1;
@@ -958,7 +960,7 @@ case 5:
}
-// line 962 "Parser.java"
+// line 964 "Parser.java"
private static byte[] init__JSON_float_actions_0()
{
return new byte [] {
@@ -1060,7 +1062,7 @@ static final int JSON_float_error = 0;
static final int JSON_float_en_main = 1;
-// line 550 "Parser.rl"
+// line 552 "Parser.rl"
void parseFloat(ParserResult res, int p, int pe) {
@@ -1078,15 +1080,15 @@ static final int JSON_float_en_main = 1;
int cs = EVIL;
-// line 1082 "Parser.java"
+// line 1084 "Parser.java"
{
cs = JSON_float_start;
}
-// line 567 "Parser.rl"
+// line 569 "Parser.rl"
int memo = p;
-// line 1090 "Parser.java"
+// line 1092 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1167,13 +1169,13 @@ case 1:
switch ( _JSON_float_actions[_acts++] )
{
case 0:
-// line 541 "Parser.rl"
+// line 543 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1177 "Parser.java"
+// line 1179 "Parser.java"
}
}
}
@@ -1193,7 +1195,7 @@ case 5:
break; }
}
-// line 569 "Parser.rl"
+// line 571 "Parser.rl"
if (cs < JSON_float_first_final) {
return -1;
@@ -1209,7 +1211,7 @@ case 5:
}
-// line 1213 "Parser.java"
+// line 1215 "Parser.java"
private static byte[] init__JSON_string_actions_0()
{
return new byte [] {
@@ -1311,7 +1313,7 @@ static final int JSON_string_error = 0;
static final int JSON_string_en_main = 1;
-// line 614 "Parser.rl"
+// line 616 "Parser.rl"
void parseString(ParserResult res, int p, int pe) {
@@ -1319,15 +1321,15 @@ static final int JSON_string_en_main = 1;
IRubyObject result = null;
-// line 1323 "Parser.java"
+// line 1325 "Parser.java"
{
cs = JSON_string_start;
}
-// line 621 "Parser.rl"
+// line 623 "Parser.rl"
int memo = p;
-// line 1331 "Parser.java"
+// line 1333 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1408,7 +1410,7 @@ case 1:
switch ( _JSON_string_actions[_acts++] )
{
case 0:
-// line 589 "Parser.rl"
+// line 591 "Parser.rl"
{
int offset = byteList.begin();
ByteList decoded = decoder.decode(byteList, memo + 1 - offset,
@@ -1423,13 +1425,13 @@ case 1:
}
break;
case 1:
-// line 602 "Parser.rl"
+// line 604 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1433 "Parser.java"
+// line 1435 "Parser.java"
}
}
}
@@ -1449,7 +1451,7 @@ case 5:
break; }
}
-// line 623 "Parser.rl"
+// line 625 "Parser.rl"
if (parser.createAdditions) {
RubyHash match_string = parser.match_string;
@@ -1476,8 +1478,7 @@ case 5:
}
}
- if (cs >= JSON_string_first_final && result != null) {
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
+ if (cs >= JSON_string_first_final && result != null) {
if (info.encodingsSupported() && result instanceof RubyString) {
((RubyString)result).force_encoding(context, info.utf8.get());
}
@@ -1488,7 +1489,7 @@ case 5:
}
-// line 1492 "Parser.java"
+// line 1493 "Parser.java"
private static byte[] init__JSON_array_actions_0()
{
return new byte [] {
@@ -1601,7 +1602,7 @@ static final int JSON_array_error = 0;
static final int JSON_array_en_main = 1;
-// line 697 "Parser.rl"
+// line 698 "Parser.rl"
void parseArray(ParserResult res, int p, int pe) {
@@ -1621,14 +1622,14 @@ static final int JSON_array_en_main = 1;
}
-// line 1625 "Parser.java"
+// line 1626 "Parser.java"
{
cs = JSON_array_start;
}
-// line 716 "Parser.rl"
+// line 717 "Parser.rl"
-// line 1632 "Parser.java"
+// line 1633 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1709,7 +1710,7 @@ case 1:
switch ( _JSON_array_actions[_acts++] )
{
case 0:
-// line 666 "Parser.rl"
+// line 667 "Parser.rl"
{
parseValue(res, p, pe);
if (res.result == null) {
@@ -1726,13 +1727,13 @@ case 1:
}
break;
case 1:
-// line 681 "Parser.rl"
+// line 682 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 1736 "Parser.java"
+// line 1737 "Parser.java"
}
}
}
@@ -1752,7 +1753,7 @@ case 5:
break; }
}
-// line 717 "Parser.rl"
+// line 718 "Parser.rl"
if (cs >= JSON_array_first_final) {
res.update(result, p + 1);
@@ -1762,7 +1763,7 @@ case 5:
}
-// line 1766 "Parser.java"
+// line 1767 "Parser.java"
private static byte[] init__JSON_object_actions_0()
{
return new byte [] {
@@ -1885,7 +1886,7 @@ static final int JSON_object_error = 0;
static final int JSON_object_en_main = 1;
-// line 776 "Parser.rl"
+// line 777 "Parser.rl"
void parseObject(ParserResult res, int p, int pe) {
@@ -1910,14 +1911,14 @@ static final int JSON_object_en_main = 1;
}
-// line 1914 "Parser.java"
+// line 1915 "Parser.java"
{
cs = JSON_object_start;
}
-// line 800 "Parser.rl"
+// line 801 "Parser.rl"
-// line 1921 "Parser.java"
+// line 1922 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -1998,7 +1999,7 @@ case 1:
switch ( _JSON_object_actions[_acts++] )
{
case 0:
-// line 731 "Parser.rl"
+// line 732 "Parser.rl"
{
parseValue(res, p, pe);
if (res.result == null) {
@@ -2015,7 +2016,7 @@ case 1:
}
break;
case 1:
-// line 746 "Parser.rl"
+// line 747 "Parser.rl"
{
parseString(res, p, pe);
if (res.result == null) {
@@ -2035,13 +2036,13 @@ case 1:
}
break;
case 2:
-// line 764 "Parser.rl"
+// line 765 "Parser.rl"
{
p--;
{ p += 1; _goto_targ = 5; if (true) continue _goto;}
}
break;
-// line 2045 "Parser.java"
+// line 2046 "Parser.java"
}
}
}
@@ -2061,7 +2062,7 @@ case 5:
break; }
}
-// line 801 "Parser.rl"
+// line 802 "Parser.rl"
if (cs < JSON_object_first_final) {
res.update(null, p + 1);
@@ -2094,7 +2095,7 @@ case 5:
}
-// line 2098 "Parser.java"
+// line 2099 "Parser.java"
private static byte[] init__JSON_actions_0()
{
return new byte [] {
@@ -2198,7 +2199,7 @@ static final int JSON_error = 0;
static final int JSON_en_main = 1;
-// line 866 "Parser.rl"
+// line 867 "Parser.rl"
public IRubyObject parseStrict() {
@@ -2208,16 +2209,16 @@ static final int JSON_en_main = 1;
ParserResult res = new ParserResult();
-// line 2212 "Parser.java"
+// line 2213 "Parser.java"
{
cs = JSON_start;
}
-// line 875 "Parser.rl"
+// line 876 "Parser.rl"
p = byteList.begin();
pe = p + byteList.length();
-// line 2221 "Parser.java"
+// line 2222 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -2298,7 +2299,7 @@ case 1:
switch ( _JSON_actions[_acts++] )
{
case 0:
-// line 838 "Parser.rl"
+// line 839 "Parser.rl"
{
currentNesting = 1;
parseObject(res, p, pe);
@@ -2312,7 +2313,7 @@ case 1:
}
break;
case 1:
-// line 850 "Parser.rl"
+// line 851 "Parser.rl"
{
currentNesting = 1;
parseArray(res, p, pe);
@@ -2325,7 +2326,7 @@ case 1:
}
}
break;
-// line 2329 "Parser.java"
+// line 2330 "Parser.java"
}
}
}
@@ -2345,7 +2346,7 @@ case 5:
break; }
}
-// line 878 "Parser.rl"
+// line 879 "Parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
@@ -2355,7 +2356,7 @@ case 5:
}
-// line 2359 "Parser.java"
+// line 2360 "Parser.java"
private static byte[] init__JSON_quirks_mode_actions_0()
{
return new byte [] {
@@ -2458,7 +2459,7 @@ static final int JSON_quirks_mode_error = 0;
static final int JSON_quirks_mode_en_main = 1;
-// line 906 "Parser.rl"
+// line 907 "Parser.rl"
public IRubyObject parseQuirksMode() {
@@ -2468,16 +2469,16 @@ static final int JSON_quirks_mode_en_main = 1;
ParserResult res = new ParserResult();
-// line 2472 "Parser.java"
+// line 2473 "Parser.java"
{
cs = JSON_quirks_mode_start;
}
-// line 915 "Parser.rl"
+// line 916 "Parser.rl"
p = byteList.begin();
pe = p + byteList.length();
-// line 2481 "Parser.java"
+// line 2482 "Parser.java"
{
int _klen;
int _trans = 0;
@@ -2558,7 +2559,7 @@ case 1:
switch ( _JSON_quirks_mode_actions[_acts++] )
{
case 0:
-// line 892 "Parser.rl"
+// line 893 "Parser.rl"
{
parseValue(res, p, pe);
if (res.result == null) {
@@ -2570,7 +2571,7 @@ case 1:
}
}
break;
-// line 2574 "Parser.java"
+// line 2575 "Parser.java"
}
}
}
@@ -2590,7 +2591,7 @@ case 5:
break; }
}
-// line 918 "Parser.rl"
+// line 919 "Parser.rl"
if (cs >= JSON_quirks_mode_first_final && p == pe) {
return result;
diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/Parser.rl
index 7dcdd2e..6d65963 100644
--- a/java/src/json/ext/Parser.rl
+++ b/java/src/json/ext/Parser.rl
@@ -246,7 +246,7 @@ public class Parser extends RubyObject {
*/
@JRubyMethod
public IRubyObject parse(ThreadContext context) {
- return new ParserSession(this, context).parse();
+ return new ParserSession(this, context, info).parse();
}
/**
@@ -302,6 +302,7 @@ public class Parser extends RubyObject {
private static class ParserSession {
private final Parser parser;
private final ThreadContext context;
+ private final RuntimeInfo info;
private final ByteList byteList;
private final ByteList view;
private final byte[] data;
@@ -313,9 +314,10 @@ public class Parser extends RubyObject {
// no idea about the origins of this value, ask Flori ;)
private static final int EVIL = 0x666;
- private ParserSession(Parser parser, ThreadContext context) {
+ private ParserSession(Parser parser, ThreadContext context, RuntimeInfo info) {
this.parser = parser;
this.context = context;
+ this.info = info;
this.byteList = parser.checkAndGetSource().getByteList();
this.data = byteList.unsafeBytes();
this.view = new ByteList(data, false);
@@ -646,8 +648,7 @@ public class Parser extends RubyObject {
}
}
- if (cs >= JSON_string_first_final && result != null) {
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
+ if (cs >= JSON_string_first_final && result != null) {
if (info.encodingsSupported() && result instanceof RubyString) {
((RubyString)result).force_encoding(context, info.utf8.get());
}