Download - Ruby performance - The low hanging fruit
![Page 1: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/1.jpg)
Ruby PerformanceThe Low Hanging Fruit
![Page 2: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/2.jpg)
Hello, I’m Bruce Werdschinski
Senior Lead Developer, Prezentt !
Spent 5 years as the Technical Director at GTP iCommerce
!
~2.5 years with Ruby, built hundreds of ecommerce websites, loves SEO &
CRO !
Mercedes enthusiast
![Page 3: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/3.jpg)
Agenda
• Introduction to common tools
• Scenarios where we would use those tools
• What else can we do, low hanging fruit wise
![Page 4: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/4.jpg)
From experience, look at common expensive tasks
• Database operations
• Network access
• Incorrect algorithm
• Unnecessary work - Can we cache it?
![Page 5: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/5.jpg)
Ruby benchmark
• Disable Garbage Collection first with: GC.disable
• Part of the Ruby standard library
• I prefer to use it like this: !
time = Benchmark.realtime do # The code I’m testing end
![Page 6: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/6.jpg)
benchmark-ips
• https://github.com/evanphx/benchmark-ips
• Benchmarks a blocks iterations/second.
• For short snippits of code, IPS automatically figures out how many times to run the code to get interesting data
• Provides a standard deviation measure which is very cool
![Page 7: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/7.jpg)
stackprof• https://github.com/tmm1/stackprof
• For Ruby 2.1 and above
• Samples what the CPU is spending time on
• https://github.com/alisnic/stackprof-webnav is a Web UI for stackprof dumps
• https://github.com/quirkey/stackprof-remote is middleware and CLI for fetching and interacting with stackprof
![Page 8: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/8.jpg)
How do we find expensive things?• Experience / Knowledge
• Logs
• Ruby's own benchmark module
• External tools
• benchmark-ips, stackprof, time
• SaaS metrics tools
• Librato, Datadog, Skylight, New Relic, Keen IO
![Page 9: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/9.jpg)
Reduce the impact• Optimise the application
• Optimise the environment
![Page 10: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/10.jpg)
Optimise the Application
• Reduce heavy I/O
• ActiveRecord tweaks
• Caching
![Page 11: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/11.jpg)
Reduce heavy I/OSilly example, but it illustrates the point. Writing to the screen is more expensive than writing to memory !1_000_000.times do puts "Hello world!" end !s = String.new 1_000_000.times do s << "Hello world!\n" end puts s
10.5 seconds vs. 6.5 seconds - But 2.28 times more memory
![Page 12: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/12.jpg)
Reduce heavy I/O• Same applies for database calls,
event processing, etc. One large call is often much faster than many little calls.
• I’ve been playing with Keen IO lately, their demo app is at: http://keen-gem-example.herokuapp.com/
• 50 calls, 1 item each: 20094ms
• 1 call with 50 items: 284ms
![Page 13: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/13.jpg)
ActiveRecord
• Know your SQL
• Check logs to see what ActiveRecord is actually doing
• Lots of tools to help us
![Page 14: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/14.jpg)
ActiveRecord sum example
I want to get a total of all to the orders in the database
Order.sum(&:total)
Order Load (49.3ms) SELECT "orders".* FROM "orders"
Order.sum(:total)
(4.0ms) SELECT SUM("orders"."total") AS sum_id FROM "orders"
![Page 15: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/15.jpg)
ActiveRecord sum example
![Page 16: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/16.jpg)
ActiveRecord sum example
![Page 17: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/17.jpg)
ActiveRecord Tools
• rack-mini-profiler
• RailsPanel
• rails-footnotes
• Bullet
• Peek
![Page 18: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/18.jpg)
rack-mini-profiler• https://github.com/MiniProfiler/
rack-mini-profiler
• Middleware that shows a HTML panel on each page
![Page 19: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/19.jpg)
RailsPanel• https://github.com/dejan/
rails_panel
• Chrome Extension that provides information about the Rails request. Includes Database, rendering and total times.
![Page 20: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/20.jpg)
Memoization
Memoization is a caching technique of storing a computed value to avoid duplicated work by future calls.
1. Perform some work
2. Store the result of that work
3. Use the stored data the next time you need the result of that work
![Page 21: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/21.jpg)
MemoizationA common pattern is using the conditional assignment operator: ||=
def current_user
User.find(session[:user_id])
end
Instead store the result in an instance variable by using:
def current_user
@current_user ||= User.find(session[:user_id])
end
![Page 22: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/22.jpg)
identity_cachehttps://github.com/Shopify/identity_cache
ActiveRecord cache for model objects
Extracted from Shopify
@user = User.fetch(id) instead of @user = User.find(id)
Uses an after_commit hook to expire the object from cache
![Page 23: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/23.jpg)
Rails Cache• Use the Dalli gem as the Rails cache store
def fetch(id)
Rails.cache.fetch("product-#{id}", expires_in: 5.minutes) do
Product.find(id)
end
end
![Page 24: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/24.jpg)
Is Ruby the best tool?
• Sometimes…shock, horror…Ruby might not be the best tool for the job.
• Where Ruby may not be the best fit:
• CPU bound
• Async I/O
![Page 25: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/25.jpg)
Leibniz formula for π1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 … = π/4
20 million iterations
CPU bound task
• Ruby: 3.78 seconds
• Rust: 0.238 seconds
![Page 26: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/26.jpg)
Optimise the Environment
• Low hanging fruit, faster server, database, more memory
• Ruby versions
• Network topology
• Caching systems
• Web performance
![Page 27: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/27.jpg)
Web performance
• No point shaving 1/10th of a second off your database access time if you’ve got a 3Mb background image.
• http://gtmetrix.com/
• http://tools.pingdom.com/fpt/
![Page 28: Ruby performance - The low hanging fruit](https://reader033.vdocument.in/reader033/viewer/2022052507/558a257bd8b42a10248b46f8/html5/thumbnails/28.jpg)
No more low hanging fruit
• “Ruby Under a Microscope” by Pat Shaughnessy
• Utilization Saturation and Errors (USE) Method