Eine Möglichkeit besteht darin, eine Funktion aufzurufen, die viel Code enthält und zwischen den Aufrufen des Elements, das Sie profilieren möchten, auf eine Menge Speicher zugreift. Zum Beispiel in Pseudo-Code (um weitgehend sprachneutral zu sein):
// loop some number of times
{
//start timing
profile_func();
//stop timing
//add to total time
large_func(); // Uses lots of memory and has lots of code
}
// Compute time of profile func by dividing number of iterations by total time
Der Code in large_func() kann unsinniger Code sein, z. B. eine Reihe von Ops, die immer wieder wiederholt werden immer wieder. Entscheidend ist, dass er oder sein Code beim Kompilieren nicht optimiert wird, so dass er tatsächlich die Code- und Daten-Caches der CPU (und auch die L2- und L3-Caches (falls vorhanden)) leert.
Dies ist ein sehr wichtiger Test für viele Fälle. Der Grund dafür ist, dass kleine schnelle Funktionen, die oft isoliert profiliert werden, sehr schnell laufen können, indem sie den CPU-Cache, Inlining und Enregistrierung nutzen. In großen Anwendungen sind diese Vorteile jedoch oft nicht vorhanden, weil diese schnellen Funktionen in einem bestimmten Kontext aufgerufen werden.
Ein Beispiel: Wenn man eine Funktion für eine Million Iterationen in einer engen Schleife ausführt, kann man feststellen, dass die Funktion in etwa 50 Nanosekunden ausgeführt wird. Wenn man sie dann mit dem oben gezeigten Framework ausführt, kann ihre Laufzeit plötzlich drastisch auf Mikrosekunden ansteigen, weil sie nicht mehr die Tatsache ausnutzen kann, dass sie den gesamten Prozessor - seine Register und Caches - für sich allein hat.