Teknik Makale

Delphi'de dürüst PDF load/save benchmark'ı: gürültü kapıları

PDF Library for Delphi için dürüst bir load/save benchmark'ı, LoadFromFile ile SaveToFile'i QueryPerformanceCounter ile ölçer, ham tik sayılarını ve sayaç frekansını saklar, baseline ile adayı A/B, B/A, A/B sırasında dönüşümlü çiftler hâlinde çalıştırır, CPU yükü %25'in üzerindeyken başlamayı reddeder, range/median yayılımı %15'i aşan her sonucu eler ve kaydettiği PDF yapısal, render ya da anlamsal doğrulamadan geçmeyen her ölçümü çöpe atar. Bu liste bürokrasi gibi okunur; ta ki bir "20% daha hızlı" iddiası tekrar çalıştırmada buharlaşana kadar. Aşağısı, özel corpus probe'unun ve karşılaştırma runner'ının buraya nasıl geldiğidir; makinenin her şeyi ölçemeyecek kadar meşgul olduğu ve düzeneğin bunu doğru bildirdiği çalıştırma dahil

Delphi PDF benchmark'ı neden sıfır saniye bildirir?

PDF load benchmark'ı, saati ölçtüğü işlemden daha kaba tik attığında sıfır saniye bildirir; GetTickCount64 tam da bu tür bir saattir: milisaniye döndürür ama Windows'ta yalnızca sistem zamanlayıcı kesmesi tetiklendiğinde ilerler, ki bu genelde her 15,6 ms'de bir olur. PDF Library for Delphi'deki dev dosya benchmark demosunun FPC portu onu kullandı, çünkü TStopwatch o araç zincirinde mevcut değil ve geçen süreyi üç ondalık basamakla kaydediyor. Küçük bir CAD çizimini ya da kısa bir etiketli belgeyi yüklemek bir zamanlayıcı adımının iyice içinde biter; demo bu yüzden açıkça gerçek iş yapan bir yük için bazen 0.000 basıyordu

function ElapsedSeconds(StartTick: QWord): Double;
begin
  Result:= (GetTickCount64- StartTick)/ 1000.0;
end;

// işlem döngüsünün içinde
Lib:= TPDFlib.Create;
try
  Lib.OnProgress:= Reporter.Progress;
  Started:= GetTickCount64;
  LoadCode:= Lib.LoadFromFile(InputFile, Password);
  ...

Sıfır, kesin olmayan bir sayıdan da kötüdür, çünkü üzerine kurduğunuz her karşılaştırma ona böler. Eşleştirilmiş karşılaştırma runner'ı, minimumu sıfır olan her kolu "Sıfır süre anlamlı bir oran engeller" gerekçesiyle sonuçsuz sayar; bu doğru bir reddediştir ama aynı zamanda demo ölçümlerinin tam da kısa dosyaların yaşadığı yerde bir ölçüm boşluğu bıraktığı anlamına gelir. Aynı demo bir OnProgress callback'i de kurar; ölçümleri böylece temiz bir load/save ölçümünün taşıması gerekmeyen callback yükünü içerir ve arşivlenmiş demo sayıları daha sonra ölçülen hiçbir şeyle takas edilemez

LoadFromFile ve SaveToFile'ı QueryPerformanceCounter ile ölçmek

Özel konsol probe'u olan Tests/CorpusLoadSave.dpr, QueryPerformanceCounter ile her girdi dosyası için iki işlemi ölçer: LoadFromFile artı PageCount okuma, ve LoadFromFile artı PageCount artı SaveToFile. Her işlem taze bir TPDFlib örneği alır ve hiçbir progress callback'i kullanmaz; örneğin constructor'ı ve destructor'ı ölçülen bölgenin dışında durur, CSV yazımı ve tüm çıktı doğrulaması da öyle. Sayaç, yüklemeden hemen önce ve son kütüphane çağrısından hemen sonra okunur; LastErrorCode yalnızca ikinci okumadan sonra alınır

PDFlibPas corpus probe'unun ölçülen bölgesi: QueryPerformanceCounter LoadFromFile'dan hemen önce ve son kütüphane çağrısından sonra okunur, PageCount ve SaveToFile içeridedir; örneğin kurulumu, CSV yazımı, çıktı doğrulaması ve hata kodu alımı ölçülen bölgenin dışında kalır
Ham tikler ve sayaç frekansı, türetilen saniyelerin yanına kaydedilir; böylece saniyede on milyon tikle 8.888 tikte yüklenen bir CAD çizimi sıfıra yuvarlanmak yerine gerçek veri olarak korunur
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');

