Профилирование и оптимизация производительности...

36
Ruby performance profiling Minsk, SaM Solutions, 2013 Presented by Alexey Tulia @AlexeyTulia, github.com/crible

description

Лекция посвящена профилированию Ruby-кода, анализу результатов работы профилировщика и использованию этих данных для оптимизации производительности.

Transcript of Профилирование и оптимизация производительности...

Page 1: Профилирование и оптимизация производительности Ruby-кода

Ruby performance profiling

Minsk, SaM Solutions, 2013

Presented by Alexey Tulia

@AlexeyTulia, github.com/crible

Page 2: Профилирование и оптимизация производительности Ruby-кода

Ruby. A programmer’s best friend

Page 3: Профилирование и оптимизация производительности Ruby-кода

Ruby implementations

Page 4: Профилирование и оптимизация производительности Ruby-кода
Page 5: Профилирование и оптимизация производительности Ruby-кода

Reasons?

Page 6: Профилирование и оптимизация производительности Ruby-кода

Garbage collection

Slow methods call

Page 7: Профилирование и оптимизация производительности Ruby-кода

one iteration takes ~ 100ms

Garbage collection

Need one Gb?

Expect 128 GC calls!

You lose 128*0,1 = 12,8 sec

Allocated memory never returns to the system!

runs on every 8Mb of allocated memory

Page 8: Профилирование и оптимизация производительности Ruby-кода

Garbage collection

More objects allocation -> more GC calls -> slow code

Page 9: Профилирование и оптимизация производительности Ruby-кода

RUBY_HEAP_MIN_SLOTS=8000000

RUBY_GC_MALLOC_LIMIT=10000

Garbage collection tuning

performance patches

Page 10: Профилирование и оптимизация производительности Ruby-кода

Ruby String performance

require 'benchmark'

ITERATIONS = 1000000

def run(str, bench) bench.report("#{str.length + 1} chars") do ITERATIONS.times do new_string = str + 'x' end endend

Benchmark.bm do |bench| run("12345678901234567890", bench) run("123456789012345678901", bench) run("1234567890123456789012", bench) run("12345678901234567890123", bench) run("123456789012345678901234", bench) run("1234567890123456789012345", bench) run("12345678901234567890123456", bench)end

user system total real21 chars 0.250000 0.000000 0.250000 ( 0.247459)22 chars 0.250000 0.000000 0.250000 ( 0.246954)23 chars 0.250000 0.000000 0.250000 ( 0.248440)24 chars 0.480000 0.000000 0.480000 ( 0.478391)25 chars 0.480000 0.000000 0.480000 ( 0.479662)26 chars 0.480000 0.000000 0.480000 ( 0.481211)27 chars 0.490000 0.000000 0.490000 ( 0.490404)

Page 11: Профилирование и оптимизация производительности Ruby-кода

Ruby String performance

Heap strings

Shared strings

Embedded strings

Page 12: Профилирование и оптимизация производительности Ruby-кода

struct RString { long len; char *ptr;};

Ruby String performance

struct RString { long len; char *ptr; VALUE shared;};

struct RString { char ary[RSTRING_EMBED_LEN_MAX +1];}

RSTRING_EMBED_LEN_MAX = 23

Page 13: Профилирование и оптимизация производительности Ruby-кода

Slow methods call

Page 14: Профилирование и оптимизация производительности Ruby-кода

What can I do to improve performance?

Use C extensions or gems

Use plain SQL instead of frameworks

Use CPU and memory profiling

Use Rubinius or JRuby

Page 15: Профилирование и оптимизация производительности Ruby-кода
Page 16: Профилирование и оптимизация производительности Ruby-кода
Page 17: Профилирование и оптимизация производительности Ruby-кода
Page 18: Профилирование и оптимизация производительности Ruby-кода

STRACE

trace system calls and signals

strace -cp <pid>strace -ttTp <pid> -o <file>

