Iskren load/save benchmark za PDF Library for Delphi mjeri LoadFromFile i SaveToFile s QueryPerformanceCounterom, čuva sirove tickove i frekvenciju brojača, pokreće baseline i kandidata u izmjeničnim parovima A/B, B/A, A/B, odbija se pokrenuti dok je opterećenje CPU-a iznad 25%, odbacuje svaki rezultat čiji omjer raspona i medijana prelazi 15%, i baca svako mjerenje čiji spremljeni PDF padne strukturnu, render ili semantičku validaciju. Ta lista zvuči kao birokracija dok se prva "20% brže" tvrdnja ne raspari pri ponovnom mjerenju. Slijedi kako je do toga došla namjenska korpusna sonda i njezin comparison runner, uključujući i run u kojem je stroj bio jednostavno prezauzet da bi se što izmjerilo, pa je to harness i ispravno rekao
Zašto Delphi PDF benchmark javlja nula sekundi?
PDF load benchmark javlja nula sekundi kad njegov sat kuca grublje od operacije koju mjeri, a GetTickCount64 je upravo takav sat: vraća milisekunde, ali na Windowsima napreduje samo kad se okine prekid sistemskog timera, obično svakih 15.6 ms. FPC port demo programa za benchmark ogromnih datoteka u PDF Library for Delphi koristio ga je jer TStopwatch nije dostupan u tom toolchainu, i vrijeme je zapisivao na tri decimale. Učitavanje malog CAD crteža ili kratkog tagged dokumenta završi daleko unutar jednog timer koraka, pa je demo ponekad ispisivao 0.000 za učitavanje koje je očito obavilo pravi posao
function ElapsedSeconds(StartTick: QWord): Double;
begin
Result:= (GetTickCount64- StartTick)/ 1000.0;
end;
// unutar petlje operacije
Lib:= TPDFlib.Create;
try
Lib.OnProgress:= Reporter.Progress;
Started:= GetTickCount64;
LoadCode:= Lib.LoadFromFile(InputFile, Password);
...
Nula je gora od nepreciznog broja, jer se svaka usporedba koju na njoj sagradite dijeli s njom. Upareni comparison runner svaki krak čiji je minimum nula tretira kao inconclusive, s razlogom "Zero duration prevents a meaningful ratio", što je ispravan odbitak, ali znači i da su demo mjerenja ostavila prazninu točno tamo gdje žive kratke datoteke. Isti demo ugrađuje i OnProgress callback, pa njegova mjerenja nose i trošak callbacka koji čisto load/save mjerenje ne bi smjelo nositi, i arhivirani demo brojevi nisu zamjenjivi s ičim što se izmjeri kasnije
Mjerenje LoadFromFile i SaveToFile uz QueryPerformanceCounter
Namjenska konzolna sonda, Tests/CorpusLoadSave.dpr, mjeri dvije operacije po ulaznoj datoteci s QueryPerformanceCounterom: LoadFromFile plus čitanje PageCount, i LoadFromFile plus PageCount plus SaveToFile. Svaka operacija dobiva svježu TPDFlib instancu i ide bez progress callbacka, a konstruktor i destruktor instance stoje izvan mjerenog područja, kao i CSV ispis i sva validacija izlaza. Brojač se čita neposredno prije učitavanja i neposredno nakon zadnjeg poziva biblioteci, a LastErrorCode se dohvaća tek nakon drugog očitanja
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');
Sonda zapisuje sirovi broj tickova i frekvenciju brojača uz izvedene sekunde, formatirane s devet decimala i fiksnom . decimalnom točkom, pa svatko može izračunati kvocijent iz CSV-a umjesto da mu vjeruje. Na FPC Win64 buildu uzorak CAD-a učitao se u 8.888 tickova pri 10.000.000 tickova u sekundi, zapisano kao 0.000888800 sekundi — zapažanje koje bi stari timer zaokružio na nulu. Sonda namjerno ne odsec kratke vrijednosti, ne zamjenjuje ih minimalnim trajanjem ni ne oduzima procijenjeni timer overhead, i i dalje zapisuje oba retka s ne-nultim exit codeom kad poziv biblioteci padne. Devet znamenki ipak nije točnost: više zapisane preciznosti ne govori ništa o ponovljivosti, a bučna ili nulta zapažanja i dalje treba odbaciti nizvodno
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));
Što usporedbu Load/Save vremena PDF-a čini pouzdanom?
Usporedba vremena između dva builda PDF Library for Delphi pouzdana je samo kad su redoslijed pokretanja, uvjeti pokretanja i raspon svi kontrolirani i zabilježeni, pa comparison runner raspoređuje najmanje tri para u redoslijedu A/B, B/A, A/B. Uvijek pokrenut baseline prvi tiho poklanja kandidatu topliji file cache i drugačije termičko stanje; izmjenični redoslijed tu pristrasnost raspršuje na oba kraka umjesto da je pripše jednome. Prije svakog kraka runner računa SHA-256 hash cijele ulazne datoteke, što i potvrđuje da se ništa nije promijenilo i prečita iste bajtove za oba kraka, a nakon svakog runa opet hashira dva executiva i validacijske alate da iznova buildana binarna datoteka ne bi potkrala usred serije
Runner zatim jednom u sekundi uzorkuje iskorištenost CPU-a cijelog stroja i krak pokreće samo kad uzorak padne na 25% ili ispod, čekajući najviše 30 sekundi prije nego pokušaj zapiše kao odbijen. Taj gate kontrolira uvjet pokretanja i ništa drugo: ne izolira stroj tijekom runa, a stanje napajanja, thermal throttling, posao u pozadini i OS caching i dalje mogu micati brojeve. Zato je drugi filter statistički u najobičnijem smislu. Za svaku operaciju runner računa raspon podijeljen s medijanom za baseline krak, kandidat krak i raspodjelu uparenih kandidat/baseline omjera, i ako bilo koji od tri pređe 0.15, rezultat se označava kao noisy umjesto da se javi kao nalaz
Zašto kontrola s identičnim executivima dokazuje ponovljivost, a ne brzinu?
Kontrola s identičnim executivima pokreće iste izvršne datoteke kao baseline i kandidata, pa omjer blizu 1.0 može dokazati samo da se postav mjerenja ponavlja; nikad ne može pokazati da je neka implementacija postala brža. Prva stroga kontrola 2026-09-21 koristila je high-resolution FPC Win64 sondu nad prihvaćenim tagged vodičem od 70 stranica, i svih šest pokretanja odbijeno je jer su CPU uzorci bili od 26.5% do 93.8%. Izvještaj je sadržavao padove i nijedan agregat, što je točno ishod koji želite kad je stroj zauzet. Istodnevni pokušaj s byte-identičnim ulazima, istom izvršnom datotekom sonde i nepromijenjenim pragovima primio je svih šest pokretanja u roku od 3 sekunde; svaki raspon prema medijanu pao je između 0.019 i 0.054, a medijani omjera bili su 1.0084 za LoadFromFile i 0.9872 za LoadFromFile + SaveToFile
Par tih brojeva utemeljuje kvalificirani prozor promatranja i ništa više. Kad se dva executiva razlikuju, stabilan run označava se kao deskriptivna usporedba, uz izričitu napomenu da su omjeri zapažanja, a ne statistička značajnost ni tvrdnja o ubrzanju. Ta disciplina najviše znači kad validirate ciljane optimizacije poput onih opisanih u članku o profilingu PDF Library for Delphi i zamjeni hot putanja hash indeksima: profiler vam kaže kamo odlazi vrijeme, ali vam samo kontrolirani upareni run na pravim dokumentima kaže je li promjena preživjela kontakt s cijelim cjevovodom. Još jedna granica vrijedna izgovaranja na glas — normal-save uključuje učitavanje, a peak working set koji runner zabilježi mjeri se na razini procesa, pa nijedan dio nije memorija koja se može pripisati samom spremanju
Tri izlazna gatea i matrica četiri kompajlera
Nijedno mjerenje PDF Library for Delphi ne vrijedi ako datoteka koju je proizvelo ne prođe tri nezavisna gatea, jer spremanje koje brzo napiše pokvareni PDF nije brže spremanje. Benchmark prvo provjerava da su obje operacije vratile 1 i javile prihvaćeni broj stranica, pa validira jedini spremljeni PDF ovim redoslijedom:
- Struktura: nezavisni PDF checker mora proći spremljenu datoteku bez grešaka i upozorenja
- Renderiranje: svaka stranica renderira se u svom zadanom stanju, a skup po-straničnih image SHA-256 mora se točno podudarati s referentnim renderiranjem prihvaćenog izvora
- Nevidljiva semantika: zasebna semantička usporedba s izvorom pokriva odabrana svojstva koja pikseli ne mogu pokazati, uključujući optional-content i mjerne strukture unutar njihova dokumentiranog opsega
S tim gateovima na mjestu, puna lokalna korpusna matrica pokrenula je sondu na FPC Win32, FPC Win64, Delphi Win32 i Delphi Win64 nad 12 prihvaćenih PDF-ova s 1.612 izvornih stranica, dajući 48 sample/target parova i 6.448 validiranih izlaznih stranica bez ijedne odabrane semantičke razlike. Svih 96 mjerenja operacija zadržalo je pozitivne sirove vrijednosti brojača usklađene s javljenim sekundama, a te se vrijednosti namjerno ne agregiraju u cross-compiler tablicu brzina, jer je matrica funkcionalni dokaz, a ne kontrolirana usporedba. Load/save putanja također ne tvrdi da dekodira svaku ugrađenu sliku, validira potpise, izvršava XFA ili certificira PDF/UA; ako trebate suditi o propusnosti renderiranja, a ne o trošku load/save-a, bolja je početna točka ograničenja paralelnosti iz članka o paralelnom renderiranju stranica i thread safety u PDF Library for Delphi
Praktičan zaključak je kratak: čuvajte sirove brojače, mijenjajte redoslijed, gate-ujte start, odbijajte noisy raspone i nikad ne mjerite izlaz koji niste validirali. Ta pravila su ono što PDF Library for Delphi čini sposobnom da kaže "nema izmjerene promjene" s istom sigurnošću kao "brže", a isti se izvorni kod sonde bez izmjena kompajlira na Delphiju i FPC-u za Win32 i Win64. Biblioteku, njezin load/save API i podržane kompajlere možete pregledati na stranici proizvoda PDF Library for Delphi