0
Rubinius     Use Ruby
Dirkjan Bussink   d.bussink@gmail.com
2008
Dynamic  vs. Static
x = 10      x = aint x    = 10string x = a => ERROR
Strong  vs.Weak
x = 10y = "20"x + y# Javascript=> 1020# PHP=> 30
Ruby
puts "Hello world!"
class MyAwesomeObject  def initialize    puts "Running constructor"  end  def cool_method(arg1, arg2)    arg1 + arg2  endend
[1, 2, 3, 4].each do |e|  puts eend
module Person  def name    puts "Every person has name"  endendclass Student  include PersonendStudent.new.name
Rubinius
Virtual Machine
Kernel
2006Evan Phoenix Brian Ford
Virtual Machine
C++
Ruby
0000:   meta_push_0                    0001:   set_local           0    # i                    0003:   pop                ...
Fancyclass Person {  read_write_slots: [name, age, city]    def initialize: @name age: @age city: @city {    }    def go_t...
JavaScript
JavaScriptPython
JavaScriptPythonBrainfuck
Ruby in Ruby
def each  return to_enum(:each) unless block_given? i = @start total = i + @total tuple = @tuple  while i < total    yield...
Ruby for Rubyists
Improveeverything
Compiler
class FixnumLiteral < NumberLiteral  def initialize(line, value)    @line = line    @value = value  end  def bytecode(g)  ...
Ruby is slow!
Flexibility
class Array  def sum    inject(0) {|total, e| total + e.to_i}  endend
class Bignum  def +(other)    self - other  endend
"The edges of the sword are life and death,      no one knows which is which"      Ikkyu Sojun, 15th Century Zen master
Hard, but not impossible
Inline caching
p = Person.new...p.name
class Person  def name    "me"  endend
module Named                 def nameclass Person                   "named"  def name                 end    "me"         ...
module Named                 def name        class Personclass Person                   "named"       end  def name       ...
class Person  attr_accessor :nameend10000.times do  p = Person.new  p.nameend
There are only two hardproblems in Computer Science:       cache invalidation,         naming things     and off-by-one er...
module Naming  def name    "me2"  endendclass Person  include Namingend10000.times do  p = Person.new  p.nameend
module Naming  def name    "me2"          class Person  end                def nameend                    "new_name"      ...
p = OtherObject.new...p.name
JIT
“...we finally managed to get our Linux (...) builds to use  GCC 4.5, ... and profile guided optimization enabled”          ...
def method1  1 + 1enddef method2  2 + 1end10000.times do  method1end
members of rubinius::VMMethod:total_args = 0,call_count = 21,llvm_function_ = 0x0,name_ = 0x6306,
static const int default_jit_call_til_compile = 4000;
pushl %ebpmovl %esp, %ebpsubl $4, %espmovl $10, -4(%ebp)leal -4(%ebp), %eaxaddl $66, (%eax)leaveret
#include <stdio.h>int func() {    int i = 0;    i += 10;    return i;}
; ModuleID = <stdin>target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:...
; ModuleID = <stdin>target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:...
Go JIT!  RBX                      LLVMthread(s)                 thread            Here it is!
members of rubinius::VMMethod:total_args = 0,call_count = 21,llvm_function_ = 0x102c07b30,name_ = 0x6306,
Code inlining
array = [1] * 1000000array.each do |element|  puts "element: #{element}"end
def method1  1 + 1enddef method2  method1end100.times do  method2end
def method1    def method1  1 + 1          1 + 1end            enddef method2    def method2  method1        method1end   ...
def method1    def method1  1 + 1          1 + 1end            enddef method2    def method2  method1        method1end   ...
def method1    def method1    def method1  1 + 1          1 + 1          1 + 1end            end            enddef method2...
def method1    def method1    def method1  1 + 1          1 + 1          1 + 1end            end            enddef method2...
def awesome(x)  return 0 if x == 0  x + 1enddef   use_awesomeness_regular  a   = awesome(0)  b   = awesome(1)  a   + bend
def use_awesomeness_inlined  a = begin    return 0 if 0 == 0    0 + 1  end  b = begin    return 1 if 1 == 0    1 + 1  end ...
array = [1] * 1000000array.each do |element|  puts "element: #{element}"end
array = [1] * 1000000array = [1] * 1000000                               i = 0                               size = array....
array = [1] * 1000000array = [1] * 1000000                                    i = 0array.each do |element|  puts "element:...
array = [1] * 100array.each do |element|  puts "element: #{element}"  b = 2endputs b
array = [1] * 100array = [1] * 100                               i = 0                               size = array.sizearra...
array = [1] * 100array = [1] * 100                                    i = 0                                    size = arra...
Control flow issues
Control flow issuesScoping issues
Control flow issuesScoping issuesToo big piece of code
GarbageCollection
MarkSweep
Generational Garbage Collection
YoungMatureLarge
YoungSemi Space collector
Mature Immix
LargeMark - sweep
Creating less  garbage
class Address  attr_reader :street  attr_reader :number  attr_reader :cityend
class Address             attr_reader :street             attr_reader :number             attr_reader :city           endA...
a          =   Address.new   a.street   =   "Street"   a.number   =   "1"   a.city     =   "Enschede"Rubinius.memory_size(...
What else?
http://rubini.us/https://github.com/evanphx/rubinius
1 patch == commit access
Questions?
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Lecture on Rubinius for Compiler Construction at University of Twente
Upcoming SlideShare
Loading in...5
×

Lecture on Rubinius for Compiler Construction at University of Twente

1,914

Published on

Slides for the guest lecture at the Compiler Construction (Vertalerbouw) course at the University of Twente.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,914
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • Regular contributor since the early beginnings of 2008\n
  • First I want to explain two concepts\nThe first concept is about dynamic versus static languages.\n\n- Dynamic languages\nTypes checking is done at runtime\n- Static languages\nTypes are checked during compile time\n\n \n
  • The first is what happens in a dynamic language. Types are not fixed and you can use different types if you want\nThe second is a static language. Once a certain type is defined, the type can&amp;#x2019;t be changed. \n
  • Another difference is how types are enforced.\nThis is often confused with static and dynamic languages, seeing the dynamic language as weakly typed. This however is often not true.\n\n-Strong typing\nThis enforces specific rules and behavior on what happens when you run certain operations on differently typed objects\n-Weak typing\nImplicit type conversion when different types are used\n\n
  • \n
  • So what is Ruby?\n\nRuby is a dynamically strongly typed language. So you don&amp;#x2019;t specify types when writing ruby code, but during runtime it&amp;#x2019;s types are not just changed automatically.\n\nIt has primarily been influenced by Perl, Smalltalk and Lisp. The primary design philosophy is that a language should be productive and fun to use. \n
  • So how does it look?\nThe classic Hello world! example\n
  • This is how basic class definition and method definition look like\n
  • Block syntax. They are lambda like constructs. It&amp;#x2019;s like passing a piece of code as a special argument to a method. \n
  • Modules. They allow for code being mixed into other classes. It&amp;#x2019;s a bit like multiple inheritance. This is made possible because of the dynamic nature of Ruby\n
  • Rubinius includes everything needed to run Ruby code\n
  • That means it includes a bytecode Virtual Machine, primarily designed for running Ruby code.\n
  • But it also includes all core classes etc. you expect in Ruby, like String, Hash and Array. In other languages t&amp;#x2019;s often called the standard library, but that has a different meaning in Ruby, so hence this name. \n
  • It was started in 2006, thought up by Evan Phoenix during his honeymoon. He and Brian Ford are payed full time to work on Rubinius.\n
  • So what does the virtual machine entail? \n
  • The first and initial version was written in Ruby. After this proof of concept, a first version of the virtual machine was written C. In 2008 the choice was made to rewrite it in C++, because that is a better fit with the architecture of the VM. \n
  • The bytecode instruction set includes the necessary instructions for running Ruby code efficiently. This doesn&amp;#x2019;t mean other languages can&amp;#x2019;t be written on top of Rubinius.\n
  • So what does the bytecode look like?\nThe comments at the end show how the variable names are mapped to slots\n
  • One example is Fancy. It has a few different aspect compare to ruby, like named parameters\n
  • There&amp;#x2019;s a bunch of other languages people created, mostly as an experiment and not very mature\n
  • There&amp;#x2019;s a bunch of other languages people created, mostly as an experiment and not very mature\n
  • There&amp;#x2019;s a bunch of other languages people created, mostly as an experiment and not very mature\n
  • So how do we make it fast? There&amp;#x2019;s quite a few techniques for that which will be discussed later in the lecture\n
  • The kernel code is written in Ruby as much as possible. This means that classes like String, Hash and Array are written in Ruby itself\n
  • This is how Array#each looks like. It uses a Tuple, which is a fixed size array like structure that Array is built upon. Hash is written in Ruby too\n
  • Having more in Ruby also means that it&amp;#x2019;s easier for people to help out with. You don&amp;#x2019;t need to know C / C++ in order to contribute to Rubinius\n
  • \n
  • \n
  • It parses into an AST and then outputs bytecode by walking the AST. Each node knows how to emit bytecode, such as this example for Fixnum literals. It stores the line number and the given value for the literal.\n
  • People often claim that Ruby, or dynamic languages in general are slow. \n
  • \n
  • Add a method useful for you on a core type. Not always the best solution, but it&amp;#x2019;s a very flexible way to handle things. \n
  • You can also do very nasty things.\n
  • \n
  • \n
  • So in order to improve performance of a dynamic language, there are various techniques. One of the most basic ones that gives an easy improvement is inline caching.\n
  • So we have this little piece of code. First, we create a Person, then we do some other stuff and then we call the method name on it. p.name here is know as a call site.\n
  • So where can this method be?\n- There&amp;#x2019;s the simple case of it being a method defined for all instances of the class\n-It can also be in a module included into the class\n-Another option is defining a method on the metaclass of the object. This means it&amp;#x2019;s only available for this specific instance of the Person.\n
  • So where can this method be?\n- There&amp;#x2019;s the simple case of it being a method defined for all instances of the class\n-It can also be in a module included into the class\n-Another option is defining a method on the metaclass of the object. This means it&amp;#x2019;s only available for this specific instance of the Person.\n
  • So where can this method be?\n- There&amp;#x2019;s the simple case of it being a method defined for all instances of the class\n-It can also be in a module included into the class\n-Another option is defining a method on the metaclass of the object. This means it&amp;#x2019;s only available for this specific instance of the Person.\n
  • So consider this extended example with complete code. If you look at the code, you see that when running this, p.name ends up in the same method every time you execute the code. So even though Ruby is very dynamic, most of the code looks like it&amp;#x2019;s static anyway. \n\nSo the expensive computation can perhaps be stored and reused so it&amp;#x2019;s not needed each time. The caching of this method dispatch result is called inline caching.\n
  • \n
  • So, here we need to be sure to invalidate our cache, otherwise it would run the wrong method\n
  • So, here we need to be sure to invalidate our cache, otherwise it would run the wrong method\n
  • So, now the question is, is this lookup changed too? The problem is that we want to keep the caches simple. So there&amp;#x2019;s a cache entry at each call site that stores for a specific type, the method it dispatched to and module that method is defined. This makes the cache entries small so there&amp;#x2019;s isn&amp;#x2019;t a lot of memory overhead.\n\n\nSo we don&amp;#x2019;t want to store the complete chain. Which means that we only have OtherObject as a type stored here. It also means that we need to invalidate the cache because we don&amp;#x2019;t know whether OtherObject includes Naming or not. \n\nTherefore invalidating caches is a brute force measure that removes all caches with the same name, so in this case &amp;#x201C;name&amp;#x201D;.\n
  • Just In Time compilation means that code is compiled to native code during execution of your programs. \n
  • This quote shows that using runtime information, you can optimize code a lot better than just only ahead of time. \n\nSo we need to track this runtime information so we know what we can compile into native code. \n
  • So here we have a bunch of code that is executed quite often. We don&amp;#x2019;t know ahead of time that we don&amp;#x2019;t actually need the method2 method, but we do during runtime. So we can use this information at runtime.\n
  • Each VMMethod object keeps track of various things\nYou can see how often a method is called\nThe llvm_function_ pointer points at jitted code for this method\nThere&amp;#x2019;s a name for the method of course\nAnd a whole bunch of other stuff removed here\n
  • So right now, a method is going to be compiled after it has been executed 4000 times. \n
  • The initial version used hand crafted assembly to output the code for it. This was cumbersome and would need a lot of work to optimize it to a decently performing level. \n
  • That&amp;#x2019;s why the LLVM compiler infrastructure was chosen. It already did a huge amount of legwork in generating good native code for various platforms. \n
  • \n
  • This is what the LLVM bytecode looks like without any optimizations. This is actually kind of like how with Rubinius code is translated. There is a C++ API for creating this bytecode. \n
  • This is what the LLVM optimizer makes out of it. It can reason about so in the end the value 10 can be returned directly. LLVM can run similar passes over code generated through the C++ API. \n
  • So how is this implemented? The code compilation actually happens in a background thread. The virtual machine requests that a certain method is jitted, which is then given to the LLVM thread. The LLVM thread then goes to work and creates the LLVM bytecode. After this is compiled, it sets the llvm_function_ pointer seen earlier. \n\nThis means that the VM just runs along nicely without being interrupted by the compilation of code. \n
  • \n
  • No overhead is faster than no overhead. We already saw that inline caches can greatly improve method dispatching, but there&amp;#x2019;s certainly room for even more optimizations. One of these is code inlining, which means that method dispatch overhead is completely removed. \n\n\n
  • Ruby has another place that can benefit greatly from code inline, which is the usage of blocks. A block is a construct which has it&amp;#x2019;s own scope and can also be captured explicitly. This means that it does add overhead and looking at removing that overhead is very interesting. \n
  • So we start here with a simple piece of code. What inlining does, is moving the actual code of the method into the method that the method is called from. So this means that instead of dispatching a method, it executes the code of that method directly. \n
  • So we start here with a simple piece of code. What inlining does, is moving the actual code of the method into the method that the method is called from. So this means that instead of dispatching a method, it executes the code of that method directly. \n
  • So we start here with a simple piece of code. What inlining does, is moving the actual code of the method into the method that the method is called from. So this means that instead of dispatching a method, it executes the code of that method directly. \n
  • So we start here with a simple piece of code. What inlining does, is moving the actual code of the method into the method that the method is called from. So this means that instead of dispatching a method, it executes the code of that method directly. \n
  • So we start here with a simple piece of code. What inlining does, is moving the actual code of the method into the method that the method is called from. So this means that instead of dispatching a method, it executes the code of that method directly. \n
  • So inline has some great potential, but there are quite a few caveats. \n
  • We take a look at this example. Here is the same method called with a different parameter, which we could perhaps inline. So we take a naive attempt in the next slide.\n
  • Here we manually inlined the two calls to awesome() and injected the code in this place. The begin / end block is used so we have the correct scope of the inlined code.\n\nBut if we look at this, this code behaves differently! Let me show this by running it. What you can see here is that the control flow is different because of the return. While the return first meant that it would return from the method, with the inlining this method is no longer present. So when inlining, control flow is something that needs considering. \n
  • This is a very simple example of how block code inlining should work. The left version is a much prettier and nicer version and that is how Ruby code should look.\n\nThe example on the right is equivalent, but it has the block used in the version on the left removed. This is what you can call block inlining in Rubinius. \n
  • This is a very simple example of how block code inlining should work. The left version is a much prettier and nicer version and that is how Ruby code should look.\n\nThe example on the right is equivalent, but it has the block used in the version on the left removed. This is what you can call block inlining in Rubinius. \n
  • This is a very simple example of how block code inlining should work. The left version is a much prettier and nicer version and that is how Ruby code should look.\n\nThe example on the right is equivalent, but it has the block used in the version on the left removed. This is what you can call block inlining in Rubinius. \n
  • But beware with scoping issues. Who thinks he knows what happens here?\n
  • But beware with scoping issues. Who thinks he knows what happens here?\n
  • But beware with scoping issues. Who thinks he knows what happens here?\n
  • So there are few reasons why code isn&amp;#x2019;t inlined. These properties can be determined by analyzing the bytecode for a method. If these issues come forth from it, the code isn&amp;#x2019;t inlined. What can be inlined is something that is improved over time. More code can be written to support more complex structures for inlining. \n
  • So there are few reasons why code isn&amp;#x2019;t inlined. These properties can be determined by analyzing the bytecode for a method. If these issues come forth from it, the code isn&amp;#x2019;t inlined. What can be inlined is something that is improved over time. More code can be written to support more complex structures for inlining. \n
  • So there are few reasons why code isn&amp;#x2019;t inlined. These properties can be determined by analyzing the bytecode for a method. If these issues come forth from it, the code isn&amp;#x2019;t inlined. What can be inlined is something that is improved over time. More code can be written to support more complex structures for inlining. \n
  • \n
  • People are really happy that others clean up their garbage. No need to worry about it anymore. Using automatic memory management has various advantages, such as not having to worry about object ownership, double free bugs and possible memory leaks. \n\nRuby also uses automatic memory management and needs garbage collection.\n
  • A simple naive way of doing garbage collection is to start at the root of the object graph and go from there. Going through each object, marking the objects as you go along. After this marking phase, you go through all objects again. Everything that doesn&amp;#x2019;t have a mark set, is freed as it is apparently not reachable anymore. \n
  • So how can we make this faster? We can look at the properties of different objects. Young objects are often only around for a very short time. So we want to have a mechanism to suit this properly. \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Immix uses different block of memory. It allocates objects in a block, so it has contiguous allocation for objects. This means it doesn&amp;#x2019;t need a free list for allocation. On the other hand, this technique can limit memory fragmentation.\n
  • Immix uses different block of memory. It allocates objects in a block, so it has contiguous allocation for objects. This means it doesn&amp;#x2019;t need a free list for allocation. On the other hand, this technique can limit memory fragmentation.\n
  • Immix uses different block of memory. It allocates objects in a block, so it has contiguous allocation for objects. This means it doesn&amp;#x2019;t need a free list for allocation. On the other hand, this technique can limit memory fragmentation.\n
  • Very large objects are directly allocated in a special area. This is because you don&amp;#x2019;t want to copy them, since copying is an expensive operation and they also don&amp;#x2019;t fit in the immix blocks. \n\nThis special area doesn&amp;#x2019;t copy objects, but just uses a very simple mark and sweep algorithm.\n
  • \n
  • This is kind of how an object looks like in memory. By default there&amp;#x2019;s an instance variable table, because you can add and remove instance variables on the fly in Ruby. There&amp;#x2019;s no definitive way to know which instance variable we need up front.\n\nBut we can make a very nice educated guess on how it would look like. We use the compiler to track all the variables we see. So if we compile the class given here, we can track all instance variables we encounter. \n
  • Here we see the effect on memory usage. With the instance variable table, it uses 160 bytes for each object of type Address, but with the packing it only uses 56 bytes!\n
  • \n
  • So if you want to know more, please look it up here. You can also of course ask me additional questions. \n
  • If you think it&amp;#x2019;s interesting and want to contribute, just one patch accepted means commit access. \n
  • \n
  • Transcript of "Lecture on Rubinius for Compiler Construction at University of Twente"

    1. 1. Rubinius Use Ruby
    2. 2. Dirkjan Bussink d.bussink@gmail.com
    3. 3. 2008
    4. 4. Dynamic vs. Static
    5. 5. x = 10 x = aint x = 10string x = a => ERROR
    6. 6. Strong vs.Weak
    7. 7. x = 10y = "20"x + y# Javascript=> 1020# PHP=> 30
    8. 8. Ruby
    9. 9. puts "Hello world!"
    10. 10. class MyAwesomeObject def initialize puts "Running constructor" end def cool_method(arg1, arg2) arg1 + arg2 endend
    11. 11. [1, 2, 3, 4].each do |e| puts eend
    12. 12. module Person def name puts "Every person has name" endendclass Student include PersonendStudent.new.name
    13. 13. Rubinius
    14. 14. Virtual Machine
    15. 15. Kernel
    16. 16. 2006Evan Phoenix Brian Ford
    17. 17. Virtual Machine
    18. 18. C++
    19. 19. Ruby
    20. 20. 0000: meta_push_0 0001: set_local 0 # i 0003: pop 0004: push_local 0 # i 0006: push_literal 1000 0008: meta_send_op_lt :< 0010: goto_if_false 23i = 0 0012: push_local 0 # iwhile i < 1000 do 0014: meta_push_1 i = i + 1 0015: meta_send_op_plus :+ 0017: set_local 0 # iend 0019: pop 0020: check_interrupts 0021: goto 4 0023: push_nil 0024: pop 0025: push_true 0026: ret
    21. 21. Fancyclass Person { read_write_slots: [name, age, city] def initialize: @name age: @age city: @city { } def go_to: city { if: (city is_a?: City) then: { @city = city } } def to_s { "Person: #{@name}, #{@age} years old, living in #{@city}" }}
    22. 22. JavaScript
    23. 23. JavaScriptPython
    24. 24. JavaScriptPythonBrainfuck
    25. 25. Ruby in Ruby
    26. 26. def each return to_enum(:each) unless block_given? i = @start total = i + @total tuple = @tuple while i < total yield tuple.at(i) i += 1 end selfend
    27. 27. Ruby for Rubyists
    28. 28. Improveeverything
    29. 29. Compiler
    30. 30. class FixnumLiteral < NumberLiteral def initialize(line, value) @line = line @value = value end def bytecode(g) pos(g) g.push @value end def defined(g) g.push_literal "expression" endend
    31. 31. Ruby is slow!
    32. 32. Flexibility
    33. 33. class Array def sum inject(0) {|total, e| total + e.to_i} endend
    34. 34. class Bignum def +(other) self - other endend
    35. 35. "The edges of the sword are life and death, no one knows which is which" Ikkyu Sojun, 15th Century Zen master
    36. 36. Hard, but not impossible
    37. 37. Inline caching
    38. 38. p = Person.new...p.name
    39. 39. class Person def name "me" endend
    40. 40. module Named def nameclass Person "named" def name end "me" end end class Personend include Named end
    41. 41. module Named def name class Personclass Person "named" end def name end "me" end def p.name end class Person "specific"end include Named end end
    42. 42. class Person attr_accessor :nameend10000.times do p = Person.new p.nameend
    43. 43. There are only two hardproblems in Computer Science: cache invalidation, naming things and off-by-one errors
    44. 44. module Naming def name "me2" endendclass Person include Namingend10000.times do p = Person.new p.nameend
    45. 45. module Naming def name "me2" class Person end def nameend "new_name" endclass Person end include Namingend 10000.times do p = Person.new10000.times do p.name p = Person.new end p.nameend
    46. 46. p = OtherObject.new...p.name
    47. 47. JIT
    48. 48. “...we finally managed to get our Linux (...) builds to use GCC 4.5, ... and profile guided optimization enabled” Mike Hommey - on Firefox 6 performance
    49. 49. def method1 1 + 1enddef method2 2 + 1end10000.times do method1end
    50. 50. members of rubinius::VMMethod:total_args = 0,call_count = 21,llvm_function_ = 0x0,name_ = 0x6306,
    51. 51. static const int default_jit_call_til_compile = 4000;
    52. 52. pushl %ebpmovl %esp, %ebpsubl $4, %espmovl $10, -4(%ebp)leal -4(%ebp), %eaxaddl $66, (%eax)leaveret
    53. 53. #include <stdio.h>int func() { int i = 0; i += 10; return i;}
    54. 54. ; ModuleID = <stdin>target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"target triple = "x86_64-apple-darwin10.7"define i32 @func() nounwind ssp {entry: %retval = alloca i32 %0 = alloca i32 %i = alloca i32 %"alloca point" = bitcast i32 0 to i32 store i32 0, i32* %i, align 4 %1 = load i32* %i, align 4 %2 = add nsw i32 %1, 10 store i32 %2, i32* %i, align 4 %3 = load i32* %i, align 4 store i32 %3, i32* %0, align 4 %4 = load i32* %0, align 4 store i32 %4, i32* %retval, align 4 br label %returnreturn: ; preds =%entry %retval1 = load i32* %retval ret i32 %retval1}
    55. 55. ; ModuleID = <stdin>target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"target triple = "x86_64-apple-darwin10.7"define i32 @func() nounwind readnone ssp {entry: ret i32 10}
    56. 56. Go JIT! RBX LLVMthread(s) thread Here it is!
    57. 57. members of rubinius::VMMethod:total_args = 0,call_count = 21,llvm_function_ = 0x102c07b30,name_ = 0x6306,
    58. 58. Code inlining
    59. 59. array = [1] * 1000000array.each do |element| puts "element: #{element}"end
    60. 60. def method1 1 + 1enddef method2 method1end100.times do method2end
    61. 61. def method1 def method1 1 + 1 1 + 1end enddef method2 def method2 method1 method1end end100.times do 100.times do method2 method1end end
    62. 62. def method1 def method1 1 + 1 1 + 1end enddef method2 def method2 method1 method1end end100.times do 100.times do method2 method1end end
    63. 63. def method1 def method1 def method1 1 + 1 1 + 1 1 + 1end end enddef method2 def method2 def method2 method1 method1 method1end end end100.times do 100.times do 100.times do method2 method1 1 + 1end end end
    64. 64. def method1 def method1 def method1 1 + 1 1 + 1 1 + 1end end enddef method2 def method2 def method2 method1 method1 method1end end end100.times do 100.times do 100.times do method2 method1 1 + 1end end end
    65. 65. def awesome(x) return 0 if x == 0 x + 1enddef use_awesomeness_regular a = awesome(0) b = awesome(1) a + bend
    66. 66. def use_awesomeness_inlined a = begin return 0 if 0 == 0 0 + 1 end b = begin return 1 if 1 == 0 1 + 1 end a + bend
    67. 67. array = [1] * 1000000array.each do |element| puts "element: #{element}"end
    68. 68. array = [1] * 1000000array = [1] * 1000000 i = 0 size = array.sizearray.each do |element| while i < size puts "element: #{element}" puts "element: #{array[i]}"end i += 1 end
    69. 69. array = [1] * 1000000array = [1] * 1000000 i = 0array.each do |element| puts "element: #{element}" == size = array.size while i < size puts "element: #{array[i]}"end i += 1 end
    70. 70. array = [1] * 100array.each do |element| puts "element: #{element}" b = 2endputs b
    71. 71. array = [1] * 100array = [1] * 100 i = 0 size = array.sizearray.each do |element| while i < size puts "element: #{element}" puts "element: #{array[i]}" b = 2 b = 2end i += 1 endputs b puts b
    72. 72. array = [1] * 100array = [1] * 100 i = 0 size = array.sizearray.each do |element| while i < size puts "element: #{element}" b = 2 != puts "element: #{array[i]}" b = 2end i += 1 endputs b puts b
    73. 73. Control flow issues
    74. 74. Control flow issuesScoping issues
    75. 75. Control flow issuesScoping issuesToo big piece of code
    76. 76. GarbageCollection
    77. 77. MarkSweep
    78. 78. Generational Garbage Collection
    79. 79. YoungMatureLarge
    80. 80. YoungSemi Space collector
    81. 81. Mature Immix
    82. 82. LargeMark - sweep
    83. 83. Creating less garbage
    84. 84. class Address attr_reader :street attr_reader :number attr_reader :cityend
    85. 85. class Address attr_reader :street attr_reader :number attr_reader :city endAddress.instance_variable_get("@seen_ivars")=> [:@street, :@number, :@city]
    86. 86. a = Address.new a.street = "Street" a.number = "1" a.city = "Enschede"Rubinius.memory_size(a) => 56 VSRubinius.memory_size(a) => 160
    87. 87. What else?
    88. 88. http://rubini.us/https://github.com/evanphx/rubinius
    89. 89. 1 patch == commit access
    90. 90. Questions?
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×