AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Delphi und NUMA-Nodes

Ein Thema von noob2k9 · begonnen am 2. Sep 2019 · letzter Beitrag vom 5. Sep 2019
Antwort Antwort
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
Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: Unterhaching
11.412 Beiträge
 
Delphi 12 Athens
 
#2

AW: Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 11:13
Kurze Frage vorab, musst Du erkennen, was sich bewegt (also Objekterkennung), oder lediglich, OB sich etwas bewegt? Ähnlich wie Alarmsysteme? Wenn Letzteres, dann Qualität runter setzen, in B/W mittels Threshold-Value umwandeln und Bilder gegeneinander vergleichen. Das hat unseren Anforderungen damals völlig genügt und ist extrem schnell gewesen, mehrere 100 Vergleiche / Sekunde. Und wenn dann doch noch eine Objekterkennung erfolgen muss, dann kann diese in den entsprechenden Situationen immer noch getätigt werden.

Des Weiteren empfehle ich Dir die Bibliothek ImageEN von (damals) HiComponents zu testen, die Routinen waren bisher die besten zur Bild- und Videoverarbeitung in Delphi.

......
Daniel Lizbeth
Ich bin nicht zurück, ich tue nur so
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.144 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 12:59
WOW... Na das ist doch mal eine detaillierte Frage...

Mit 2x Intel Xeon E3-2670 hast Du zwar genug Threads für 33 Cam's, hast Du es trotzdem mal mit 11 statischen Threads versucht und einer Queue?
ggf. auch je Thread einen statischen Speicher zu reservieren und diese nicht jedes mal zu erzeugen und wieder freizugeben?

Server und Virtualisierung ist das eine, ggf. könnte man den Server eine entsprechende Grafikkarte gönnen und zahlreiche Berechnungen auf der GPU machen.
GGf. ohne die Virtualisierung.

Grüsse Mavarik
  Mit Zitat antworten Zitat
noob2k9

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

AW: Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 21:42
Ich muss nur erkennen, dass sich etwas bewegt und in welche Richtung es sich bewegt.
Dazu sind je nach Bedarf auf dem Boden Streifen- und Schachbrettmuster aufgebracht wodurch die Aufgabe recht trivial wird.

Die Reduzierung der JPEG-Qualität hat nur geringfügig Einfluss auf den Download und das Dekodieren. Bei noch halbwegs brauchbarer Qualität halbiert sich die Dateigröße. Die Zeiteinsparung liegt jedoch bei lediglich ~5%. Dabei ist aufgefallen, dass die Kamera zwar auf Graustufen eingestellt ist, jedoch wird dennoch ein Farb-JPEG übermittelt (nur eben monochrom). Dadurch entsteht vermutlich unnötig Overhead beim Dekodieren, aber dass kann ich nicht beeinflussen ohne die Kameras zu ersetzen.

Beim detaillierten Logging hat sich nun herausgestellt, dass der Zeitanteil der Speicherzugriffe und -verschiebungen lediglich einen Bruchteil der Gesamtzeit ausmacht - der Löwenanteil geht auf Konto des Jpeg-Decoders. Ich werde hie rnochmal libJpeg versuchen.

Vorher werde ich noch einen Benchmark durchführen und die Zahl der parallelen Threads variieren. Die 2 CPUs haben jeweils 8 Cores, 16 Threads (logische Prozessoren). Ich vermute in den häufigen Kontextwechseln das Bottleneck, so dass 16 parallele Threads (Anwendung) - jeweils verteilt auf 1 Core / 2 logische Prozessoren - optimal sein könnten.

---

Der Speicher den ich zum Austausch zwischen den Prozessen verwende ist statisch. Der Input ist dynamisch, die 300kB sind jedoch in <1ms verschoben.
Die Anwendung wird gerade auf ThreadPools umgestellt, dass hat dann auch gleich den Vorteil, dass man problemlos wieder zurück auf eine feste Zuordnungen gehen kann.
Ich glaube nicht, dass eine zusätzliche GPU hier sinnvoll ist - was soll auf dieser berechnet werden? Das verschieben der Daten in den Speicher der GPU über eine relativ langsame Anbindung dauert dann ja länger als es direkt auf der CPU zu erledigen.

