ruby performance - the last mile - rubyconf india 2016

106
Ruby Performance The Last Mile

Upload: charles-nutter

Post on 22-Jan-2017

1.384 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Ruby Performance - The Last Mile - RubyConf India 2016

Ruby PerformanceThe Last Mile

Page 2: Ruby Performance - The Last Mile - RubyConf India 2016

Charles Oliver Nutter @headius

Page 3: Ruby Performance - The Last Mile - RubyConf India 2016
Page 4: Ruby Performance - The Last Mile - RubyConf India 2016
Page 5: Ruby Performance - The Last Mile - RubyConf India 2016

I've spent ten years building

Page 6: Ruby Performance - The Last Mile - RubyConf India 2016

I love Ruby

Page 7: Ruby Performance - The Last Mile - RubyConf India 2016

I want Ruby to succeed

Page 8: Ruby Performance - The Last Mile - RubyConf India 2016

I believe JRuby is the way

Page 9: Ruby Performance - The Last Mile - RubyConf India 2016

Do you want performance today?

Page 10: Ruby Performance - The Last Mile - RubyConf India 2016

Do you want concurrency today?

Page 11: Ruby Performance - The Last Mile - RubyConf India 2016

Do you know JRuby?

Page 12: Ruby Performance - The Last Mile - RubyConf India 2016
Page 13: Ruby Performance - The Last Mile - RubyConf India 2016

What you love from Ruby• Latest Ruby language features

• Mostly-same Ruby standard library

• Pure-Ruby gems work great

• Native gems with JRuby support

• It walks like Ruby, talks like Ruby

• It is Ruby!

Page 14: Ruby Performance - The Last Mile - RubyConf India 2016

With the power of the JVM

• Fast JIT to native code

• Fully parallel threading

• Leading-edge garbage collectors

• Access to Java, Scala, Clojure, ...

• But it's still Ruby!

Page 15: Ruby Performance - The Last Mile - RubyConf India 2016
Page 16: Ruby Performance - The Last Mile - RubyConf India 2016

Do you know Jay?

Page 17: Ruby Performance - The Last Mile - RubyConf India 2016

Matz's Keynote

Page 18: Ruby Performance - The Last Mile - RubyConf India 2016

Performance

Page 19: Ruby Performance - The Last Mile - RubyConf India 2016

Concurrency

Page 20: Ruby Performance - The Last Mile - RubyConf India 2016

By 2020

Page 21: Ruby Performance - The Last Mile - RubyConf India 2016

But what about today?

Page 22: Ruby Performance - The Last Mile - RubyConf India 2016

Performance

Page 23: Ruby Performance - The Last Mile - RubyConf India 2016

What do you optimize for?

• Easy to develop with: short time until first deploy

• Fast startup: good response cycle at command line

• Straight-line performance, many operations per second

• Parallelism: utilize many cores to get more done

Page 24: Ruby Performance - The Last Mile - RubyConf India 2016

State of the Art: Production-quality Rubies

Page 25: Ruby Performance - The Last Mile - RubyConf India 2016

Production Quality?• Support for 99%+ of Ruby language features

• Important parts of standard library

• Runs typical Ruby applications and libraries

• Healthy extension ecosystem

• CRuby, JRuby are the only real options right now

Page 26: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby (MRI)• Up until 1.9, AST interpreter

• YARV bytecode VM introduced for 1.9.0

• GC and performance improvements through 2.x series

• Ruby 2.3 is latest, released in December

• Future work on JIT, GC, happening now

Page 27: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby• Many redesigns since creation in 2001

• AST interpreter until 2007

• Simple AST-to-bytecode JIT until JRuby 9000

• Optimizing compiler with JIT for 9k

• JRuby 9.0.5 is current, 9.1 in a couple weeks

• Next-gen Truffle runtime in the works

Page 28: Ruby Performance - The Last Mile - RubyConf India 2016

Lies, damn lies, and benchmarks

Page 29: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby: red/black tree

0

2

4

6

8

1.8.7 1.9.3 2.0 2.1 2.2 2.3

Page 30: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby: red/black tree

0

0.625

1.25

1.875

2.5

1.8.7 1.9.3 2.0 2.1 2.2 2.3

Page 31: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby: red/black tree

0

1.25

2.5

3.75

5

JRuby 9.1 CRuby 2.3

Page 32: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby: red/black tree

0

1.25

2.5

3.75

5

JRuby 9.1 CRuby 2.3

Page 33: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby: red/black tree

0

0.6

1.2

1.8

2.4

JRuby 9.1 CRuby 2.3

4x FASTER

Page 34: Ruby Performance - The Last Mile - RubyConf India 2016

Ruby Code

Page 35: Ruby Performance - The Last Mile - RubyConf India 2016

Ruby Code

ParserJRuby AST

Page 36: Ruby Performance - The Last Mile - RubyConf India 2016

Parser

JRuby AST

Com

piler

JRuby IR

