Skip to content

Commit

Permalink
Improve performance of reading escaped string (#948)
Browse files Browse the repository at this point in the history
This patch will improve the performance of reading escaped string
by using a lookup table.

−       | before  | after   | result
--      | --      | --      | --
Oj.load | 601.508 | 654.004 | 1.087x

### Environment
- Linux
  - Manjaro Linux x86_64
  - Kernel: 6.12.4-1-MANJARO
  - AMD Ryzen 9 8945HS
  - gcc version 14.2.1
  - Ruby 3.4.1

### Code
```ruby
require 'bundler/inline'
gemfile do
  source 'https://rubygems.org'
  gem 'benchmark-ips'
  gem 'oj'
end

# https://github.com/miloyip/nativejson-benchmark/blob/master/data/twitter.json
json = File.read('twitter.json')

Benchmark.ips do |x|
  x.time = 10
  x.report('Oj.load compat') { Oj.load(json, mode: :compat) }
end
```

### Before
```
$ ruby json_load.rb
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
      Oj.load compat    59.000 i/100ms
Calculating -------------------------------------
      Oj.load compat    601.508 (± 1.2%) i/s    (1.66 ms/i) -      6.018k in  10.006395s
```

### After
```
$ ruby json_load.rb
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [x86_64-linux]
Warming up --------------------------------------
      Oj.load compat    64.000 i/100ms
Calculating -------------------------------------
      Oj.load compat    654.004 (± 1.7%) i/s    (1.53 ms/i) -      6.592k in  10.082170s
```
  • Loading branch information
Watson1978 authored Jan 2, 2025
1 parent 04b612b commit 7388e5b
Showing 1 changed file with 12 additions and 2 deletions.
14 changes: 12 additions & 2 deletions ext/oj/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,19 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
}
}

static const unsigned char end_of_scan_string[] = {
// Filled 1 at the positions of '\0', '\\', and '"'
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
for (; '"' != *str; str++) {
if (end <= str || '\0' == *str || '\\' == *str) {
for (; str < end; str++) {
if (end_of_scan_string[(unsigned char)*str]) {
break;
}
}
Expand Down

0 comments on commit 7388e5b

Please sign in to comment.