Ruby jegyzet

Ha meg szeretnénk vizsgálni, hogy a program kódunk mely részei mennyi időt igényelnek a futáshoz, akkor Profiling techinkára van szükségünk. A cél a kódunk optimalizációja úgy, hogy felmérjük, mely programrészek a legidőigényesebbek és ezeket adott esetben átírjuk vagy újraírjuk.

Ruby-nak van beépített profiling megoldása. A "-r profile" paramétert megadva az interpreter kinyomtat az stderr kimenetre a program futása után egy statisztikát, melyben minden egyes sor egy külön metódust ábrázol és megmutatja, hogy mennyi ideig tartott a futása és mennyiszer lett meghívva.

(Az alábbi példában arra voltam kíváncsi, hogy 100 véletlen számból eltávolítva az egyformákat mennyi számot kapunk. Érdekes módon az iterációk számát növelve egy bizonyos értékhez közelít az eredmény.)

time ruby -r profile -e "n = 1000; puts (1..n).map{(1..100).map{rand 100}.uniq.size}.inject(:+)/n.to_f"
63.382
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 75.07     2.65      2.65     1001     2.65     6.79  Range#each
 21.81     3.42      0.77   100000     0.01     0.01  Kernel.rand
  1.13     3.46      0.04     1000     0.04     0.04  Array#uniq
  0.85     3.49      0.03     1001     0.03     6.82  Enumerable.map
  0.57     3.51      0.02        1    20.00    30.00  Array#each
  0.28     3.52      0.01     1000     0.01     0.01  Array#size
  0.28     3.53      0.01      999     0.01     0.01  Fixnum#+
  0.00     3.53      0.00        1     0.00     0.00  Float#/
  0.00     3.53      0.00        1     0.00     0.00  Float#coerce
  0.00     3.53      0.00        2     0.00     0.00  IO#write
  0.00     3.53      0.00        1     0.00     0.00  Kernel.puts
  0.00     3.53      0.00        1     0.00     0.00  Float#to_s
  0.00     3.53      0.00        1     0.00    30.00  Enumerable.inject
  0.00     3.53      0.00        1     0.00     0.00  Fixnum#/
  0.00     3.53      0.00        1     0.00     0.00  Fixnum#to_f
  0.00     3.53      0.00        1     0.00  3530.00  #toplevel

real    0m4.614s
user    0m3.533s
sys     0m1.074s

Az oszlopok közül fontos az első "time" oszlop, mely a metódusra szánt teljes időt mutatja százalékban a teljes program futáshoz képest; a "self seconds" a saját szükséges teljes időt mutatja másodpercben; a "calls" a metódus meghívásainak számát; a "self ms/call" pedig ez utóbbi két érték hányadosát.

A statisztikában látszik például, hogy a véletlen szám generálás időben elég drága. Illetve érdekes még számomra, hogy a uniq metódus a legdrágább a belső ciklusban a rand-on kívül.

Itt egy másik:

ruby -r profile -e "10000.times { puts 'hello'; print 'hello\n' }" 1>/dev/null
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 38.62     0.56      0.56    10000     0.06     0.07  Kernel.puts
 30.34     1.00      0.44        1   440.00  1450.00  Integer#times
 19.31     1.28      0.28    10000     0.03     0.03  Kernel.print
 11.72     1.45      0.17    30000     0.01     0.01  IO#write
  0.00     1.45      0.00        1     0.00  1450.00  #toplevel

Itt tisztán látható, mennyivel hatékonyabb print-et használni puts helyett. (Ugye a puts annyiban különbözik a print-től önmagában, hogy egy newline karaktert is nyomtat a sor végére alapból.)

Az alábbi linken egy 2005-ben készült 9 oldalas bemutató olvasható az IBM-től, mely lépésekben bemutatja a profiling-ot Ruby nyelven. Tömör és egyszerű. Egy programkódon bemutatja a mérést, majd a kódon változtatva a teljesítmény javulást.

IBM tutorial: Profiling and optimizing Ruby code

A bejegyzés apropója: Népszerűsítsük a Ruby programozási nyelvet!

Hozzászólások

Ez érdekes volt, jöhet még ilyen! :)

Ebbol a szempontbol a Rubinius erdemes kezdemenyezes meg, nagyon sokmindent, sokfelekeppen tud profilozni, raadasul mivel LLVM-et hasznal, az osszes abban hasznalatos eszkoz is jo a futtatott ruby kod inspektalasahoz. Az csak bonusz, hogy 3in1 platform, mind a 3 fo ruby platformot kepes szolgaltatni (1.8, 1.9, 2.0) egy binarison belul. Eleg nagy aranyban kompatibilis a C API-ja.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal