---
title: 'Profil Çıkarma'
source: 'https://academia.sh/tr/kurslar/ruby-uretim/profil-cikarma'
course: 'Ruby Ekosistemi ve Üretim'
language: tr
updated: '2026-10-21T05:03:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'TracePoint ile programın kendi yöntemlerinin çağrı sayısını çıkarır'
    - 'Sıcak yolu çağrı sayısından belirler ve belirleyeninin kod olduğunu gösterir'
    - 'Düzeltmeden sonra yeni sayımın sıcak yolu nasıl değiştirdiğini ölçer'
    - 'Çağrı sayısı ile sürenin aynı soruyu yanıtlamadığını açıklar'
---

# Profil Çıkarma

Bir programın hangi yöntemi sıcak yoldur sorusu çağrı sayısıyla sorulur ve çağrı sayısı koda aittir. Ders TracePoint ile çağrıları sayar, düzeltmenin sayıyı nasıl değiştirdiğini ölçer ve süreye dayalı sıralamanın neden ortama bağlı olduğunu gösterir.

Önceki ders bir bloğun kaç nesne ayırdığını sordu. Bu ders bir programın hangi yöntemde ne kadar çalıştığını sorar; ancak süreyle değil, çağrı sayısıyla. Kursun ölçü ekseni değişmez: **bu sonucu ne belirliyor?** Bu dersin gözlemi `sicak yol` satırıdır ve belirleyeni **kod**dur.

**Profil çıkarma (profiling)**, bir programın zamanının ya da çağrılarının nerede toplandığını ölçme işidir. M10/K03'te bir kodun **kaç kez koştuğu** ölçülmüştü. Profil çıkarma da çağrı sayar, ama burada sınıf sayının kendisi değil, sayıyı **ne belirlediğidir**. Karşılaştırmalı ölçüm ve profil çıkarmanın ilkeleri M10/K05'te görülmüştü; bu ders yalnız Ruby'nin standart kütüphanesindeki araçlarla, ürün ya da profil aracı kullanmadan, iki şeyi ölçer: yöntem çağrılarının sayısı ve sürenin türü. **Sıcak yol (hot path)**, en çok çağrılan yöntemdir. Çekirdeğin `belirleyen.rb` dosyası ve bu dersin kesiti `profil.rb` aşağıda olduğu gibi verilir; ikisi de kaynaktır, çıktısı yoktur. Kesitteki `sicak_yol` çağrıları `TracePoint` ile sayar; yalnız programın kendi tanımladığı yöntemler sayılır.

```ruby
# belirleyen.rb — bir kosum modeli ve bir sonucu neyin belirledigini siniflandiran yardimci

# Kosum: sonucun bagli olabilecegi uc girdi. Bu uc girdinin disinda kalan her sey koddur.
Kosum = Data.define(:kilit, :tohum, :ortam)

TABAN = Kosum.new(
  kilit: { "bicimleyici" => "1.4.2", "ayristirici" => "2.0.1" },
  tohum: 1,
  ortam: { saat: Time.utc(2026, 10, 16, 9, 0), cekirdek: 4, degiskenler: {} }
)

# Her degisken tek bir girdiyi degistirir; otekiler tabandaki gibi kalir.
DEGISKENLER = {
  bagimlilik: TABAN.with(kilit: { "bicimleyici" => "1.5.0", "ayristirici" => "2.1.0" }),
  sira: TABAN.with(tohum: 2),
  ortam: TABAN.with(ortam: { saat: Time.utc(2027, 3, 1, 9, 0), cekirdek: 8,
                             degiskenler: { "ISCI_SAYISI" => "3" } })
}

# Kural: hesap once tabanda, sonra her degiskende bir kez kosar. Sonucu degistiren ilk
# degisken (bagimlilik, sira, ortam sirasiyla) belirleyendir; hicbiri degistirmiyorsa kod.
def belirleyen(hesap)
  taban = hesap.call(TABAN)
  degisti = DEGISKENLER.to_h { |ad, kosum| [ad, hesap.call(kosum) != taban] }
  tur = degisti.key(true)&.to_s || "kod"
  kanit = degisti.map { |ad, d| "#{ad[0].upcase}#{d ? '+' : '-'}" }.join(" ")
  [tur, kanit, taban]
end
```

```ruby
# profil.rb — programin tanimladigi yontemlerin cagrilari sayilir
# Profil: programin tanimladigi yontemlerin cagrilari sayilir; en cok cagrilan sicak yoldur.
def sicak_yol
  sayim = Hash.new(0)
  iz = TracePoint.new(:call) { |t| sayim[t.method_id] += 1 if t.defined_class == Object }
  iz.enable { yield }
  sayim.max_by { |_, n| n }
end

def para_bicimle(kurus) = format("%d.%02d", kurus / 100, kurus % 100)
def satir_bicimle(satir) = "#{satir[:ad]} #{para_bicimle(satir[:birim])} #{para_bicimle(satir[:toplam])}"
def rapor(satirlar) = satirlar.map { |s| satir_bicimle(s) }.join("\n")
```

## Çağrıları Saymak

Bir yüz satırlık rapor kurulur: her satırın bir adı, birim fiyatı ve toplamı vardır. `rapor` her satırı `satir_bicimle`ye verir, o da hem birim fiyatı hem toplamı `para_bicimle` ile biçimler. Aşağıdaki blok bu raporu `TracePoint` altında koşturur ve her yöntemin çağrı sayısını çıkarır.

```ruby
# sayim.rb — her yontemin cagri sayisi
require_relative "belirleyen"
require_relative "profil"

def cagri_sayimi
  sayim = Hash.new(0)
  iz = TracePoint.new(:call) { |t| sayim[t.method_id] += 1 if t.defined_class == Object }
  iz.enable { yield }
  sayim.sort_by { |ad, n| [-n, ad] }
end

satirlar = Array.new(100) { |i| { ad: "urun#{i}", birim: 1250, toplam: 1250 * (i + 1) } }
p cagri_sayimi { rapor(satirlar) }
p sicak_yol { rapor(satirlar) }
p belirleyen(->(_k) { sicak_yol { rapor(satirlar) } })
```

```
[[:para_bicimle, 200], [:satir_bicimle, 100], [:rapor, 1]]
[:para_bicimle, 200]
["kod", "B- S- O-", [:para_bicimle, 200]]
```

`para_bicimle` iki yüz kez çağrıldı: yüz satırın her biri onu iki kez çağırdı. `satir_bicimle` yüz, `rapor` bir kez çağrıldı. İkinci satır `sicak_yol` sonucudur, yani en çok çağrılan yöntem ve sayısı. Üçüncü satır kuralı çalıştırır: kilit dosyasındaki sürümler, tohum ve ortam değişince sonuç değişmedi, belirleyen **kod**dur. Çağrı sayısı raporun satır sayısından ve yöntemlerin birbirini çağırma düzeninden gelir; ikisi de kodun işidir. **RB13.** `defined_class == Object` süzgeci yalnız ana düzeyde tanımlı yöntemleri sayar; başka sınıflardaki yöntemler bu sayıma girmez.

Süzgeç yalnız programın kendi yöntemlerini seçer. Ruby'nin kendi yerleşik yöntemleri `:call` olayını üretmez, `:c_call` olayını üretir. Aynı raporu `:c_call` ile saymak, hangi yerleşik yöntemlerin sıcak olduğunu gösterir.

```ruby
# yerlesik.rb — yerlesik yontemlerin cagri sayisi
require_relative "profil"

satirlar = Array.new(100) { |i| { ad: "urun#{i}", birim: 1250, toplam: 1250 * (i + 1) } }
sayim = Hash.new(0)
iz = TracePoint.new(:c_call) { |t| sayim[t.method_id] += 1 }
iz.enable { rapor(satirlar) }
p sayim.sort_by { |ad, n| [-n, ad] }.first(5)
```

```
[[:[], 300], [:%, 200], [:/, 200], [:format, 200], [:join, 1]]
```

En çok çağrılan yerleşik yöntem `[]` oldu: her satır adı, birim fiyatı ve toplamı üç kez indeksler. `%`, `/` ve `format` ikişer yüz kez geldi, çünkü `para_bicimle` iki yüz kez çağrıldı ve her çağrı bir bölme, bir kalan alma ve bir `format` yaptı. Sayılar kodun yapısını yansıtır; satır sayısını ikiye katlasak satıra bağlı sayıların hepsi ikiye katlanırdı. **RB14.** Altıncı sıra ve sonrası burada gösterilmedi; beşinci sıradaki `join` bir kez çağrıldı ve geri kalanlar bu sayımdan çıkmaz.

## Düzeltme ve Yeni Sayım

Sıcak yol bulunduktan sonra ilk soru şudur: bu çağrıların hepsi gerekli mi? Raporda birim fiyat her satırda aynıdır ve yalnız bir kez basılması yeterlidir. Düzeltilmiş sürüm her satırda toplamı bir kez biçimler.

```ruby
# duzelt.rb — para_bicimle her satirda bir kez cagrilir
require_relative "profil"

def satir_bicimle_kisa(satir) = "#{satir[:ad]} #{para_bicimle(satir[:toplam])}"
def rapor_kisa(satirlar) = satirlar.map { |s| satir_bicimle_kisa(s) }.join("\n")

def cagri_sayimi
  sayim = Hash.new(0)
  iz = TracePoint.new(:call) { |t| sayim[t.method_id] += 1 if t.defined_class == Object }
  iz.enable { yield }
  sayim.sort_by { |ad, n| [-n, ad] }
end

satirlar = Array.new(100) { |i| { ad: "urun#{i}", birim: 1250, toplam: 1250 * (i + 1) } }
p cagri_sayimi { rapor_kisa(satirlar) }
```

```
[[:para_bicimle, 100], [:satir_bicimle_kisa, 100], [:rapor_kisa, 1]]
```

`para_bicimle` artık yüz kez çağrılıyor ve `satir_bicimle_kisa` ile aynı sayıya düştü. Sıcak yol tek bir yöntem olmaktan çıktı: iki yöntem eşit çağrılıyor. Düzeltme çağrıyı yarıya indirdi ama yavaşın hangisi olduğu sorusunu çözmedi. **RB15.** Bu ölçüm çağrı sayısının yarıya indiğini gösterir; sürenin de yarıya indiğini göstermez.

## Sınırlayıcı Ölçüm

Çağrı sayısı, en çok çalışan yöntemi söyler; en yavaş yöntemi söylemez. Bir yöntem yüz kez çağrılıp her çağrıda uzun sürebilir, bir başkası iki yüz kez çağrılıp her seferinde kısa sürebilir. Süre ayrı bir ölçümdür ve ayrı bir belirleyeni vardır. İki araç süreyi ölçer: `Benchmark.realtime` ve `Process.clock_gettime(Process::CLOCK_MONOTONIC)`. İkisi de kayan noktalı bir sayı döndürür; sayının kendisi basılmaz çünkü her koşumda ve her makinede farklıdır.

```ruby
# sure.rb — sure olcen iki arac, ikisi de Float dondurur
require "benchmark"
require_relative "profil"

satirlar = Array.new(100) { |i| { ad: "urun#{i}", birim: 1250, toplam: 1250 * (i + 1) } }
p Benchmark.realtime { rapor(satirlar) }.class
p Process.clock_gettime(Process::CLOCK_MONOTONIC).class
```

```
Float
Float
```

İki araç da `Float` döndürdü; değerleri basılmadı. Bir ölçüm süreye dayanıyorsa ve sonuç "en yavaş hangisi" ise, belirleyen **ortam**dır: makine yüklüyse, çekirdek farklıysa ya da önbellek ısınmışsa sıra değişir. Çağrı sayısı ise kodun işidir ve bu yüzden her yerde aynı çıkar. İkisi aynı soruyu yanıtlamaz: hangisi daha çok çalışıyor sorusunun yanıtı koddadır; hangisi daha çok zaman alıyor sorusunun yanıtı makinededir.

Bu dersin sınırlayıcısı budur: sıcak yol çağrı sayısıyla belirlenir ve kod olarak sınıflandırılır, ama "en yavaş" bu sınıflamanın dışındadır. **RB16.** Süre ölçümü burada yalnız türüyle gösterildi; hangi yöntemin gerçekten en yavaş olduğu bu derste ölçülmedi ve çağrı sayısından çıkarılmamalıdır.

## Özet

- Programın kendi yöntemlerinin çağrı sayısı `TracePoint` ile `:call` olayı üzerinden sayılır; yerleşik yöntemler `:c_call` ile ayrıca sayılır.
- Sıcak yolu çağrı sayısı belirler, çağrı sayısını ise **kod**: kural üç değişkende de aynı yöntemi buldu.
- Düzeltmeden sonra yeni sayım yapılır; sıcak yol tek yöntemden birkaçına yayılabilir.
- Süre `Benchmark.realtime` ya da `Process.clock_gettime` ile ölçülür ve ortama bağlıdır; çağrı sayısı ile süre aynı soruyu yanıtlamaz.

## Sonraki Adım

Kod, çağrı sayıları ve ayrılan nesneler ölçüldü; elde bir yayın çıkarılacak bir uygulama var. Son ders yayının içindeki üç şeyi, varlık adını, sürüm dizinini ve bildirimi ayrı ayrı sorgular ve her birinin belirleyenini bulur.