Page 37: Ruby Performance - The Last Mile - RubyConf India 2016

Com

piler

JRuby IR

JIT

JVM Bytecode

Page 38: Ruby Performance - The Last Mile - RubyConf India 2016

What can we do with this?

Page 39: Ruby Performance - The Last Mile - RubyConf India 2016

Block Pass-throughdef foo(&b) bar(&b) enddef bar yieldend

Page 40: Ruby Performance - The Last Mile - RubyConf India 2016

Block Pass-throughloop { puts Benchmark.measure { i = 0 while i < 1_000_000 i+=1 foo { }; foo { }; foo { }; foo { }; foo { } end } }

Page 41: Ruby Performance - The Last Mile - RubyConf India 2016

Block Passing

0

0.55

1.1

1.65

2.2CRuby 2.3 JRuby 1.7.24 JRuby 9.1

Page 42: Ruby Performance - The Last Mile - RubyConf India 2016

define_method

define_method :add do |a, b| a + b end

Page 43: Ruby Performance - The Last Mile - RubyConf India 2016

define_method

0

0.25

0.5

0.75

1CRuby 2.3 JRuby 1.7.24 JRuby 9.1

Page 44: Ruby Performance - The Last Mile - RubyConf India 2016

Postfix rescue

foo rescue nil

Page 45: Ruby Performance - The Last Mile - RubyConf India 2016

csv.rb Converters

