diff options
author | Ben Browning <bbrownin@redhat.com> | 2014-12-16 10:12:10 -0500 |
---|---|---|
committer | Ben Browning <bbrownin@redhat.com> | 2014-12-16 10:12:10 -0500 |
commit | eaac48419d196e909fcdf526c4e3dbec2cc3d19b (patch) | |
tree | 1f851077f62e776de524e731a3b092f4b5b6a782 /java/src/json/ext/Parser.rl | |
parent | 17fe8e72f484e65e0c36670946934d1f8696e37b (diff) | |
download | json-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.
Diffstat (limited to 'java/src/json/ext/Parser.rl')
-rw-r--r-- | java/src/json/ext/Parser.rl | 9 |
1 files changed, 5 insertions, 4 deletions
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()); } |