Page 19: Профилирование и оптимизация производительности Ruby-кода

% time seconds uses/call calls errors syscall50,39 0,00064 0 1197 592 read

34,56 0,00044 0 609 writev

14,96 0,000019 0 1226 epoll_ctl

0,00 0,000000 0 4 close

0,00 0,000000 0 1 select

0,00 0,000000 0 4 socket

0,00 0,000000 0 4 4 connect

0,00 0,000000 0 1057 epoll_wait

100,0 0,000127 4134 596 total

strace -cp <pid>

Page 20: Профилирование и оптимизация производительности Ruby-кода

LTRACEtrace dynamic library calls

ltrace -F <conf_file> -bg -x <symbol> -p pid

Page 21: Профилирование и оптимизация производительности Ruby-кода

ltrace -F <conf_file> -bg -x <symbol> -p pid

-F <conf_file>

int mysql_real_query(addr,string,ulong);void garbage_collect(void);int memcached_set(addr,string,ulong,string,ulong);

Page 22: Профилирование и оптимизация производительности Ruby-кода

ltrace -x garbage_collect

ltrace -x mysql_real_query

mysql_real_query(0x1c9e0500, "SET NAMES 'UTF8'", 16) = 0 <0.000324>mysql_real_query(0x1c9e0500, "SET SQL_AUTO_IS_NULL=0", 22) = 0 <0.000322>mysql_real_query(0x19c7a500, "SELECT * FROM `users`", 21) = 0 <1.206506>mysql_real_query(0x1c9e0500, "COMMIT", 6) = 0 <0.000181>

Page 23: Профилирование и оптимизация производительности Ruby-кода

RUBY-PROFfast code profiler for Ruby

Page 24: Профилирование и оптимизация производительности Ruby-кода

%self total self child calls name------------------------------------------------------------------------ 8.39 0.54 0.23 0.31 602 Array#each_index 7.30 0.41 0.20 0.21 1227 Integer#gcd 6.20 0.49 0.17 0.32 5760 Timecell#date 5.11 0.15 0.14 0.01 1 Magick::Image#to_blob

RUBY-PROF

Page 25: Профилирование и оптимизация производительности Ruby-кода

KCachegrind

a tool for visualisation

http://kcachegrind.sourceforge.net

Page 26: Профилирование и оптимизация производительности Ruby-кода

KCachegrind

Page 27: Профилирование и оптимизация производительности Ruby-кода

KCachegrind

Page 28: Профилирование и оптимизация производительности Ruby-кода
Page 29: Профилирование и оптимизация производительности Ruby-кода

PERFTOOLS.RBgoogle’s performance tools for ruby code

CPUPROFILE=/tmp/myprof \

pprof --calgrind ./myapp /tmp/myprof

gem install perftools.rb

RUBYOPT="-r`gem which perftools | tail -1`" \ ruby my_app.rb

Page 30: Профилирование и оптимизация производительности Ruby-кода

PERFTOOLS.RB

CPUPROFILE_REALTIME = 1

CPU/wall time

CPUPROFILE_OBJECTS = 1CPUPROFILE_METHODS = 1

Page 31: Профилирование и оптимизация производительности Ruby-кода

When should I stop performance optimisation?

Premature optimization is the root of all evil(c) Donald Knuth

Page 32: Профилирование и оптимизация производительности Ruby-кода

Make it work

Make it right

Make it fast

Page 33: Профилирование и оптимизация производительности Ruby-кода

What should I remeber before profiling?

Turn GC off (GC.disable)

class Foo def do_smth return "x" * 1024 # take one Kb of memory endendsmth = "x" * 7999999 # alloc almost 8Mb Foo.new.do_smth # here GC will be called

do_smth is so slow!!!

Page 34: Профилирование и оптимизация производительности Ruby-кода
Page 35: Профилирование и оптимизация производительности Ruby-кода
Page 36: Профилирование и оптимизация производительности Ruby-кода

Questions?