Probe, ham tik sayısını ve sayaç frekansını türetilen saniyelerin yanına yazar; dokuz ondalık basamakla ve sabit . ondalık ayracıyla biçimlendirir, böylece herkes bölüme körü körüne güvenmek yerine onu CSV'den yeniden hesaplayabilir. FPC Win64 derlemesinde CAD örneği saniyede 10.000.000 tikle 8.888 tikte yüklendi ve 0.000888800 saniye olarak kaydedildi — eski zamanlayıcının sıfıra yuvarlayacağı bir gözlem. Probe kısa değerleri bilinçli olarak kırpmaz, en az bir süre ikame etmez ya da tahmini zamanlayıcı yükünü düşmez ve bir kütüphane çağrısı başarısız olduğunda sıfır olmayan çıkış koduyla her iki satırı da yazmaya devam eder. Ama dokuz basamak doğruluk demek değildir: kaydedilen daha fazla hassasiyet tekrarlanabilirlik hakkında hiçbir şey söylemez ve gürültülü ya da sıfır gözlemlerin aşağı akışta yine reddedilmesi gerekir

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));

Bir PDF load/save süre karşılaştırmasını güvenilir yapan nedir?

PDF Library for Delphi'nin iki derlemesi arasındaki süre karşılaştırması, yalnızca başlangıç sırası, başlangıç koşulları ve yayılımın hepsi denetlenip kaydedildiğinde güvenilirdir; karşılaştırma runner'ı bu yüzden en az üç çifti A/B, B/A, A/B sırasında planlar. Baseline'ı her zaman önce çalıştırmak adayına sessizce daha sıcak bir dosya önbelleği ve farklı bir ısıl durum devreder; sırayı dönüşümlü yapmak bu yanlılığı tek kola yazmak yerine iki kola da yayar. Runner her koldan önce tam girdi dosyasını SHA-256 ile hash'ler; bu hem hiçbir şeyin değişmediğini doğrular hem de her iki kol için aynı baytları önceden okur, ayrıca her çalıştırmadan sonra iki çalıştırılabilir ile doğrulama araçlarını yeniden hash'ler, böylece yeniden derlenmiş bir ikili seri ortasına süzülemaz

Runner ardından makine genelindeki CPU kullanımını saniyede bir örnekler ve bir örnek %25'e ya da altına düştüğünde kolu başlatır; denemeyi reddedilmiş olarak kaydetmeden önce en çok 30 saniye bekler. O kapı başlangıç koşulunu denetler ve başka hiçbir şeyi: çalıştırma sırasında makineyi yalıtmaz; güç durumu, ısıl kısma, arka plan işi ve OS önbelleği sayıları hâlâ oynatabilir. Bu yüzden ikinci filtre en yalın hâliyle istatistiktir. Runner her işlem için baseline kolu, aday kolu ve eşleştirilmiş aday/baseline oranlarının dağılımı üzerinden range'in medyana bölümünü hesaplar ve üçünden herhangi biri 0,15'i aşarsa sonuç bulgu olarak bildirilmek yerine gürültülü etiketi alır

PDFlibPas'ta eşleştirilmiş karşılaştırma kapıları: üç çift A/B, B/A, A/B sırasında, her koldan önce SHA-256 girdi hash'i ile çalışır; başlangıç kapısı CPU'nun %25 ve altına inmesini bekler ve LoadFromFile ya da load artı SaveToFile kolunda 0,15 üzeri range/median yayılımı çalıştırmayı gürültülü etiketler
Başlangıç sırasını dönüşümlü yapmak önbellek ve ısıl yanlılığı iki kola da yayar; aynı ikili kontrol böyle bir düzeneğin kanıtlayabileceğini gösterir: 1,0 civarı oranlar tekrarlanabilirliği kurar, asla hızlanma iddiası değil

Aynı ikili kontrol neden hızı değil tekrarlanabilirliği kanıtlar?

Aynı ikili kontrol, baseline ve aday olarak özdeş çalıştırılabilirleri koşar; 1,0 civarı bir oran yalnızca ölçüm düzeneğinin kendini tekrarladığını kanıtlar, bir uygulamanın hızlandığını asla gösteremez. 2026-09-21'deki ilk sıkı kontrol, kabul edilmiş 70 sayfalık etiketli bir rehbere karşı yüksek çözünürlüklü FPC Win64 probe'unu kullandı ve altı başlangıcın tamamı reddedildi, çünkü CPU örnekleri %26,5 ile %93,8 arasında salınıyordu. Rapor başarısızlıklar içeriyordu, toplamlar değil; makine meşgulken istediğiniz sonuç tam olarak budur. Aynı gün içinde, bayt özdeş girdilerle, aynı probe çalıştırılabiliriyle ve değişmemiş eşiklerle yapılan yeniden deneme altı başlangıcın tamamını 3 saniye içinde kabul etti; her range/median yayılımı 0,019 ile 0,054 arasında kaldı ve oran medyanları LoadFromFile için 1,0084, LoadFromFile + SaveToFile için 0,9872 oldu

