10. Many Options
• Ruby 2.0
• Significant execution improvements
• JRuby
• Leveraging JVM more and more
• Rubinius
• OptimizingVM built for Ruby
Monday, July 1, 13
11. 0
7.5
15
22.5
30
Java 1.4 Java 5 Java 6 Java 7
Go Java Go!
JRuby 1.0.3 (bm_red_black_tree.rb)
300% for free
Monday, July 1, 13
26. Dynamic Optimization
• Target method/value discovered at runtime
• Lookup is expensive
• We can cache it
• Cache has to be validated
• Indirection hurts pipeline
• Inline methods/values at access point
Monday, July 1, 13
29. VM Operations
Method Lookup
Method Caching
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
30. VM Operations
Method Lookup
Method Caching
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
31. VM Operations
Method Lookup
Branch
Method Caching
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
32. VM Operations
Method Lookup
Branch
Method Cache
Method Caching
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
44. It's a multi-core world
• Scaling today is horizontal, not vertical
• N processes does not cut it
• N users * X MB process = $$$
• CoW is only a partial band-aid
• Non-parallel impls are falling behind
• JRuby, Rubinius your only real options
Monday, July 1, 13
57. Doing It Right
• Lock-free persistent data structures
• hamster et al
• Thread-safety utilities
• Mutex, Queue, thread_safe + atomic gems
• Threaded servers
• puma, trinidad, torquebox, JVM servers
Monday, July 1, 13
58. Finding Problems
• JRuby
• VM flags (heap/thread dumps, debug)
• Some of the best tools in the world
• Rubinius
• gdb, OS-level tools
• #rubinius
Monday, July 1, 13
60. • eval
• Exceptions as flow control
• Excessive allocation
• Defeating optimizations
• IO, DB, bad libraries
• VM flaw*
Usual Suspects
*I usually assume it's JRuby's fault until proven otherwise
Monday, July 1, 13
61. eval
• Code never stays the same
• VM can't cache, can't see patterns
• No optimization is possible*
*Specific cases can sometimes be cached and optimized
Monday, July 1, 13
62. Fixing eval
• Evaluate code into a method and leave it
• Methods are stable, optimizable
• Pass dynamic state, rather than interpolate
• Branches are cheaper than new code
• Do all evaluation up front
• ...not during your app's hot path
Monday, July 1, 13
63. Exceptions
• Act like a special return value
• Construct object with information
• Capture call stack at raise point
• Unroll call stack until rescued
• Overhead ranges from big to huge
• Especially costly on optimizingVMs
Monday, July 1, 13
65. def foo(a); raise; rescue; return a + 1; end
Deep stack, 100k calls:
JRuby w/ exception: 200s
Ruby 2 w/ exception: 1.25s
Rubinius w/ exception: 7.7s
Monday, July 1, 13
66. Exception Alternatives
• Pre-allocated exception object
• Empty backtrace passed to raise()
• Special return value
• Check at each caller
• catch/throw
• Avoids most overhead
Monday, July 1, 13
67. Allocation
• Literals
• "foo" creates object every time
• String + String,Array + Array
• Creates intermediate objects
• += is especially wasteful
• Slicing and enumerating
• ary.map{}.select{}.inject{}.find = 3 arrays
Monday, July 1, 13
68. Fixing Literals
• Constants are your friends
• Optimizes well on most impls
• Avoids literal churn
• Cache common interpolated values
• Study memory profiles
Monday, July 1, 13
69. Fixing Concat/Copy
• Modify in place
• Thread-safety trade-offs...
• Use persistent structures
• "hamster" gem
• Google "immutable ruby"
Monday, July 1, 13
70. Fixing Enum Chaining
• Condense into fewer steps
• Lazy Enumerator in 2.0
• Just use a loop :-)
Monday, July 1, 13
71. Defeating Optimization
• Caching and inlining are key to perf
• If we can't cache...
• Methods won't inline, won't optimize
• Constants must be looked up every time
• We have less time for real work
Monday, July 1, 13
72. Method Cache Busting
• VM must ensure cache is correct
• Check type
• Ensure method table is the same
• New type every time? No caching.
• Modify method table? No caching.
Monday, July 1, 13
73. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
74. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
75. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
76. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
77. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
78. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
79. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
80. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
81. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
Call Site
method table
Monday, July 1, 13
82. VM Operations
Method Lookup
Branch
Method Cache
Dynamic Invocation
Target
Object
FooClass
def foo ...
def bar ...
associated with
obj.foo() VM
def foo ...
Call Site
method table
Monday, July 1, 13
83. Singletons
• Creates new types at runtime
• Impossible to cache based on type
• Usually defines new methods
• Method table is always different
class << foo ...
def foo.bar ...
Monday, July 1, 13
84. Object#extend
• Includes module into single object
• New one-off type every time
• Class hierarchy keeps changing
foo.extend Enumerable
Monday, July 1, 13
85. static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
{
...
n = rb_read_internal(fptr->fd, RSTRING_PTR(str), len);
rb_str_unlocktmp(str);
if (n < 0) {
if (!nonblock && rb_io_wait_readable(fptr->fd))
goto again;
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
rb_mod_sys_fail(rb_mWaitReadable, "read would block");
rb_sys_fail_path(fptr->pathv);
}
...
}
Monday, July 1, 13
86. static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
{
...
n = rb_read_internal(fptr->fd, RSTRING_PTR(str), len);
rb_str_unlocktmp(str);
if (n < 0) {
if (!nonblock && rb_io_wait_readable(fptr->fd))
goto again;
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
rb_mod_sys_fail(rb_mWaitReadable, "read would block");
rb_sys_fail_path(fptr->pathv);
}
...
}
Monday, July 1, 13
87. void
rb_mod_sys_fail(VALUE mod, const char *mesg)
{
VALUE exc = make_errno_exc(mesg);
rb_extend_object(exc, mod);
rb_exc_raise(exc);
}
Monday, July 1, 13
88. void
rb_mod_sys_fail(VALUE mod, const char *mesg)
{
VALUE exc = make_errno_exc(mesg);
rb_extend_object(exc, mod);
rb_exc_raise(exc);
}
Monday, July 1, 13
89. Fixing Singletons/
#extend
• Functional patterns
• FooLibrary.process(obj) rather than
obj.extend FooLibrary; obj.process
• Create types up front (programmatically?)
• 1000 predefined types beats infinite types
Monday, July 1, 13
92. Constant Lookup
• Constants in tables on classes/modules
• Usually assigned only once, at load time
• Lookup is expensive, like methods
• Values can be cached
Monday, July 1, 13
93. Constant Cache
• Constant search proceeds two ways
• First, lexical scoping
• Second, class hierarchy
• Invalidation happens globally
Monday, July 1, 13
94. Constant Cache Busting
• Redefining constants
• Introducing new lexical scopes
• Classes created at runtime
• Evaluated code
• Altering class hierarchies
• Lookup results may change...no caching
Monday, July 1, 13
95. Fixing Constants
• Don't modify them
• i.e. CONSTANT
• Avoid runtime class hierarchy changes
Monday, July 1, 13
97. Performance Issues
• Assume nothing...most can be fixed
• Isolate bad code, small a case as possible
• UseVM tools to monitor caches
• Fix if it's your bug, PR if it's a library
• Come to us for help or if it's aVM bug
• Repeat...
Monday, July 1, 13
98. Concurrency Issues
• Avoid mutable state
• Synchronize mutations
• Start coarse-grained, get finer over time
• VM tooling to monitor locks, contention
• ContactVM authors for help
Monday, July 1, 13