Die reine Bildverarbeitung dauert nichtmal 5ms, das Bildformat ist recht simpel: ein einfacher Bytestream zu dem die Breite und Höhe des Bildes gespeichert wird. Die Pixel werden als Graustufen / 1 Byte gespeichert.
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 22:02
Besteht die Möglichkeit, dem Decoder zu sagen: Dekoriere nur die Y-Plane und ignoriere U- und V-Komponente?
  Mit Zitat antworten Zitat
noob2k9

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

AW: Delphi und NUMA-Nodes

  Alt 2. Sep 2019, 23:59
Besteht die Möglichkeit, dem Decoder zu sagen: Dekoriere nur die Y-Plane und ignoriere U- und V-Komponente?
Leider nein, ich werde morgen jedoch libJpeg integrieren - evtl. gibt es dort die Möglichkeit dies zu konfigurieren.



Der Benchmark hat gezeigt, dass die eingesetzte Bibliothek nicht skaliert - zumindest nicht so wie sie derzeit konfiguriert und kompiliert ist.
An den Affinitäten und Prioritäten wurde nichts verändert... keine feste Zuordnung von Threads zu Prozessoren oder NUMA-Knoten.

Der Wert gibt die Anzahl der dekodierten Jpegs / Minute an.

Mango (https://github.com/t0rakka/mango)
1: 696
2: 1002
4: 1204
8: 1207
16: 863
32: 784
64: 840
128: 824

nanoJpeg (http://www.emix8.org/static.php?page=nanoJpeg)
1: 415
2: 822
4: 1633
8: 3095
16: 5316
32: 7806
64: 7627
128: 7202

nanoJpeg ist nun nicht gerade für Performance bekannt, jedoch skaliert es wesentlich besser.
Bei 1-2 Threads hat Mango noch die Nase vorn, danach dreht sich das Bild gravierend um.
Mango kommt über 50%, scheint aber nicht an den NUMA-Knoten zu hängen da die Last über alle Threads verteilt wird.
nanoJpeg reizt ab 32 Threads volle 100% aus...

Ich werde den Test morgen mal mit der nativen Jpeg-Implementierung und libJpeg wiederholen
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Delphi und NUMA-Nodes

  Alt 4. Sep 2019, 14:03
Besteht die Möglichkeit, dem Decoder zu sagen: Dekoriere nur die Y-Plane und ignoriere U- und V-Komponente?
Leider nein, ich werde morgen jedoch libJpeg integrieren - evtl. gibt es dort die Möglichkeit dies zu konfigurieren.
Nutzt du die bisherige libjpeg oder die Turbo-Variante?
https://libjpeg-turbo.org/
https://github.com/libjpeg-turbo/libjpeg-turbo
  Mit Zitat antworten Zitat
noob2k9

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

AW: Delphi und NUMA-Nodes

  Alt 5. Sep 2019, 00:09
Besteht die Möglichkeit, dem Decoder zu sagen: Dekoriere nur die Y-Plane und ignoriere U- und V-Komponente?
Leider nein, ich werde morgen jedoch libJpeg integrieren - evtl. gibt es dort die Möglichkeit dies zu konfigurieren.
Nutzt du die bisherige libjpeg oder die Turbo-Variante?
https://libjpeg-turbo.org/
https://github.com/libjpeg-turbo/libjpeg-turbo
Ich habe jetzt libjpeg-turbo integriert, aktuellster Stand auf SF als Binary ist die Version 2.0.2. Die API scheint vollständig kompatibel zu sein. libjpeg-turbo ist jedoch auf dem Versionsstand 6.2b stehen geblieben (aktuell 9c), jedoch ist das kein Problem für mich. Die Performance ist gefühlt gut, Benchmark folgt.

Es scheint auch direkt die Möglichkeit zu geben den Farbraum festzulegen. Mit 8bit-Graustufen habe ich noch unschöne Effekte, welche ich weiter analysieren muss.

Es springt auch gleich Issue #325 "Provide memory manager overriding api" auf github ins Auge - ich scheine nicht allein zu sein mit diesem oder änhlichen Poblemen
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:54 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz