upper right bubble
ephort logo
contact icon
lower left bubble

Sådan optimerer du hastigheden på PHP med Cachegrind

Den bedste hastighed får du ved at skrive god kode, når du skriver den. Alligevel kan det være nødvendigt at skulle optimere på det efterfølgende – det hænder i hvert fald for mig

Af Kristian Just Iversen

I artikelserien "Hastighedsoptimering af PHP" går jeg i dybden med, hvordan man bygger hurtige og skalerbare PHP applikationer. Det er ikke en masse tips til små optimeringer, men håndgribelige metoder til at undgå flaskehalse og suboptimal kode.

Artiklerne omhandler udelukkende god eksekveringstid på dine PHP scripts. Vil du forbedre din hjemmesides overall loadtid, så start på PageSpeed Insights, eller se i din browsers Netværks-fane for nogle lavthængende frugter - det er ikke lige det, denne artikelserie handler om.

Artikler i serien:


Koden vokser, brugeraktiviteten vokser og der er pludselig en side, der er langsom, selvom man synes, man tog højde for det hele.

Men hvordan ved du, hvad der gør siden langsom?

Ved at benytte en profiler, kan du få det komplette overblik over ydelsen af din kode – hvor lang tid hver funktion tager om eksekvering, hvor mange gange en funktion kaldes, callstack for hver funktion med mere.

Du kan også benytte et meget omfattende var_dump(microtime(true)); setup, men det vil jeg ikke anbefale dig 😉

Jeg vil i det følgende vise, hvordan jeg bruger Xdebugs Profiler og et Cachegrind-analyseprogram til at finde ud af, hvad der skaber flaskehalse i et PHP script.

Sådan køres Xdebugs Profiler

Xdebugs Profiler køres samtidig med eksekvering af dit PHP script og outputter dens rapport i en Cachegrind-fil.

Aktiver Xdebug i din PHP installation og sæt PHP-variablen xdebug.profiler_enable_trigger til 1. Angiv hvor Cachegrind-filerne skal oprettes med PHP-variablen xdebug.profiler_output_dir.

Start nu dit script med GET-parametret XDEBUG_PROFILE. Fx http://localhost/ditProjekt/index.php?XDEBUG_PROFILE.

Der ligger efterfølgende en Cachegrind-fil klar i den valgte sti, som er klar til at blive importeret i dit yndlings Cachegrind-analyseprogram.

Analyse i WinCacheGrind

Der er mange forskellige analyseprogrammer at vælge imellem. Da jeg er på Windows faldt jeg over WinCacheGrind, som jeg er meget tilfreds med. Andre er glade for KCacheGrind, QCacheGrind eller Webgrind.

Hvis jeg åbner min Cachegrind-fil i WinCacheGrind, vælger “{main}” i venstre-menuen og tabben “Overall” ser jeg en komplet liste over alle funktionskald, hvor lang tid de gennemsnitligt har taget om at blive eksekveret, og en samlet eksekveringstid for alle de gange, den pågældende funktion er blevet kaldt.

image

Brug 1 minut på at kigge på listen over funktioner, inden du læser videre.

Klar igen?

Listen viser alle funktionskald. Alle. Det vil også sige funktioner, der er kaldt af andre funktioner. De øverste linjer vil af samme grund oftest ikke være særligt interessante, da det blot er overordnede funktioner, der initialiserer dit projekt. For at finde de rigtige syndere, skal der dykkes lidt ned på listen.

Trævisningen i venstre side giver mulighed for kun at vise funktionskald under et andet givent funktionskald. Min erfaring siger mig, at det dog kan være en del sværere at bevare overblikket – men det kan være, det fungerer for dig.

WinCacheGrind viser som standard en eksekveringstid i millisekunder. Mange andre Cachegrind-analyseprogrammer har valgt at vise eksekveringstiden som en procent af den samlede eksekveringstid for PHP scriptet. Dette skyldes, at man ikke kan regne med millisekunderne i rapporten. Dels kører du højest sandsynligt profileren på din udviklingsmaskine fremfor produktionsserver, dels gør Xdebug Profileringen at eksekveringstiden er højere end normalt.

Indstil WinCacheGrind til at benytte procent fremfor millisekunder ved at trykke på “sum”-ikonet i toolbaren.

Den samlede eksekveringstid for scriptet står under “Cumulative time” i “{main}”-vinduet.

Find de suboptimale funktioner

Led efter de (selvstændige) funktioner på listen, der optager en betydelig procent af den samlede eksekveringstid.

Se også i kolonnen “Calls” om det giver mening, at funktionen skulle være kaldt, så mange gange, som den er. Måske kaldes funktionen rekursivt ved en fejl.

Med din viden om projektet og kendskab til koden kan du nemt vurdere, hvor lang eksekveringstid der er rimelig for en given funktion.

Filtrer på includes

image

En anden fremgangsmåde er at filtrere på includes/requires.

I ovenstående eksempel ses et række standard WordPress filer, samt nogle af lidt mere interessant karakter: dashboard-top-view.php, activity-loop.php og entry.php.

Jeg ved at activity-loop.php kalder entry.php – så måske kan loopet begrænses til færre iterationer, eller jeg kan undersøge om koden i entry.php kan optimeres.

Nu fandt jeg i hvert fald på under 3 minutter ud af, at entry.php skal undersøges nærmere, da den kan være en mulig flaskehals.

Udfordringer ved call_user_func

Har du mangler funktioner, der kaldes igennem call_user_func mister du overblikket i WinCacheGrind.

Har du lavet meget tynde funktioner, er det dog som regel ikke et reelt problem, da du i stedet kan se på en relateret funktion.

Ellers må du markere call_user_func-linjen i WinCacheGrind og gennemtrævle callstacken.

Jeg synes det hele ser fint ud?!

Hvis ingen funktioner ser ud til at have en urimelig lang eksekveringstid, kan din langsomme eksekveringstid for PHP scriptet skyldes følgende

  1. Mange bække små: alle dine funktioner tager lidt for lang tid 🙂 Måske du er flittig til at lave MySQL kald (dette vil i så fald også fremgå i WinCacheGrind, da du kan se query-funktionens samlede eksekveringstid og samlede antal kald)
  2. Det er ikke dit PHP scripts skyld: din server er langsom, din PHP konfiguration er ikke optimal el.lign.
  3. Dine “nødvendige kernefunktioner” er simpelthen bare tunge. Formålet med dit PHP script kan jo være tung processering af et eller andet. Der er grænser for, hvor meget der kan optimeres (ellers ville alle sider kunne køre på en one.com server – det kan de ikke..).

Var det det?

Ja!

Overblikket over dine funktionskald i WinCacheGrind, lidt sund fornuft og eftertanke gør, at du meget nemt kan overtage kontrollen over dine store PHP projekter igen.

18. NOV 2021

Få en uforpligtende snak

Rune Due Møller

Rune Due Møller

Partner og direktør

Du er velkommen til at ringe direkte på +45 21 90 71 75 eller skrive en mail på info@ephort.dk

Du kan også udfylde formularen, så kontakter vi dig hurtigst muligt.