Sunday, February 13, 2011

REE garbage collector performance tuning


Ruby’s garbage collector tries to adapt memory usage to the amount of memory used by the program by dynamically growing or shrinking the allocated heap as it sees fit. For long running server applications, this approach isn’t always the most efficient one. The performance very much depends on the ratio heap_size / program_size. It behaves somewhat erratic: adding code can actually make your program run faster.
With REE, one can tune the garbage collector’s behavior for better server performance. It is possible to specify the initial heap size to start with. The heap size will never drop below the initial size. By carefully selecting the initial heap size one can decrease startup time and increase throughput of server applications.
Garbage collector behavior is controlled through the following environment variables. These environment variables must be set prior to invoking the Ruby interpreter.
  • RUBY_HEAP_MIN_SLOTS
    This specifies the initial number of heap slots. The default is 10000.
  • RUBY_HEAP_SLOTS_INCREMENT
    The number of additional heap slots to allocate when Ruby needs to allocate new heap slots for the first time. The default is 10000.
    For example, suppose that the default GC settings are in effect, and 10000 Ruby objects exist on the heap (= 10000 used heap slots). When the program creates another object, Ruby will allocate a new heap with 10000 heap slots in it. There are now 20000 heap slots in total, of which 10001 are used and 9999 are unused.
  • RUBY_HEAP_SLOTS_GROWTH_FACTOR
    Multiplicator used for calculating the number of new heaps slots to allocate next time Ruby needs new heap slots. The default is 1.8.
    Take the program in the last example. Suppose that the program creates 10000 more objects. Upon creating the 10000th object, Ruby needs to allocate another heap. This heap will have 10000 * 1.8 = 18000 heap slots. There are now 20000 + 18000 = 38000 heap slots in total, of which 20001 are used and 17999 are unused.
    The next time Ruby needs to allocate a new heap, that heap will have 18000 * 1.8 = 32400 heap slots.
  • RUBY_GC_MALLOC_LIMIT
    The amount of C data structures which can be allocated without triggering a garbage collection. If this is set too low, then the garbage collector will be started even if there are empty heap slots available. The default value is 8000000.
  • RUBY_HEAP_FREE_MIN
    The number of heap slots that should be available after a garbage collector run. If fewer heap slots are available, then Ruby will allocate a new heap according to the RUBY_HEAP_SLOTS_INCREMENT and RUBY_HEAP_SLOTS_GROWTH_FACTOR parameters. The default value is 4096.

GC configuration With respect to my portal

As mentioned into coffeepowdered.net(reference link), we have used scrap plugin.
It's given following statistic
Number of objects : 2181349 (1735589 AST nodes, 79.56%)
Heap slot size : 40
GC cycles so far : 415
Number of heaps : 9
Total size of objects: 85208.95 KB
Total size of heaps : 119579.90 KB (34370.95 KB = 28.74% unused)
Leading free slots : 389261 (15205.51 KB = 12.72%)
Trailing free slots : 2 (0.08 KB = 0.00%)
Number of contiguous groups of 16 slots: 38143 (19.94%)
Number of terminal objects: 6617 (0.22%)
As, you see in the statistic, we required 9 heaps slot to feet 2181349 objects. To reduce this to feet into single heap we have added following configuration.
1. Created a file with any name. e.g
sudo vi /opt/ruby-enterprise-1.8.7-2010.02/bin/ruby_with_env
2. Added following line in it
#!/bin/bash
export RUBY_HEAP_MIN_SLOTS=2500000
export RUBY_HEAP_SLOTS_INCREMENT=200000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_GC_MALLOC_LIMIT=40000000
export RUBY_HEAP_FREE_MIN=25000
exec "/opt/ruby-enterprise-1.8.7-2010.02/bin/ruby" "$@" 
3. Given execute permission to it
sudo chmod +x /opt/ruby-enterprise-1.8.7-2010.02/bin/ruby_with_env
4. As we using passenger, so we have modified nginx.conf to use above configuration,
passenger_ruby /opt/ruby-enterprise-1.8.7-2010.02/bin/ruby;
with
passenger_ruby /opt/ruby-enterprise-1.8.7-2010.02/bin/ruby_with_env;
After doing this configuration, we got following statistic,
Number of objects : 2093655 (1698545 AST nodes, 81.13%)
Heap slot size : 40
GC cycles so far : 14
Number of heaps : 1
Total size of objects: 81783.40 KB
Total size of heaps : 97656.29 KB (15872.89 KB = 16.25% unused)
Leading free slots : 406346 (15872.89 KB = 16.25%)
Trailing free slots : 0 (0.00 KB = 0.00%)
Number of contiguous groups of 16 slots: 25396 (16.25%)
Number of terminal objects: 6993 (0.28%)
As you can see two important variables are come down drastically.
GC cycles so far : 14
Number of heaps : 1



Reference

http://www.coffeepowered.net/2009/06/13/fine-tuning-your-garbage-collector
http://www.mikeperham.com/2009/05/25/memory-hungry-ruby-daemons/


No comments:

Post a Comment