charkost / prosopite

:mag: Rails N+1 queries auto-detection with zero false positives / false negatives
Apache License 2.0
1.48k stars 45 forks source link

Improve performance in sql.activerecord subscription callback #66

Closed technicalpickles closed 1 year ago

technicalpickles commented 1 year ago

I was memory profiling a particularly slow system spec, and these two lines popped up on my radar. It's calling caller twice, and then duplicating one of them.

caller is pretty well understood as being pretty slow, so calling it only once is an Improve.

The second call was using dup. This should not be necessary, as caller returns a new object anyways. Even when calling caller once, we don't do any manipulation of it, so it's safe to remove the dup

In my specific spec, I saw an improvement from 2m18s to 1m58s. I also did a micro benchmark showing the difference:

require 'benchmark/ips'
require 'digest'

def original
  location_key = Digest::SHA1.hexdigest(caller.join)
  caller.dup
end

def refactored
  query_caller = caller
  location_key = Digest::SHA1.hexdigest(query_caller.join)
  query_caller
end

Benchmark.ips do |x|
  x.report("original") { original }
  x.report("refactored") { refactored }
  x.compare!
end

Which gives us:

Warming up --------------------------------------
            original    15.465k i/100ms
          refactored    25.355k i/100ms
Calculating -------------------------------------
            original    150.987k (± 1.3%) i/s -    757.785k in   5.019798s
          refactored    253.851k (± 1.3%) i/s -      1.293M in   5.094844s

Comparison:
          refactored:   253850.9 i/s
            original:   150987.3 i/s - 1.68x  slower
technicalpickles commented 1 year ago

Snuck another small improvement: Use SHA256 with is marginally faster than SHA1

Benchmark:

require 'benchmark/ips'
require 'digest'

def refactored
  query_caller = caller
  location_key = Digest::SHA1.hexdigest(query_caller.join)
  query_caller
end

def refactored_sha2
  query_caller = caller
  location_key = Digest::SHA256.hexdigest(query_caller.join)
  query_caller
end

Benchmark.ips do |x|
  x.config warmup: 0, times: 100
  x.report("refactored") { refactored }
  x.report("refactored_sha2") { refactored_sha2 }
  x.compare!
end

Results:

Calculating -------------------------------------
          refactored    272.508k (±16.2%) i/s -      1.157M in   4.794913s
     refactored_sha2    279.210k (±16.6%) i/s -      1.184M in   4.793971s

Comparison:
     refactored_sha2:   279210.1 i/s
          refactored:   272507.7 i/s - same-ish: difference falls within error
charkost commented 1 year ago

Nice perf improvements @technicalpickles, thanks!