Converters = { integer: lambda { |f| Integer(f.encode(ConverterEncoding)) rescue f }, float: lambda { |f| Float(f.encode(ConverterEncoding)) rescue f },

Page 46: Ruby Performance - The Last Mile - RubyConf India 2016

Postfix rescue

0

3.5

7

10.5

14CRuby 2.3 JRuby 9.1

Page 47: Ruby Performance - The Last Mile - RubyConf India 2016

0

3.5

7

10.5

14CRuby 2.3 JRuby 9.1

Postfix rescue

Page 48: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby starts up the fastest

Page 49: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby runs the fastest

Page 50: Ruby Performance - The Last Mile - RubyConf India 2016

And we're getting faster

Page 51: Ruby Performance - The Last Mile - RubyConf India 2016

Concurrency

Page 52: Ruby Performance - The Last Mile - RubyConf India 2016

Parallelism

Page 53: Ruby Performance - The Last Mile - RubyConf India 2016

Concurrency? Parallelism?

• Parallelism happens on the harder, e.g. multi-core

• Concurrency happens in the software, e.g. Thread API

• You can have concurrency without parallelism

• You can have both with JRuby

Page 54: Ruby Performance - The Last Mile - RubyConf India 2016
Page 55: Ruby Performance - The Last Mile - RubyConf India 2016

Parallelism in Ruby• On CRuby, usually process-level

• Ruby threads prevented from running in parallel

• Extensions, IO can opt to release lock

• On JRuby, usually thread-level

• Ruby thread == JVM thread == OS thread

• Single-process, shared memory

Page 56: Ruby Performance - The Last Mile - RubyConf India 2016

A Mailing Queue• A simple example of concurrency

• For each job, construct an email to send

• Some computation added to make processing heavier

• "Ruby Concurrency and Parallelism: A Practical Tutorial" https://www.toptal.com/ruby/ruby-concurrency-and-parallelism-a-practical-primer

Page 57: Ruby Performance - The Last Mile - RubyConf India 2016

require "./lib/mailer"require "benchmark"puts Benchmark.measure{ (ARGV[0] || 10_000).times do |i| Mailer.deliver do from "eki_#{i}@eqbalq.com" to "jill_#{i}@example.com" subject "Threading and Forking (#{i})" body "Some content" end end }

Page 58: Ruby Performance - The Last Mile - RubyConf India 2016

POOL_SIZE = (ARGV[0] || 10).to_ijobs = Queue.new(ARGV[1] || 10_000).to_i.times{|i| jobs.push i} workers = (POOL_SIZE).times.map do Thread.new do begin while x = jobs.pop(true) Mailer.deliver do ... end end rescue ThreadError end endendworkers.map(&:join)

Page 59: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby: mailer * 1000Ti

me

in S

econ

ds

0

37.5

75

112.5

150

synchronous 4 threads 4 forks

Page 60: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby: mailer * 1000

0

7

14

21

28

Synchronous 4 Threads

Page 61: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby vs MRITimes Improvement

0

0.85

1.7

2.55

3.4

CRuby Forks JRuby Threads

3.37x3.09x

Page 62: Ruby Performance - The Last Mile - RubyConf India 2016

But Threads are bad, right?

Page 63: Ruby Performance - The Last Mile - RubyConf India 2016

Most users will never Thread.new

Page 64: Ruby Performance - The Last Mile - RubyConf India 2016

You'll deploy one Rails server for your entire site

Page 65: Ruby Performance - The Last Mile - RubyConf India 2016

You'll cut your instances ten times

Page 66: Ruby Performance - The Last Mile - RubyConf India 2016

Or maybe 100 times

Page 67: Ruby Performance - The Last Mile - RubyConf India 2016

Libraries and frameworks will Thread.new for you

Page 68: Ruby Performance - The Last Mile - RubyConf India 2016

And on JRuby, you'll have more efficient apps

Page 69: Ruby Performance - The Last Mile - RubyConf India 2016

So we're done?

Page 70: Ruby Performance - The Last Mile - RubyConf India 2016

Move to JRuby

Page 71: Ruby Performance - The Last Mile - RubyConf India 2016

Now your app is fast!

Page 72: Ruby Performance - The Last Mile - RubyConf India 2016

Right?

Page 73: Ruby Performance - The Last Mile - RubyConf India 2016

It is possible to write efficient Ruby code

Page 74: Ruby Performance - The Last Mile - RubyConf India 2016

But it's very easy to write inefficient Ruby code

Page 75: Ruby Performance - The Last Mile - RubyConf India 2016

Great Features, Hidden Costs• Blocks are expensive to create, slower than method calls

• case/when is an O(n) cascade of calls

• Singleton classes/methods are costly and hurt method cache

• Literal arrays, hashes, strings have to be constructed, GCed

• Flow-control exceptions can be very expensive and hard to find

Page 76: Ruby Performance - The Last Mile - RubyConf India 2016

What happens if your code does not run fast enough?

Page 77: Ruby Performance - The Last Mile - RubyConf India 2016

You need to know your app

Page 78: Ruby Performance - The Last Mile - RubyConf India 2016

You need good tools

Page 79: Ruby Performance - The Last Mile - RubyConf India 2016

And the JVM has great tools

Page 80: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby Tooling

• Basic GC stats built in

• Simple profilers in standard library

• Some third-party tools

• stackprof, ruby-prof, perftools.rb, ...

Page 81: Ruby Performance - The Last Mile - RubyConf India 2016

JVM tooling is JRuby tooling

Page 82: Ruby Performance - The Last Mile - RubyConf India 2016

JVM Tooling

• Wide range of GCs: parallel, concurrent, realtime, pauseless

• Built-in tools for analyzing GC, JIT, thread, IO, heap

• Built-in remote monitoring via JMX

• Dozens of tools out there for profiling, management, and more

Page 83: Ruby Performance - The Last Mile - RubyConf India 2016

VisualVM• Graphical console into your application

• Monitor GC, threads, CPU usage

• Sampled or full profiling with GUI browser

• Live memory dumping, heap inspection

• Ships with every OpenJDK install

Page 84: Ruby Performance - The Last Mile - RubyConf India 2016
Page 85: Ruby Performance - The Last Mile - RubyConf India 2016
Page 86: Ruby Performance - The Last Mile - RubyConf India 2016

Java Mission Control

• Extremely low-overhead application recording

• Analyze results offline in JMC

• GC, CPU, heap events, IO operation all browsable

• Commercial feature, free for development use

Page 87: Ruby Performance - The Last Mile - RubyConf India 2016
Page 88: Ruby Performance - The Last Mile - RubyConf India 2016
Page 89: Ruby Performance - The Last Mile - RubyConf India 2016
Page 90: Ruby Performance - The Last Mile - RubyConf India 2016

More on GC

• JVM GCs are incredibly tunable with sensible defaults

• Tools like http://gceasy.io and JClarity give you a deeper view

• These are the best GCs and the best tools in the world

Page 91: Ruby Performance - The Last Mile - RubyConf India 2016

Finding Bottlenecks

Page 92: Ruby Performance - The Last Mile - RubyConf India 2016

Profiling

Page 93: Ruby Performance - The Last Mile - RubyConf India 2016

Profiling Tools

• Command line options: --profile, --sample

• JVM command-line profilers like prof

• Many graphical sampling/complete profiling options

• Flame graphs, stack profilers, you name it!

Page 94: Ruby Performance - The Last Mile - RubyConf India 2016
Page 95: Ruby Performance - The Last Mile - RubyConf India 2016
Page 96: Ruby Performance - The Last Mile - RubyConf India 2016
Page 97: Ruby Performance - The Last Mile - RubyConf India 2016

...and this is just the beginning

Page 98: Ruby Performance - The Last Mile - RubyConf India 2016

Wrapping Up

Page 99: Ruby Performance - The Last Mile - RubyConf India 2016

Ruby is alive and well

Page 100: Ruby Performance - The Last Mile - RubyConf India 2016

CRuby continues to improve

Page 101: Ruby Performance - The Last Mile - RubyConf India 2016

Ruby 3 is very exciting

Page 102: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby is performance today

Page 103: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby is concurrency today

Page 104: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby has tools today

Page 105: Ruby Performance - The Last Mile - RubyConf India 2016

JRuby makes you happier!

Page 106: Ruby Performance - The Last Mile - RubyConf India 2016

Thank You!Charles Oliver Nutter

[email protected] @headius

http://jruby.org https://github.com/jruby/jruby