Skip to content

Commit

Permalink
Improve JSON_parse_string() performance
Browse files Browse the repository at this point in the history
`rb_str_resize()` might reallocate the heap area in String object and it might cause to downgrade the performance.

When use `rb_str_new()` instead of `rb_str_buf_new()`, it does not allocate extra heap area internally. After then, it will not need to resize the object.

This patch will be 36.6 % faster for parsing string value.

## Before
```
$ ruby bench.rb
Warming up --------------------------------------
                json    14.000  i/100ms
Calculating -------------------------------------
                json    144.882  (± 1.4%) i/s -    728.000  in   5.025682s
** Memory usage
1105348
```

## After
```
$ ruby bench.rb
Warming up --------------------------------------
                json    19.000  i/100ms
Calculating -------------------------------------
                json    197.928  (± 4.5%) i/s -    988.000  in   5.005914s
** Memory usage
1138428
```

## Test code
```
require 'json'
require 'objspace'
require 'securerandom'
require 'benchmark/ips'

obj = []

1000.times do |i|
  obj << {
    "id": i,
    "uuid": SecureRandom.uuid,
    "created_at": Time.now
  }
end

json = obj.to_json

Benchmark.ips do |x|
  x.report "json" do |iter|
    count = 0
    while count < iter
      JSON.parse(json)
      count += 1
    end
  end
end

puts "** Memory usage"
p ObjectSpace.memsize_of_all String
```
  • Loading branch information
Watson1978 committed Feb 25, 2018
1 parent b3ec252 commit c451dd8
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 14 deletions.
20 changes: 9 additions & 11 deletions ext/json/ext/parser/parser.c
Expand Up @@ -1514,7 +1514,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
int cs = EVIL;
VALUE match_string;

*result = rb_str_buf_new(0);
*result = rb_str_new(NULL, 0);

#line 1520 "parser.c"
{
Expand Down Expand Up @@ -1658,8 +1658,6 @@ case 7:

if (json->symbolize_names && json->parsing_name) {
*result = rb_str_intern(*result);
} else {
rb_str_resize(*result, RSTRING_LEN(*result));
}
if (cs >= JSON_string_first_final) {
return p + 1;
Expand Down Expand Up @@ -1830,15 +1828,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}


#line 1834 "parser.c"
#line 1832 "parser.c"
enum {JSON_start = 1};
enum {JSON_first_final = 10};
enum {JSON_error = 0};

enum {JSON_en_main = 1};


#line 742 "parser.rl"
#line 740 "parser.rl"


/*
Expand All @@ -1855,16 +1853,16 @@ static VALUE cParser_parse(VALUE self)
GET_PARSER;


#line 1859 "parser.c"
#line 1857 "parser.c"
{
cs = JSON_start;
}

#line 758 "parser.rl"
#line 756 "parser.rl"
p = json->source;
pe = p + json->len;

#line 1868 "parser.c"
#line 1866 "parser.c"
{
if ( p == pe )
goto _test_eof;
Expand Down Expand Up @@ -1898,7 +1896,7 @@ case 1:
cs = 0;
goto _out;
tr2:
#line 734 "parser.rl"
#line 732 "parser.rl"
{
char *np = JSON_parse_value(json, p, pe, &result, 0);
if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
Expand All @@ -1908,7 +1906,7 @@ cs = 0;
if ( ++p == pe )
goto _test_eof10;
case 10:
#line 1912 "parser.c"
#line 1910 "parser.c"
switch( (*p) ) {
case 13: goto st10;
case 32: goto st10;
Expand Down Expand Up @@ -1997,7 +1995,7 @@ case 9:
_out: {}
}

#line 761 "parser.rl"
#line 759 "parser.rl"

if (cs >= JSON_first_final && p == pe) {
return result;
Expand Down
4 changes: 1 addition & 3 deletions ext/json/ext/parser/parser.rl
Expand Up @@ -535,7 +535,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
int cs = EVIL;
VALUE match_string;

*result = rb_str_buf_new(0);
*result = rb_str_new(NULL, 0);
%% write init;
json->memo = p;
%% write exec;
Expand All @@ -553,8 +553,6 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu

if (json->symbolize_names && json->parsing_name) {
*result = rb_str_intern(*result);
} else {
rb_str_resize(*result, RSTRING_LEN(*result));
}
if (cs >= JSON_string_first_final) {
return p + 1;
Expand Down

0 comments on commit c451dd8

Please sign in to comment.