Einzelnen Beitrag anzeigen

noob2k9

Registriert seit: 1. Aug 2008
13 Beiträge
 
Delphi XE2 Starter
 
#1

Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 11:05
Hallo zusammen,

die Erfassung von Bildern und deren Verarbeitung auf einem Multi-Core-Server machen Probleme ...

Kurzbeschreibung des Projektes:
Laden von 33 Kamerabildern, umwandeln in Graustufen, Bewegungserkennung, Zählen der Bewegungen über eine externe Anwendung - TCP/IP-Schnittstelle.

Details:
Über HTTPS-Requests (Overbyte ICS) wird in variablen Zeitintervallen (alle 250-5000ms) das Bild von 33 IP-Kameras als JPEG-Datei abgerufen. Die Kameras benötigen hierfür im Schnitt 180ms + 70ms für den Transfer. Jede Kamera arbeitet in einem eigenen Thread (Affinität zu jeweils exakt einem Prozessor), ruft das Kamerabild ab und speichert den TMemoryStream direkt in einem "Framebuffer" (TList).

Anschließend wird das Bild dekodiert, in Graustufen umgewandelt und verarbeitet. Die Verarbeitung dauert ~200ms.
Die internen JPEG-Routinen waren zu langsam, jpegdec von Synopse unterstützt nur 32bit, libJPEG ist zu kompliziert (falls der Flaschenhals hier liegt wird noch ein Versuch gestartet), daher wird "mango" verwendet - als externe DLL (C++) kompiliert. Der Zugriff auf die Rohdaten (jpeg) erfolgt mittels Pointer auf den gespeicherten MemoryStream. Das Ergebnis (Graustufen-Bitmap) wird in einen Speicherbereich geschrieben, der ebenfalls als Pointer übergeben wurde.

Der Server ist mit 2x Intel Xeon E3-2670 v3 und ausreichend RAM bestückt und läuft unter einer ESXi-Virtualisierung (exklusive Nutzung für die Anwendung), das Betriebssystem ist ein Windows Server 2012 R2.

Als Memory Manager wird die aktuelle Version des FastMM4 genutzt. Andere wurden probiert, jedoch ohne wesentliche Verbesserung.

Problem:
Der Abruf der Bilddaten allein ist ausreichend performant. Alle 33 Kameras können die 4 Bilder / Sekunde stabil parallel liefern. Die I/O-Last auf dem Netzwerk liegt dabei bei ungefähr 400MBit/s. Evtl. stelle ich dies noch auf "Scheduling" um, da nur 2 Kameras die 4 Bilder / Sekunde liefern müssen, die restlichen reichen alle 1 - 5 Sekunden.

Wird nun die Bildverarbeitung aktiviert, dann steigt die Verarbeitungdauer auf ~650ms an. Der Download der Bilddaten dauert weiterhin ~250ms / Kamera.
Die CPU erreicht jedoch nie mehr als 55-60% Auslastung (laut Windows Task-Manager)

Vermutung:
Die Speicherzuweisungen für das Dekodieren der JPEG-Dateien dauern zu lang (Verschiebung zwischen den NUMA-Knoten).
Die Daten müssen mehrfach zwischen den 2 NUMA-Knoten verschben werden, was zeitintensiv ist und CPU-Leistung kostet. Die Anwendung verursacht sehr viele Pagefaults (> 1 Million in weniger als einer Minute). Verschiedene Kontextwechsel der Threads welche die CPU-Auslastung reduzieren.

Lösungsansätze:
  • Verringern der JPEG-Qualität um die Dekodierung zu beschleunigen - ist das wirklich der Flaschenhals?
  • manuelle Reservierung und Zuweisung der Speicherbereiche mittels VirtualAllocNumaEx beim Erstellen der Threads um sicherzustellen, dass der Speicherbereich im gleichen NUMA-Knoten liegt wie der verarbeitende Prozessor - gibt es einen Memory Manager für Delphi (auch als *.dll eingebunden), welcher die NUMA-Knoten berücksichtigt?
  • Ringpuffer direkt auf Basis des TMemoryStream statt TList<TMemoryStream> zum Zwischenspeichern der Bilddaten - das ist vermutlich nicht der Knackpunkt, die TList wird alle x Bilder aufgeräumt
  • Auslagerung der Bildverarbeitung in einen "ProcessingPool"
  • Logging erweitern um herauszufinden welche Codezeile(n) die meiste Zeit beanspruchen -> gibt es einen freien Sampling Profiler für 64bit? asmprofiler und gpProfiler scheint es nur für 32 bit zu geben - notfalls wird mit Log-Ausschriften gearbeitet...

---

Nun die Frage(n) in die Runde - ich erwarte keine pauschale odereinfache Lösung für mein Problem erwarte...
  • Habt ihr ähnliche Erfahrungen gemacht?
  • Wie seid ihr weiter vorgegangen und was war die Ursache / Lösung? (Delphi ist in dieser Form als Serveranwendung wohl eher ein Aussenseiter - jedoch dürfte das Problem unabhängig von der Programmiersprache sein)
  • Ist dies wirklich ein Indiz für den Wechsel zwischen den NUMA-Knoten
  • mögliche Ansätze zur weiteren Verbesserung der Performance und bessere Auslastung der CPU-Ressourcen
  Mit Zitat antworten Zitat