Egy korrekt load/save benchmark a PDF Library for Delphi számára a LoadFromFile-ot és a SaveToFile-ot QueryPerformanceCounter-rel méri, megőrzi a nyers tick-eket és a counter frekvenciáját, a baseline-t és a jelöltet váltakozó A/B, B/A, A/B párokban futtatja, nem indul el, amíg a CPU-terheltség 25% fölött van, elutasít minden eredményt, aminek a range-to-median szórása meghaladja a 15%-ot, és kidob minden időmérést, aminek a mentett PDF-je megbukik a szerkezeti, a renderelési vagy a szemantikai validáción. Ez a lista bürokráciának tűnik, amíg először el nem párolog egy „20%-kal gyorsabb" állítás egy újrafutáson. Az alábbiak az, hogyan jutott el ide a dedikált corpus-szonda és az összehasonlító futtatója, beleszámítva azt a futást is, amikor a gép egyszerűen túl elfoglalt volt bármi mérésére, és a harness helyesen mondta ki ezt
Miért jelent nulla másodpercet egy Delphi PDF-benchmark?
Egy PDF load-benchmark akkor jelent nulla másodpercet, amikor az órája durvábban ketyeg, mint az általa mért művelet, a GetTickCount64 pedig pontosan ilyen óra: ezredmásodperceket ad vissza, de Windowson csak akkor lép, amikor a rendszeridő-megszakítás elsül, ami jellemzően 15,6 ms-onként történik. A PDF Library for Delphi huge-file benchmark demójának FPC portja azért használta, mert TStopwatch nem érhető el abban a toolchainben, és három tizedesjegy pontossággal rögzíti az eltelt időt. Egy kis CAD-rajz vagy egy rövid tagged dokumentum betöltése jól belefér egy idősítő lépésbe, így a demo néha 0.000-t írt ki egy olyan betöltésre, ami nyilvánvalóan valódi munkát végzett
function ElapsedSeconds(StartTick: QWord): Double;
begin
Result:= (GetTickCount64- StartTick)/ 1000.0;
end;
// a műveleti cikluson belül
Lib:= TPDFlib.Create;
try
Lib.OnProgress:= Reporter.Progress;
Started:= GetTickCount64;
LoadCode:= Lib.LoadFromFile(InputFile, Password);
...
A nulla rosszabb egy pontatlan számnál, mert minden rá épített összehasonlítás vele oszt. A párosított összehasonlító futtató minden nulla minimumú ágat eredménytelennek tekint a „Zero duration prevents a meaningful ratio" indoklással, ami a helyes elutasítás, de azt is jelenti, hogy a demo időméresei éppen ott hagytak mérési rést, ahol a rövid fájlok élnek. Ugyanez a demo egy OnProgress callbacket is telepít, így az időméresei tartalmazzák a callback költségét, amit egy tiszta load/save mérés nem viselhet, és az archivált demo számok nem cserélhetők fel semmivel, amit később mértek
LoadFromFile és SaveToFile időmérése QueryPerformanceCounterrel
A dedikált konzolos szonda, a Tests/CorpusLoadSave.dpr, bemenetenként két műveletet mér QueryPerformanceCounter-rel: LoadFromFile plusz a PageCount kiolvasása, valamint LoadFromFile plusz PageCount plusz SaveToFile. Minden művelet friss TPDFlib instanciát kap és semmilyen progress callbacket, az instancia konstruktorát és destruktorát pedig a mért régión kívül hagyjuk, akárcsak a CSV-írást és az összes kimenetvalidációt. A counter közvetlenül a load előtt és közvetlenül az utolsó library-hívás után olvasódik, a LastErrorCode-t pedig csak a második olvasás után kérik le
Lib:= TPDFlib.Create;
try
if not QueryPerformanceCounter(Started) then
raise Exception.Create('Performance counter unavailable');
Code:= Lib.LoadFromFile(WideString(SourceFile), '');
if Code= 1 then
begin
Pages:= Lib.PageCount;
if Save then Code:= Lib.SaveToFile(WideString(SavedFile));
end;
if not QueryPerformanceCounter(Finished) then
raise Exception.Create('Performance counter unavailable');
ErrorCode:= Lib.LastErrorCode;
finally
Lib.Free;
end;
Ticks:= Finished- Started;
if Ticks< 0 then
raise Exception.Create('Performance counter moved backwards');
A szonda a nyers tick-számot és a counter frekvenciáját a leszámított másodpercek mellé írja, kilenc tizedesjeggyel és rögzített . tizedeselválasztóval formázva, így bárki újraszámolhatja a hányadost a CSV-ből ahelyett, hogy elhinné. Az FPC Win64 builden a CAD-minta 8 888 tick alatt töltött be, másodpercenként 10 000 000 tick mellett, 0.000888800 másodpercként rögzítve — egy olyan megfigyelés, amit a régi idősítő nullára kerekített volna. A szonda tudatosan nem csonkol rövid értékeket, nem helyettesít minimum időtartamot, és nem von le becsült timer költséget, valamint library-hívás hibája esetén is kiírja mindkét sort nemnulla kilépési kóddal. A kilenc számjegy viszont nem pontosság: a több rögzített tizedes semmit nem mond az ismételhetőségről, a zajos vagy nulla megfigyeléseket pedig továbbra is el kell utasítani a folyamat későbbi szakaszában
if not QueryPerformanceFrequency(Frequency) or (Frequency<= 0) then
raise Exception.Create('Performance counter frequency unavailable');
NumberFormat:= TFormatSettings.Create;
NumberFormat.DecimalSeparator:= '.';
...
Rows.Add(CSV(ExtractFileName(SourceFile))+ ','+ CSV(Operation)+ ','+
FormatFloat('0.000000000', Ticks/ Frequency, NumberFormat)+ ','+
IntToStr(Code)+ ','+ IntToStr(ErrorCode)+ ','+ IntToStr(Pages)+ ','+
IntToStr(Ticks)+ ','+ IntToStr(Frequency));
Mi tesz megbízhatóvá egy PDF load/save időmérés-összehasonlítást?
Egy időmérés-összehasonlítás a PDF Library for Delphi két buildje között csak akkor megbízható, ha az indítási sorrend, az indítási feltételek és a szórás is ellenőrzött és rögzített, ezért az összehasonlító futtató legalább három párt ütemez A/B, B/A, A/B sorrendben. Ha mindig először fut a baseline, az csendben melegebb fájlcache-et és más hőállapotot ad a jelöltnek; a sorrend váltogatása ezt a torzítást szétosztja a két ág között, ahelyett hogy egyiknek jóváírná. Minden ág előtt a futtató a teljes bemeneti fájlt SHA-256-tal hasheli, ami egyszerre ellenőrzi, hogy semmi nem változott, és előre beolvassa ugyanazokat a bájtokat mindkét ágnak, a két végrehajtható fájlt és a validációs eszközöket pedig minden futás után újra hasheli, hogy egy újrafortolt bináris ne csúzhasson be egy sorozat közepébe
A futtató ezután másodpercenként mintavételezi a gépszintű CPU-kihasználtságot, és csak akkor indítja az ágat, ha egy minta 25%-ra vagy alá esik, legfeljebb 30 másodpercet várva, mielőtt a kísérletet elutasítottként rögzítené. Ez a kapu az indítási feltételt szabályozza és semmi mást: nem izolálja a gépet a futás alatt, és a tápellátás állapota, a termikus throttlelés, a háttérmunka és az OS cache-elése továbbra is elmozdíthatja a számokat. Ezért a második szűrő a legegyértelműbb értelemben statisztikai. Minden műveletre a futtató kiszámolja a range osztva mediánnal a baseline ágra, a jelölt ágra és a párosított jelölt/baseline hányadosok eloszlására, és ha a három közül bármelyik meghaladja a 0,15-öt, az eredmény zajosként címkéződik ahelyett, hogy eredményként jelentenék
Miért az ismételhetőséget bizonyítja az azonos binárisú kontroll, nem a sebességet?
Az azonos binárisú kontroll azonos végrehajtható fájlokat futtat baseline-ként és jelöltként, így egy 1,0 közeli hányados csak azt bizonyíthatja, hogy a mérési felállás reprodukálja önmagát; soha nem mutathatja meg, hogy egy implementáció gyorsabb lett. Az első szigorú kontroll 2026-09-21-én a nagyfelbontású FPC Win64 szondát használta egy beismert, 70 oldalas tagged útmutatóra, és mind a hat indítás elutasításra került, mert a CPU-minták 26,5% és 93,8% között szórtak. A riport hibákat tartalmazott és semmilyen aggregátumot, ami pontosan az a kimenet, amit akkor akarsz, amikor a gép elfoglalt. Egy aznapi újrapróbálás bájtonként azonos bemenetekkel, ugyanazzal a szonda végrehajtható fájllal és változatlan küszöbökkel mind a hat indítást elfogadta 3 másodpercen belül; minden range-to-median szórás 0,019 és 0,054 közé esett, a hányadosmediánok pedig 1,0084 voltak a LoadFromFile-ra és 0,9872 a LoadFromFile + SaveToFile-ra
Ez a számpár egy képesített megfigyelési ablakot állít fel és semmi többet. Amikor a két bináris különbözik, egy stabil futás leíró összehasonlításként címkéződik, azzal az explicit megjegyzéssel, hogy a hányadosok megfigyelések, nem statisztikai szignifikancia vagy gyorsulási állítás. A fegyelem akkor számít a legjobban, amikor célzott optimalizációkat validálsz, mint amilyeneket a PDF Library for Delphi profilozása és a forró útvonalak hash indexekkel való kiváltása ír le: a profiler megmondja, hova megy az idő, de csak egy kontrollált páros futás valódi dokumentumokon mondja meg, hogy a változás túléli-e a teljes pipeline-dal való találkozást. Még egy határ, amit érdemes hangosan kimondani — a normal-save magában foglalja a betöltést, és a futtató által rögzített csúcs working set folyamatszintű, így egyetlen része sem kizárólag a mentésnek tulajdonítható memória
Három kimeneti kapu és egy négyfordítós mátrix
Egyetlen PDF Library for Delphi időmérés sem számít, hacsak az általa előállított fájl át nem megy három független kapun, mert egy gyors mentés, ami törött PDF-et ír, nem gyorsabb mentés. A benchmark először ellenőrzi, hogy mindkét művelet 1-et adott-e vissza és a beismert oldalszámot jelentette-e, majd ebben a sorrendben validálja az egyetlen mentett PDF-et:
- Struktúra: egy független PDF checkernek hibák és figyelmeztetések nélkül kell átmennie a mentett fájlon
- Renderelés: minden oldal alapállapotában renderelődik, és az oldalankénti image SHA-256 halmaznak pontosan egyeznie kell a beismert forrás referenciarenderelésével
- Nemvizuális szemantika: egy külön szemantikai összehasonlítás a forrással olyan kiválasztott tulajdonságokat fed le, amiket a pixelek nem mutatnak meg, beleértve az optional-content és a mérési struktúrákat a dokumentált hatókörükön belül
Ezekkel a kapukkal a teljes helyi corpus-mátrix FPC Win32-n, FPC Win64-en, Delphi Win32-n és Delphi Win64-en futtatta a szondát 12 beismert PDF-en 1 612 forrásoldallal, ami 48 minta/cél párt és 6 448 validált kimeneti oldalt adott kiválasztott szemantikai különbség nélkül. Mind a 96 műveletmérés pozitív nyers counter értékeket őrzött meg, konzisztensen a jelentett másodperceikkel, és ezeket az értékeket tudatosan nem aggregáljuk fordítóközi sebességtáblává, mert a mátrix funkcionális bizonyíték, nem kontrollált összehasonlítás. A load/save útvonal azt sem állítja, hogy minden beágyazott képet dekódolna, aláírásokat validálna, XFA-t futtatna vagy PDF/UA-t tanúsítana; ha a renderelési áteresztőképességet kell megítélned a load/save költség helyett, a párhuzamos oldalrenderelés és szálbiztonság a PDF Library for Delphi-ben cikkben lévő konkurencia-korlátok a jobb kiindulópont
A gyakorlati tanulság rövid: őrizd meg a nyers counter értékeket, váltogasd a sorrendet, kapuzd az indítást, utasítsd el a zajos szórásokat, és soha ne mérj olyan kimenetet, amit nem validáltál. Ezek a szabályok teszik lehetővé, hogy a PDF Library for Delphi ugyanolyan magabiztosan mondja ki, hogy „nincs mérhető változás", mint azt, hogy „gyorsabb", és ugyanez a szonda forrása változatlanul fordul Delphire és FPC-re Win32-n és Win64-en. A library, annak load/save API-ja és a támogatott fordítók áttekinthetők a PDF Library for Delphi termékoldalon