O sayı çifti nitelikli bir gözlem penceresi kurar ve başka bir şey kurmaz. İki ikili farklı olduğunda, sağlam bir çalıştırma betimsel karşılaştırma etiketi alır; oranların gözlem olduğuna, istatistiksel anlamlılık ya da hızlanma iddiası olmadığına dair açık notla. Disiplin en çok, PDF Library for Delphi'yi profilleyip sıcak yolları hash indeksleriyle değiştirmek yazısında anlatılan türden hedefli iyileştirmeleri doğrularken önemlidir: profiler zamanın nereye gittiğini söyler ama değişikliğin tüm hattıyla teması atlattığını yalnızca gerçek belgeler üzerinde denetimli eşleştirilmiş bir çalıştırma söyler. Bir sınırı daha yüksek sesle söylemek gerek — normal-save yüklemeyi içerir ve runner'ın kaydettiği tepe working set süreç genişindedir; dolayısıyla hiçbiri yalnızca kaydetmeye atfedilebilir bellek değildir

Üç çıkış kapısı ve dört derleyicilik matris

Ürettiği dosya üç bağımsız kapıdan geçmediği sürece hiçbir PDF Library for Delphi ölçümü sayılmaz, çünkü bozuk bir PDF'i hızlı yazan bir save daha hızlı bir save değildir. Benchmark önce her iki işlemin de 1 döndürdüğünü ve kabul edilmiş sayfa sayısını bildirdiğini kontrol eder, sonra kaydedilen tek PDF'i bu sırayla doğrular:

PDFlibPas'ta üç çıkış kapısı: her iki işlem 1 döndürmeli ve kabul edilmiş PageCount'u bildirmeli, bağımsız bir checker kaydedilen dosyayı uyarısız geçmeli, her sayfa kaynağın sayfa başına görüntü SHA-256 kümesiyle eşleşen render üretmeli ve görsel olmayan anlamsallık optional content ve measurement yapılarında eşleşmeli
Bozuk bir PDF'i hızlı yazan save daha hızlı bir save değildir; bir ölçüm yalnızca yapı, render ve görsel olmayan anlamsallığın hepsi çıktının hâlâ aynı belge olduğu konusunda hemfikir olduğunda sayar
  • Yapı: bağımsız bir PDF checker kaydedilen dosyayı hatasız ve uyarısız geçmeli
  • Render: her sayfa varsayılan durumunda render edilir ve sayfa başına görüntü SHA-256 kümesi kabul edilmiş kaynağın referans render'ıyla tam olarak eşleşmeli
  • Görsel olmayan anlamsallık: kaynağa karşı ayrı bir anlamsal karşılaştırma, piksellerin gösteremeyeceği seçilmiş özellikleri kapsar; belgelenmiş kapsamları içindeki optional-content ve measurement yapıları dahil

Bu kapılar yerindeyken tam yerel corpus matrisi, 1.612 kaynak sayfalı 12 kabul edilmiş PDF üzerinde probe'u FPC Win32, FPC Win64, Delphi Win32 ve Delphi Win64'te çalıştırdı; 48 örnek/hedef çifti ve seçilmiş hiçbir anlamsal farkı olmayan 6.448 doğrulanmış çıktı sayfası verdi. 96 işlem ölçümünün tamamı, bildirdikleri saniyelerle tutarlı pozitif ham sayaç değerlerini korudu ve bu değerler bilinçli olarak derleyiciler arası bir hız tablosuna toplanmadı, çünkü matris denetimli bir karşılaştırma değil işlevsel kanıttır. Load/save yolu ayrıca her gömülü görüntüyü çözdüğünü, imzaları doğruladığını, XFA çalıştırdığını ya da PDF/UA sertifikaladığını iddia etmez; load/save maliyeti değil render verimini yargılamanız gerekiyorsa, PDF Library for Delphi'de paralel sayfa render'ı ve thread safety içindeki eşzamanlılık kısıtları daha iyi bir başlangıç noktasıdır

Pratik çıkarım kısa: ham sayaçları saklayın, sırayı dönüşümlü yapın, başlangıcı kapılayın, gürültülü yayılımları reddedin ve doğrulamadığınız hiçbir çıktıyı ölçmeyin. PDF Library for Delphi'nin "daha hızlı" demek kadar güvenle "ölçülebilir değişiklik yok" diyebilmesini sağlayan kurallar bunlar; ve aynı probe kaynağı değişmeden Delphi ve FPC'de Win32 ve Win64 için derlenir. Kütüphaneyi, load/save API'sini ve desteklenen derleyicileri PDF Library for Delphi ürün sayfasında inceleyebilirsiniz