![]() |
QueryPerformanceCounter - Probleme, Zeitversatz
Hab heute mal wieder mein altes Proggie zum lesen von IF-Fernbedienungen rausgekramt, weil es da wieder was zu tun gibt.
Ist so was ähnliches wie WinLIRC - nur finde ich, dass es mir besser gelungen ist ... :oops: Vor gut 2 Jahren lief das noch einwadnfrei - u.a. Als FB-Empfänger auf meinem alten HTPC. Heute nur Stress, liefert überwiegend wirres Zeugs bei den Signal-Timings - sogar negative Werte ! Noch verrückter ist, dass es Sprünge/Versätze von gut 4-7 mS (in meinem Fall eine 'Ewigkeit') gibt. Lange Rede, kurzer Sinn - ich bin dank DP [eeeendlich] drauf gekommen ! Irgendwo hatte ich gelesen, das QueryPerformanceCounter Probleme macht mit MultiCore-CPU. Ein kurzer Klick im Taskmanager und schon ist Ruhe im Karton mit nur einer CPU ! Man kann das recht schön beobachten, wie mal für ein paar Signale CPU-1 verwendet wird und dann wieder CPU-2. Besagt Unterschied von ca. 4-7 mS muss wohl Zeitdifferenz zwischen den beiden CPU's liegen. Verstehen zue ich das nicht wirklich, weil der Apparat hier eigentlich die ganze Zeit schläft und AUslastung gegen 0 geht. Frage(n): Wie kann das ? Ich hatte damals beim proggen auch schon die gleiche Maschine und da fiel das nicht auf. Delphi 7 (ja ich weiß - Steinzeit. Für mich reichts alle male...) ist auch noch das gleiche. Gibt's da irgendeinen Patch, ne andere Lösung ? Falls nicht, wie kann ich dem Proggie sagen, das es nur 1 CPU nutzen soll ? Wäre dankbar für einige Tipps. |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Wie du deinem Programm sagen kannst, dass es nur 1 CPU verwenden soll? - Genauso wie TaskManager/ProzessExplorer das auch machen:
![]() Bernhard |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Mit dem richtigen Suchbegriff bin ich u. a. auch
![]() Sozusagen das gleiche Prob. .... und ![]() Irgendwie scheine ich im Moment aber zu dumm zum finden eines Codeschnipsel zu sein, mit dem ich das bewerkstelligen kann ... |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Nun ja, du brauchst ja nicht fiel zu wissen:
a) Dein Prozess-Handle und b) den/die Kern(e), auf denen dein Programm laufen soll. Wenn es nur auf einem laufen soll, empfiehlt sich, den ersten zu benutzen, da der eh immer da ist. Heißt also:
Delphi-Quellcode:
Bernhard
procedure TForm1.FormCreate(Sender: TObject);
begin SetProcessAffinity(GetProcessHandle(), 1); end; |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Na ja, ganz so einfach geht es auch nicht, aber ...
... hab mir ![]() Nun funzt das - wie mit per Hand eingestellt - wie die Wutz ! Wenn ich mal so die 'echten' Timings div. FB-Typen (Philips RC5/6, NEC, Sony, DBox) ansehe und mit meiner Leseroutine vergleiche, habe ich eine Abweichung von +/- max. 30µS (ja: Mükro !). Schon extrem gut. Nur scheint noch irgendwas anderes zu stören :roll: Starte ich meine DVB-App, geht das geeiere wieder los. Auch wenn ich beide auf verschiedene CPU's stelle. Ich betreibe den IR-Empänger übrigens an einem 'echten' COM-Port. Hab hier noch 2x COM-USB- Adapter, davon will aber keiner. DSR-Leitungen scheinen die wohl nicht zu supporten ... |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Du könntest auch statt QueryPerformanceCounter einen Multimedia-Timer verwenden. (
![]() ![]() Unter diesem Begriff werden verschiedene Timer/Zähler geführt, mit höheren Auflösungen arbeiten (z.B. für die Spiele, Musik oder Videos) Ganz kraß sah man sowas beim "Time Stamp Counter" ![]() Wobei inzwischen viele CPU-Hersteller diese Counter (leider) vom CPU-Takt trennen (bei dynamisch getakteten CPUs lief sowas auch noch unterschiedlich schnell, je nach CPU-Auslastung). |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Problem scheint wohl offensichtlich zu sein, dass alle (anderen) Timer zu langsam sind. :(
Ich muss schon eine Auflösung von max. ( ! ) 250 µS haben, um die Timings unterschiedlicher IR-FB-Typen noch so eben auflösen zu können. Mit Timer-Auflösungen >= 1 mS ist da leider (gar) nichts zu machen. Wie gesagt geht das mit dem QPC ganz hervorragend - wenn man die Anwendung auf einen Kern setzt. :-D Aber: Was tun, wenn das ganze in einer DLL / Plugin als Child in einem Programm läuft, was es von der Performance her 'nicht so witzig' finden würde, wenn man die CPU-Power beschränkt ? Ein Ansatz wäre, jedes mal beim Auslesen des Counters die CPU definiert zu setzen und dann gleich wieder zurück zu setzen. Oder halt so lange auf einer CPU 'sitzen' zu bleiben, bis das FB-Signal fertig gelesen ist.... Irgendwie kann ich mir vorstellen, dass das z.B. bei DVB-Anwendungen mit HD-Signal oder anderen Power-Intensiven Anwendung doch sicher zum stottern im Bildfluß führen wird - also sicher nicht die pralle Lösung. :roll: 2. Idee wäre, das ganze in einen Thread zu packen und diesen dann definiert einer CPU zuzuweisen - mit ggf. dann höchster gesetzter Priorität. :cyclops: Könnte mir vorstellen, dass das geht - aber wie ? Ich bin da nicht so der Held .... Jemand vielleicht noch ne andere Idee ? PS: ![]() Nur leider auch noch keine Lösung ... PS-2: Der in v.g. Fred beannte MS-Artikel ist jetzt ![]() ... ich studiere ihn gerade ... |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Ich finde eine Hardwarelösung mit Microcontroller besser.
![]() ![]() Wenn man alles von einer CPU (Desktop, Notebook) machen lässt, stellt man früher oder später fest, dass eine betriebssystemunabhängige Lösung besser ist. Die IR-Auswertung (vor allem die Loops) treiben die CPU-Last nach oben. Offtopic: Das beste Beispiel ist ein Satelliten-Empfänger (DVB-S) mit PVR-Funktion. Die eingebaute HDD funktioniert fehlerfrei, aber eine USB-HDD blockiert die ganze Bedieneinheit: Das Gerät funktioniert nicht direkt auf Befehle (oder nur zufällig): - kurz nach dem Einschalten, weil dann die USB-HDD gesucht und gelesen wird - beim Abspielen von Aufzeichnungen von der USB-HDD |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Einige Mainboards haben sogar schon einen IR-Empfänger an Board (oftmals fehlt nur noch die Empfängerdiode :stupid: ) ... ein Blick ins Handbuch des Boards kann das klären.
Zitat:
|
AW: QueryPerformanceCounter - Probleme, Zeitversatz
delete
|
AW: QueryPerformanceCounter - Probleme, Zeitversatz
@himitsu
A) Die in PC's verfügbaren IR's sind alle vom Typ IRDA und für Datenverbindungen z.B. zu einem PDA o.ä. Für 'normale FB's mit 35-36KHz Modulation nicht zu verwenden. B) Über die Sache mit den Threads denke ich nach - leider im Büro keine Chance :? @hathor Ob eine Hardwarelösung so viel besser ist ? Zum einen kostet sie extra um zum anderen muss der PC auch wieder irgendwo 'zuhören', wenn der kleine Bruder spricht. Ich lasse mir auch nur nen Event vom COM-Port auf DSR geben und lese max 80mS (via erst dann gestartetem Timer) Daten, die da kommen (können). Da gibt es keine Dauer-Loop mit Sleeps oder sonstigen Schwachfug. Ich hab mein FB-Tool mal wieder ausgebuddelt, weil ich genau an einem solchen HTPC wieder weiterarbeiten muss (!). Hatte mir damals mal nen Topfield TF 7700 PVR gegönnt und dachte, mit dem passenden Image (AAC MME) ist das sicher besser als mein WinDoof-Gebastel (in einem jedoch sehr schicken Gehäuse). Falsch gedacht ! Mit dem Pinguin komme ich nicht klar und das, was ich haben will, geht mit dem Topf (zunächst) nicht. Also alles noch mal neu überarbeitet und diesmal richtig. Als DVB-App verwende ich neben DVBDream übrigens meine eigene Kreation. Geht gut. Zum OnlineTV-Zeitung lesen nehme ich den TV-Browser und zum Filme gucken wurde VLC adaptiert/implementiert. Das alles kann ich über eine einzige (egal welche) FB aus dem Sofa steuern. Nur wenn es da schon mit der Auswertung der FB hapert .... aber auch das bekomme ich (mit eurer Hilfe =!) sicher hin. |
AW: QueryPerformanceCounter - Probleme, Zeitversatz
Da ich wirklich nicht der Held in Sachen Threads bin, brauche ich eure (kleine) Unterstützung.
Zum Verständnis, wie es in meinen FB-Tool 'abgeht', hier mal die relevanten Codeschnipsel, wie im Normalfall bei erkannter und angelernter FB:
Delphi-Quellcode:
'FormCreate' arbeitet neben den o.a. Dingen logo noch ne Latte anderer Initialisierungen ab. Normaler INI-Kram...
// -----------------------------------------------------------------------------
procedure TIR2KB_frm_RCINTERFACE.FormCreate(Sender: TObject); begin ... RCTimer.Enabled := false; // disable Timer RCTimer.Interval := 80; // set to 80 mS / fit for almost IR-RCCodes ... SetProcessCPUKernel(GetProcessID, 1); // use always 1st CPU (safe ?) if QueryPerformanceFrequency(qpcfreq) Then begin ... // do not start COM if error occurs here ! end; ... end; // ----------------------------------------------------------------------------- procedure TIR2KB_frm_RCINTERFACE.StartCOM; begin RCTimer.Enabled := false; // stop timer for safety / on restart Data.RCInterface := 2; ComPort.Open; ComPort.SetRTS(True); ComPort.SetDTR(True); // QueryPerformanceCounter(TSqpc1); // remain TqpcStamp divider TSqpc1 := 0; // defined settingfor 1st compare end; // ----------------------------------------------------------------------------- procedure TIR2KB_frm_RCINTERFACE.ComPortDSRChange(Sender: TObject; OnOff: Boolean); begin QueryPerformanceCounter(TSqpc2); // get new TqpcStamp Tqpc := ((TSqpc2 - TSqpc1) * 1000000) div qpcfreq; // calc Tqpc in µS ! TSqpc1 := TSqpc2; // set last TqpcStamp if (Tqpc > 12500) then // > 12.5 mS ? > must be a new Code-Sequence! begin fillchar(TCP, sizeof(TTCP),0); // clear TP - new frame started RCTimer.Enabled := false; // stop timer for safety RCTimer.Enabled := true; // start timer again exit; // !!! wait for next valid pulse end; // TCP.Len = 0 ! if (TCP.Len < TCPmaxlen) then // space in TP to write ? begin TCP.HL[TCP.Len] := OnOff; // Pulse-type TCP.Pulse[TCP.Len] := Tqpc; // Pulse-duration TCP.Time := TCP.Time + Tqpc; // Command-duration (incremented) inc(TCP.Len); // number of pulses end; end; // ----------------------------------------------------------------------------- procedure TIR2KB_frm_RCINTERFACE.RCTimerTimer(Sender: TObject); begin case Data.RCInterface of 1: begin // USB .... CheckRCData; end; 2: begin // COM RCTimer.Enabled := false; // stop timer for safety / on restart CheckRCData; end; 3: begin // HID .... CheckRCData; end; end; end; So bald der gewünschte Kern definiert gesetzt ist (Abfrage auf Erfolg fehlt noch), wird hier nur einmal der erforderliche Divisor gelesen. Sollte lt. MS nur einmal passieren - hier sicherlich der richtige Platz !? 'StartCOM' wird im weiteren Verlauf des Programms automatisch ausgeführt, wenn so weit COM mit dem korrekten Port und QPC verfügbar ist. Der erstmaligen Aufruf von QPC ist hier eigentlich unwichtig, daher ausmarkiert und der Wert der 'Startzeit' auf 0 gesetzt. 'ComPortDSRChange' ist eine Event-Routine, die (nur) bei Signalwechsel (H > L oder L > H) am DSR-Pin vom COM-Port aufgerufen wird. Erst hier lese ich den QPC als Stopp-Wert und ermittle die vergangene Zeit seit letztem Event - oder Start. [INTERMEZZO] Eben hier fiel auf, das sich 'gelegentlich' und nicht konkret wiederholbar halt eben die berechnete Zeit (weit) in's negative verschiebt und auch kurz danach ebenso (und weiter) in's positive. Irgendwann nach ca. 10-20 bis 30-40 mS passt das dann interessanterweise wieder. Für ne Mittelwertbildung von Ping-Zeiten kann man das vielleicht ignorieren - aber in diesem Fall fehlen bei den Adressen und Daten einer FB-Taste halt ein paar elementare wichtige Bits zur Tastenerkennung .... [/INTERMEZZO] Startwert wird = Stoppwert gesetzt für den nächsten Event. Wenn > als 12.5mS, dann handelt es sich garantiert (99,99999%) um den 1. Event seit Start oder eine neue Folge von Impulsen der FB (auch wenn man eine Taste gedrückt hält). Ist das der Fall, lösche ich mein 'Daten-Array', stoppe den Timer pro forma und starte in wieder. Nix Repeat, While, Wait, Sleep oder in der Art. Hier wird keiner Prozessorzeit verballert. Wichtig: Dieser Timer läuft 80 mS (das passt für die Laufzeit eines Daten-/Adress-Frames für alle möglichen gängigen IR-FBs) und gibt mir ein definiertes Ende auf das sonst endlose Warten eines beendeten Frames. Ich mache das deswegen hier so, weil es unterschiedliche FB-Protokolle mit unterschiedlichen Pulse-/Pause-Zeiten und unterschiedlichen Datenlängen gibt. Muss universell sein - man kann nicht (schon) für für jeden Typ ne extra Abfrage machen, bläht nur auf und wird unübersichtlich. Danach 'raus aus dem Haus'. Handelt es sich um einen (vermeintlich) gültigen Impulsabstand, merke ich mir entsprechende Daten zur späteren Auswertung. Danach warten auf den nächsten Event - oder halt bis der Timer nach 80 mS abgelaufen ist. 'RCTimerTimer' benötige ich eigentlich nur für COM - USB und HID 'funktionieren anders, deshalb lasse ich hier erst mal weg .... Der Timer schaltet sich bei Aufruf selber ab, bis er wieder durch den ersten 'Neu-Impuls' in 'ComPortDSRChange' gestartet wird. Dazwischen vergehen mindestens 20 mS - mit dem 'Erkennen' eines neuen, kompletten Daten-/Adress-Frames also min. 100 mS. Das reicht erfahrungsgemäß nach ausgiebigen Tests hier, um eine Auswertung durchzuführen und Daten entsprechend an die Applikation(en) zu senden. Ich hatte bisher keine Timing-Probs damit. Mit ca. 20 und auch mehr verschiedenen FBs. 'CheckRCData' (hier nicht gelistet) validiert die Daten vorgegebener FB's/Programme und gibt sie bei Gültigkeit je nach Einstellung über eine flexibel einzubindende Callback-Rotuine an ein korrespondierendes Programm / System weiter: - als ein KeyBoard-Event oder Maus-Simulation (an gewählte App / Fenster) - via API des Programms direkt dahin - oder .... was sonst noch so geht. Ausbaufähig ?! Funktioniert wirklich recht genial. Auf meinem WinDoof-HTPC (AMD X2 5400) kann ich damit die DVB-App 'DVBDream', VLC und auch die Online-TV-Zeitung TV-Browser recht gut vom Sofa mit einer IMON-FB (die hat ein Mausrad) recht prima bedienen. Noch gibt es hier & da ein paar Macken - aber da arbeite ich ja (wieder) dran ..... Problem ist bei der Lösung, dass ich wie o.g. absolut kein Held in Sachen Threads bin. Und da dieses Proggie sowohl als Stand-Alone-App läuft (zum Anlernen, einstellen, zuweisen), sowie auch als DLL in einer Anwendung, ist eine generelle Kernzuweisung für die gesamte App sicher nicht der schlaueste Weg ... Im SA-Betrieb stört die generelle Zuweisung auf einen Kern absolut nicht, aber z.B. als DLL mit DVBDream und meinem kleinen (naja, auch wachsenden) DVB-Proggie geht das von der reduzierten Performance her gar nicht. Mit VLC + TV-Browser hab ich das mangels Zeit noch nicht getestet. Wie löst man das mit dem Zugriff betreff QPC auf nur einen Kern am schlauesten ? - |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz