Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
base: 9291c56e2cc1
Choose a base ref
...
head repository: jruby/jruby
compare: 933fae03ded6
Choose a head ref
  • 2 commits
  • 1 file changed
  • 2 contributors

Commits on Dec 6, 2016

  1. Optimize getDefinedMessage by deduping during initialization

    While benchmarking a barebones rails application I was seeing a lot of
    lock contention. When I looked into it, all threads were spending a lot
    of time waiting to grab the mutex on the `dedupMap` inside
    `Ruby.freezeAndDedupString()`.
    
    This happened because activesupport uses
    `defined?(@somevar) && @somevar` a lot while filling the
    output template, and thus threads were spending a lot of time in the
    `Ruby.getDefinedMessage()` method fighting to dedup the same strings
    over and over and over again.
    
    To fix this, instead of deduping when they are accessed, let's dedup the
    defined messages when they are initially populated inside the
    definedMessages map. This way we get the same effect, but only dedup
    once.
    
    This fix has a considerable effect on single-thread performance:
    
    ```ruby
    require 'benchmark/ips'
    
    class Test
      def initialize
        @foo = 'foo'
      end
    
      def defined_test
        defined?(@foo) && @foo
      end
    end
    
    t = Test.new
    
    Benchmark.ips do |benchmark|
      benchmark.time = 20
      benchmark.warmup = 20
    
      benchmark.report("defined") { t.defined_test }
    
      benchmark.compare!
    end
    ```
    
    with fix:
    
    ```
    Warming up --------------------------------------
                 defined   256.296k i/100ms
    Calculating -------------------------------------
                 defined     11.992M (± 4.4%) i/s -    239.380M in  20.008996s
    ```
    
    without fix:
    
    ```
    Warming up --------------------------------------
                 defined   224.042k i/100ms
    Calculating -------------------------------------
                 defined      7.373M (± 2.5%) i/s -    147.420M in  20.009003s
    ```
    
    ...but it has an even more noticeable effect on multi-threaded performance:
    
    ```ruby
    def defined_loop(count)
      @foo = true
      count.times do
        defined?(@foo) && @foo
      end
    end
    
    defined_loop(2**27)
    
    puts "Warmup done"
    
    start = Time.now
    
    t = (0..20).map do
      Thread.new do
        defined_loop(2**25)
      end
    end
    
    t.each(&:join)
    
    puts "Done in #{Time.now - start} seconds"
    ```
    
    In this case I wasn't able to find a decent ruby multithreaded benchmark
    harness, so pardon the crappiness, but I ran it fine times and got
    (on a linux dual-core skylake i7):
    
    with fix:
    
    ```
    Done in 12.442 seconds
    Done in 12.284 seconds
    Done in 12.803 seconds
    Done in 13.724 seconds
    Done in 13.844 seconds
    ```
    
    and under visualvm it looks like this:
    
    ![Thread state graph with fix](http://i.imgur.com/i3f72H4.png)
    
    without fix:
    
    ```
    Done in 71.088 seconds
    Done in 71.664 seconds
    Done in 64.57 seconds
    Done in 65.504 seconds
    Done in 62.81 seconds
    ```
    
    and under visualvm it looks like this:
    
    ![Thread state graph without fix](http://i.imgur.com/0ulO9zM.png)
    
    As expected, this is a major win on multithreaded scenarios.
    ivoanjo committed Dec 6, 2016
    Copy the full SHA
    95b5d2e View commit details
    Browse the repository at this point in the history

Commits on Dec 7, 2016

  1. Merge pull request #4366 from ivoanjo/improve-defined-performance

    Optimize getDefinedMessage by deduping during initialization
    kares committed Dec 7, 2016
    Copy the full SHA
    933fae0 View commit details
    Browse the repository at this point in the history