Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unnessary volatile qualifier in Oj.load #802

Merged
merged 1 commit into from
Jul 30, 2022

Conversation

Watson1978
Copy link
Collaborator

When we use volatile qualifier, seems it has some performance penalty on GCC.
The volatile qualifier is unnecessary since the VALUE type object has been kept on the local stack.
(If we manage VALUE on the heap, we need to be careful.)

before after result
GCC 4.969M 5.165M 1.039x
Clang 5.054M 5.090M -

Environment

  • Linux
    • Manjaro Linux x86_64
    • Kernel: 5.18.12-3-MANJARO
    • AMD Ryzen 7 5700G
    • gcc version 12.1.0
    • clang version 14.0.6
    • Ruby 3.1.2

GCC

Before

Warming up --------------------------------------
             Oj.load   497.783k i/100ms
Calculating -------------------------------------
             Oj.load      4.969M (± 0.1%) i/s -     49.778M in  10.017042s

After

Warming up --------------------------------------
             Oj.load   518.127k i/100ms
Calculating -------------------------------------
             Oj.load      5.165M (± 0.1%) i/s -     51.813M in  10.031075s

Clang

Before

Warming up --------------------------------------
             Oj.load   503.712k i/100ms
Calculating -------------------------------------
             Oj.load      5.054M (± 0.1%) i/s -     50.875M in  10.067027s

After

Warming up --------------------------------------
             Oj.load   510.215k i/100ms
Calculating -------------------------------------
             Oj.load      5.090M (± 0.1%) i/s -     51.022M in  10.022973s

Test code

require 'benchmark/ips'
require 'oj'

json = Oj.dump(42)

Benchmark.ips do |x|
  x.warmup = 5
  x.time = 10

  x.report('Oj.load') do |times|
    i = 0
    while i < times
      Oj.load(json)
      i += 1
    end
  end
end

@ohler55
Copy link
Owner

ohler55 commented Jul 29, 2022

I'd have to see more tests with large files that cause a GC while parsing. My understanding is the volatile keyword cause the variable not to be put in a register since Ruby does not"see" register variables. Making the VALUE volatile tests the compiler it may change to put it on the stack instead of in a register.

@Watson1978 Watson1978 force-pushed the volatile branch 2 times, most recently from 3c96012 to caf6e0a Compare July 30, 2022 15:42
@Watson1978
Copy link
Collaborator Author

Added the test

When we use volatile qualifier, seems it has some performance penalty on GCC.
The volatile qualifier is unnecessary since the VALUE type object has been kept on the local stack.
(If we manage VALUE on the heap, we need to be careful.)

−       | before  | after   | result
--       | --      | --      | --
GCC      | 4.969M  | 5.165M  | 1.039x
Clang    | 5.054M  | 5.090M  | -


### Environment
- Linux
  - Manjaro Linux x86_64
  - Kernel: 5.18.12-3-MANJARO
  - AMD Ryzen 7 5700G
  - gcc version 12.1.0
  - clang version 14.0.6
  - Ruby 3.1.2

### GCC
#### Before
```
Warming up --------------------------------------
             Oj.load   497.783k i/100ms
Calculating -------------------------------------
             Oj.load      4.969M (± 0.1%) i/s -     49.778M in  10.017042s
```

#### After
```
Warming up --------------------------------------
             Oj.load   518.127k i/100ms
Calculating -------------------------------------
             Oj.load      5.165M (± 0.1%) i/s -     51.813M in  10.031075s
```

### Clang
#### Before
```
Warming up --------------------------------------
             Oj.load   503.712k i/100ms
Calculating -------------------------------------
             Oj.load      5.054M (± 0.1%) i/s -     50.875M in  10.067027s
```

#### After
```
Warming up --------------------------------------
             Oj.load   510.215k i/100ms
Calculating -------------------------------------
             Oj.load      5.090M (± 0.1%) i/s -     51.022M in  10.022973s
```

### Test code
```ruby
require 'benchmark/ips'
require 'oj'

json = Oj.dump(42)

Benchmark.ips do |x|
  x.warmup = 5
  x.time = 10

  x.report('Oj.load') do |times|
    i = 0
    while i < times
      Oj.load(json)
      i += 1
    end
  end
end
```
@ohler55
Copy link
Owner

ohler55 commented Jul 30, 2022

I'll have to remember GC.stress. Looks very useful when testing.

@ohler55 ohler55 merged commit 62f4c61 into ohler55:develop Jul 30, 2022
@Watson1978 Watson1978 deleted the volatile branch July 31, 2022 04:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants