9.7 Mérés és profiling

← 9. Optimalizációs alapok

9.7 Mérés és profiling alapok

Áttekintő

Az előző alfejezetekben sokat beszéltünk arról, mit érdemes optimalizálni. De hogyan tudod meg, hogy kell-e egyáltalán optimalizálni valamit, és ha igen, hol kell belenyúlni a kódba?

A válasz: méréssel.

Ez az alfejezet azt mutatja be, hogyan mérj teljesítményt helyesen – ne találgatással, ne érzésre, hanem adatokkal. Megismered a legfontosabb mérési eszközöket és módszereket, és megtanulod, mikor elég egy egyszerű console.time(), és mikor kell komolyabb profilozóeszköz.

Amit tanulsz:

  • Mi a különbség a benchmarking és a profiling között
  • Hogyan mérj válaszidőt backend oldalon
  • Hogyan használd a böngésző DevTools Performance tabját
  • Mikor automizálj mérést és mikor elég a manuális megközelítés
  • Hogyan értelmezd a mért adatokat és döntsd el, mit optimalizálj

Miért számít ez az állásinterjún?
Ha egy interjún azt kérdezik: „Hogyan közelítenél meg egy lassú oldalt?", és azt mondod: „Mérnék először" – ez azonnal megkülönböztet a többi junior jelentkezőtől, akik rögtön kódot kezdenének módosítani.

Miért számít production-ben?
Vak optimalizálással rengeteg időt lehet elvesztegetni olyan dolgokra, amelyek nem okozzák a tényleges problémát. A mérés megmutatja, hol az igazi szűk keresztmetszet.


Részletes leírás

Mérés előtt: tisztázd, mit mész

Mielőtt elindítod a stoppert, tudnod kell, mit mész. A teljesítménymérés három kérdésre keresi a választ:

  1. Mennyit? – Mennyi ideig tart egy adott művelet? (Idő)
  2. Hol? – A kód melyik részén töltődik el a legtöbb idő?
  3. Miért? – Mi az oka a lassúságnak?

Az első kérdésre benchmarking, a másodikra és harmadikra profiling ad választ.


Benchmarking vs. profiling – mi a különbség?

Ez a két fogalom sokszor összekeveredik, de különböző kérdésekre válaszolnak.

Benchmarking = Mennyi ideig tart?

Megméred, hogy egy adott kódrészlet, endpoint, vagy rendszer milyen gyorsan fut. Eredménye egy szám (pl. „ez az API endpoint átlagosan 240ms alatt válaszol").

Mire jó?

  • Összehasonlítás: most gyorsabb, mint korábban?
  • Teljesítmény-küszöb betartása: az SLA 500ms-t mond, mi 240ms-en vagyunk – megfelel-e?
  • Regresszió-detektálás: egy változtatás után lassabb lett-e valami?

Profiling = Hol töltődik el az idő?

Megmutatja, hogy a futás alatt a kód melyik részén mennyi időt töltött a program. Eredménye egy térkép: „a teljes futásidő 70%-a az adatbázis-lekérésben ment el, 20% a fájlírásban, 10% a logikában".

Mire jó?

  • Szűk keresztmetszet azonosítása
  • Váratlan teljesítménybeli problémák feltérképezése
  • „Hol nyúljak bele?" kérdés megválaszolása

Analógia:
Benchmarking = megméred, hogy 100 métert mennyi idő alatt futottál le.
Profiling = kiderítjük, hogy az idő 60%-ában cipőfűzőt kötöttél.


Backend response time mérése

Az egyszerű megközelítés: manuális időzítés

Ha gyorsan kell egy számot, a legtöbb nyelvben van egyszerű időmérési eszköz.

Python:

import time

start = time.time()
result = do_something_slow()
end = time.time()

print(f"Elapsed: {(end - start) * 1000:.2f}ms")

JavaScript (Node.js):

console.time('my-operation');
const result = doSomethingSlow();
console.timeEnd('my-operation');
// Kimenet: my-operation: 243.521ms

PHP:

$start = microtime(true);
$result = doSomethingSlow();
$end = microtime(true);

echo "Elapsed: " . round(($end - $start) * 1000, 2) . "ms";

Ez hasznos fejlesztés közben, ha gyorsan szeretnéd tudni, hogy egy konkrét kódrészlet mennyit fut.

Logging és monitoring production-ben

Fejlesztői print/console.log időmérés production-ben nem elegendő. Helyette:

  • Request logging: minden HTTP kéréshez logold a válaszidőt (ezt sok framework automatikusan megteszi)
  • Application Performance Monitoring (APM): eszközök, amelyek automatikusan gyűjtik és vizualizálják a teljesítményadatokat (pl. New Relic, Datadog, Sentry Performance)
  • Slow query log: adatbázis szinten logolható, ha egy lekérdezés egy adott idő felett van

Junior fejlesztőként ritkán te állítod be ezeket – de tudnod kell, hogy léteznek, és hogyan olvasd az eredményeket.

Amit nézz: p50, p95, p99

Ha egy endpoint válaszidejét vizsgálod, ne csak az átlagot nézd. Az átlag elfedheti a problémát.

MérőszámJelentés
p50 (medián)A kérések 50%-a ennyi ms alatt válaszol
p95A kérések 95%-a ennyi ms alatt válaszol
p99A kérések 99%-a ennyi ms alatt válaszol

Ha az átlag 100ms, de a p99 8000ms, az azt jelenti, hogy minden 100. felhasználó 8 másodpercet vár. Ez érzékelhető probléma, az átlag mégis „szépnek" tűnik.


Browser DevTools Performance tab

A Chrome (és más modern böngészők) beépített Performance eszköze az egyik leghasznosabb profiling eszköz frontend fejlesztéshez – és ingyenes.

Hogyan nyisd meg és rögzíts

  1. F12 (vagy jobb klikk → Inspect)
  2. Kattints a Performance tabra
  3. Kattints a piros rögzítés gombra (⏺)
  4. Végezd el a lassúnak tűnő műveletet
  5. Kattints a Stop gombra

Mit látsz a felvételen?

Flamegraph (lángtérkép)
A legfontosabb nézet. Mutatja, hogy a böngésző mit csinált és mennyi ideig. Egy széles sáv = sok idő telt el abban a funkcióban. A mélység = egymásból hívott függvények.

Fő kategóriák, amiket nézz:

  • Scripting (JS futtatás): sok időt vesz el? Lehet JS-optimalizációra szükség
  • Rendering: az oldal újrarajzolása – sok layout-reflow jele lehet
  • Painting: pixelek kirajzolása – intenzív animációknál jellemző

Konkrét dolgok, amit keress juniorként:

  • Hosszú script blokkok (>50ms) – ezek blokkolhatják a UI-t
  • Sok és ismétlődő re-render – felesleges állapotváltozás jele
  • Nagy hálózati kérések – Network tab-on látható az ideje és mérete

Tipp: Ne ijedj meg, ha elsőre sok mindent nem értesz. A Performance tab mély eszköz. A legfontosabb, hogy meg tudd nyitni, rögzíts egy felvételt, és azonosítsd, hol töltődik el a legtöbb idő.

Network tab – a gyors győzelem

Ha az oldal lassú, először mindig nézd meg a Network tabot, mielőtt mélyre mész a Performance tabban:

  • Mennyi ideig tartanak a kérések?
  • Van-e feleslegesen nagy fájl (pl. 5MB-os kép, tömörítetlen JavaScript)?
  • Sorban állnak-e egymás után kérések, amelyek párhuzamosan is mehetnének?
  • Van-e 404 vagy 500 hiba, ami újra-kéréseket okoz?

Sokszor a leglassabb oldal nem a JavaScript, hanem egy 10MB-os kép vagy egy 2 másodpercig váró API hívás.


Profiling backend kódban

Python: cProfile

import cProfile

cProfile.run('my_slow_function()', sort='cumulative')

Kimenet: táblázat, amelyben látható, hogy melyik függvény hányszor lett meghívva és mennyi ideig futott összesen.

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.243    1.243 my_code.py:10(my_slow_function)
     1000    1.230    0.001    1.230    0.001 my_code.py:25(database_query)

Ebből látszik: database_query 1000-szer lett meghívva, és ez viszi el az idő 99%-át. Valószínűleg N+1 query-ről van szó.

Node.js: --prof flag

node --prof my_app.js
# Generál egy isolate-*.log fájlt
node --prof-process isolate-*.log > profile.txt

PHP: Xdebug vagy Blackfire

PHP-ban az Xdebug profiler vagy a Blackfire.io eszköz a legelterjedtebb. Ezeket általában fejlesztői környezetben futtatják, production-ben kerülik, mert lelassítják az alkalmazást.

Általános tanács: profilozz fejlesztési/staging környezetben

A legtöbb profiling eszköz overhead-del jár – maga a mérés lassítja a programot. Éles production-ban ne hagyd bekapcsolva állandóan a profiling eszközt. Futtasd fejlesztésben, staging-en, vagy production-ban rövid időre, ha konkrét problémát kell diagnosztizálni.


Mikor elég a manuális mérés, mikor kell automatizálni?

Manuális mérés elég, ha:

  • Egyszeri kérdésre keresel választ: „Ez a függvény lassú-e?"
  • Fejlesztés közben gyors visszajelzésre van szükséged
  • Nincs production teljesítményproblémád, csak fejlesztői kíváncsiság

Automatizált mérés kell, ha:

  • Regressziót akarsz elkerülni (CI pipeline-ban futó performance benchmark)
  • Production rendszer folyamatos monitorozásra szorul
  • SLA betartását kell bizonyítanod
  • Terheléstesztet végzel (pl. k6, JMeter, Locust eszközökkel)

Junior fejlesztőként valószínűleg ritkán állítasz be CI pipeline-os performance tesztet. De ha a csapatodban van ilyen rendszer, tudnod kell olvasni az eredményeket és érteni, mire figyelmeztetheti.


A mérési folyamat junioroknak

Ha egy lassúság-panasz érkezik (felhasználótól, projektmenedzsertől, csapattárstól), ez a javasolt megközelítés:

  1. Reprodukáld – Te is látod a lassúságot? Milyen feltételek mellett?
  2. Mérd meg – Pontosan mennyi ideig tart? Minden esetben, vagy csak bizonyos feltételek mellett?
  3. Lokalizáld – Frontend, backend, adatbázis, hálózat? Melyik rész a lassú?
  4. Profilozz – Azon a rétegen belül, mi a szűk keresztmetszet?
  5. Hipotézis és javítás – Mit változtatsz, és miért gondolod, hogy segít?
  6. Ellenőrizd a javítást – Tényleg gyorsabb lett? Mérj újra!

Ez a folyamat akkor is működik, ha csak console.time()-ot és Network tabot használsz. A lényeg a szisztematikusság, nem az eszköz.


Életszerű példák

Példa 1: „Az oldal lassú" – hol kezdj?

Szituáció: A csapat Slack-jén jön az üzenet: „Az admin felületen a felhasználólista töltése nagyon lassú, 10+ másodperc."

Amit junior tapasztalat nélkül csinálna:
Egyből belemegy a kódba, elkezdi „optimalizálni" a JavaScriptet, esetleg hozzáad cache-t – találomra.

Amit méréssel csinálsz:

  1. Megnyitod a Network tabot – Látod: egy API hívás (GET /api/users) 9800ms-t vesz igénybe. A frontend nem a probléma.
  2. Backend logot nézel – Az endpoint log azt mutatja: az adatbázis lekérdezés 9600ms.
  3. SQL EXPLAIN-t futtatsz – Kiderül: nincs index a created_at oszlopon, amin szűrnek. Full table scan fut 2 millió soron.
  4. Index hozzáadása – 50ms-re csökken a válaszidő.
  5. Újramérés – Megerősíted, hogy tényleg megoldódott.

Tanulság: A Network tab 30 másodperce megmutatta, hogy nem a frontend a probléma. Ha vak optimalizálással kezdtük volna, napokat elpazarolhattunk volna.


Példa 2: Benchmark – romló-e a teljesítmény?

Szituáció: Egy refaktorálás előtt és után le akarod ellenőrizni, hogy a változtatás nem rontotta-e a teljesítményt.

import time
import statistics

def benchmark(func, iterations=100):
    times = []
    for _ in range(iterations):
        start = time.perf_counter()
        func()
        end = time.perf_counter()
        times.append((end - start) * 1000)  # ms
    
    print(f"Átlag: {statistics.mean(times):.2f}ms")
    print(f"Medián: {statistics.median(times):.2f}ms")
    print(f"Min: {min(times):.2f}ms, Max: {max(times):.2f}ms")

benchmark(old_implementation)
benchmark(new_implementation)

Ez egy egyszerű, de hasznos megközelítés: 100-szor mérsz, hogy kiátlagold a véletlenszerű ingadozásokat.

Fontos: Egyetlen mérés nem elég. A CPU terheltsége, az operációs rendszer más folyamatai, a cache állapota mind befolyásolják az eredményt. Mindig több iteráció átlagát nézd.


Példa 3: DevTools flamegraph értelmezése

Szituáció: Egy gombkattintás után az oldal 2 másodpercig nem reagál semmire.

Performance tab rögzítés után a flamegraph-on látod:

[click handler - 1980ms]
  └─ [processItems - 1950ms]
       └─ [filterByDate - 1200ms]
       └─ [sortItems - 740ms]

Ebből látszik:

  • A filterByDate veszi el az idő 62%-át
  • A sortItems veszi el a 38%-át
  • Ha csak a filterByDate-et javítod, máris felére csökkented a teljes futásidőt

Ezek nélkül az adat nélkül vakon próbálgathattad volna, hogy melyik részben van a probléma.


Példa 4: „Gyorsabb lett" – de tényleg?

Szituáció: Optimalizálás után úgy tűnik, gyorsabb lett az oldal. De biztos vagy benne?

Helytelen megközelítés: „Korábban lassúnak tűnt, most gyorsabbnak tűnik."

Helyes megközelítés:

Előtte: 5 mérés átlaga = 2340ms (p95: 3100ms)
Utána:  5 mérés átlaga = 340ms  (p95: 420ms)

Most már bizonyítékod van. És ha jövőre valaki visszakérdez, hogy „mikor lassult be az oldal?", van egy mérési kiindulópontod.


Feladatok és tesztek

Gyakorlati feladat

Teljesítmény-mérési terv

Kapsz egy feladatot: „A terméklista oldal lassú, különösen sok termék esetén."

Állítsd össze a mérési tervet az alábbi szempontok szerint:

  1. Milyen eszközzel mérnéd először, hogy a frontend vagy a backend a lassú? Miért?
  2. Ha a backend a lassú, milyen adatot szeretnél látni a logban?
  3. Hogyan különböztetnéd meg, hogy az adatbázis-lekérdezés vagy a feldolgozási logika a probléma?
  4. Miután megtaláltad a problémát és javítottad: hogyan ellenőrzöd, hogy a javítás tényleg segített?
  5. Mit jelent az, hogy „p95 = 800ms"? Ez jó eredmény-e, ha az elvárás az, hogy az oldal 1 másodpercen belül betöltödjön?

(Nem kell kódot írni – szöveges tervként is megadható a válasz.)


Tesztkérdések

1. Mi a különbség a benchmarking és a profiling között?

a) Benchmarking csak frontend-re, profiling csak backend-re vonatkozik
b) Benchmarking azt méri, mennyi ideig tart egy művelet; profiling megmutatja, a kód melyik részén töltődik el az idő
c) Benchmarking automatikus, profiling manuális mérési módszer
d) Profiling az egyetlen pontos mérési módszer, a benchmarking csak becslés

(Helyes: b)


2. Az alábbi Python kódrészlet mit mér?

import time
start = time.time()
result = process_data(large_dataset)
print(f"{(time.time() - start) * 1000:.2f}ms")

a) A process_data függvény memóriafelhasználását
b) A process_data függvény futásidejét milliszekundumban
c) A large_dataset méretét
d) A CPU terhelését a függvény futása alatt

(Helyes: b)


3. Miért nem elegendő az átlag (mean) egyedül egy backend endpoint válaszidejének értékelésekor?

a) Az átlag nem számítható ki pontosan, ha sok mérés van
b) Az átlag elfedheti a kiugró (lassú) eseteket, amelyeket a p95/p99 mutat meg
c) Az átlag csak frontend mérésre alkalmazható
d) Az átlag mindig magasabb értéket ad, mint a valódi teljesítmény

(Helyes: b)


4. A Browser DevTools Performance tab rögzítése után flamegraph-ot látsz. Melyik állítás igaz?

a) Minél mélyebb egy elem a gráfban, annál lassabb
b) A vízszintesen szélesebb sávok több időt jelölnek az adott műveletre
c) A flamegraph csak hálózati kéréseket mutat
d) Flamegraph csak Node.js alkalmazásokban elérhető

(Helyes: b)


5. Egy lassú oldal diagnosztizálásakor mi a helyes első lépés?

a) Optimalizálni a legnagyobb JavaScript fájlt
b) Rögtön SQL indexet adni hozzá
c) A Network tab megnyitásával megvizsgálni, melyik kérés lassú
d) A teljes kódbázist újraírni

(Helyes: c)


6. Mit jelent, ha egy mérési eredménynél azt olvasod: p99 = 4500ms, de az átlag 120ms?

a) Az átlag mérési hibás, a helyes értéket a p99 adja
b) A kérések 99%-a 4500ms alatt válaszol, és ez egy jó eredmény
c) A kérések 1%-a 4500ms-nél is hosszabb ideig vár – ez 100 felhasználóból 1-et érint
d) Nincs különbség a p99 és az átlag között, ugyanazt jelzik

(Helyes: c)


7. Miért nem hagyják bekapcsolva a profiling eszközt folyamatosan production-ban?

a) Mert a profiling eszközök illegálisak éles környezetben
b) Mert a profiling overhead-del jár és maga is lassítja az alkalmazást
c) Mert a profiling csak fejlesztői gépeken működik
d) Mert a profiling csak CPU-t mér, nem hálózatot

(Helyes: b)


8. Melyik állítás igaz a benchmarking helyes elvégzéséről?

a) Elég egyszer lefuttatni a mérést, az eredmény pontos lesz
b) Több iteráció átlagát kell nézni, mert a CPU terheltsége és cache-állapot befolyásolják az eredményt
c) Benchmarking csak terhelésteszt keretében végezhető
d) A benchmark eredménye mindig milliszekundumban adandó meg

(Helyes: b)


9. Melyik szituációban elegendő a manuális console.time() / time.time() mérés?

a) Production rendszer folyamatos monitorozásakor
b) SLA teljesítésének folyamatos bizonyításakor
c) Fejlesztés közben egy konkrét kódrészlet gyors teljesítményvizsgálatakor
d) 1000 párhuzamos felhasználó szimulálásához

(Helyes: c)


10. Egy diagnosztizálási folyamatban mi a helyes sorrend?

a) Javítás → mérés → lokalizálás → reprodukálás
b) Reprodukálás → mérés → lokalizálás → hipotézis → javítás → újramérés
c) Profilozás → hipotézis → reprodukálás → mérés
d) Lokalizálás → javítás → mérés → reprodukálás

(Helyes: b)

Scroll to Top