Hidlibrary: ReadReport()-Speicherleck

Erstellt am 14. Aug. 2011  ·  9Kommentare  ·  Quelle: mikeobrien/HidLibrary

Tolle Bibliothek Mike, vielen Dank für diese riesige Arbeit.

Das Problem ist, wenn ich InputReport mit Daten füllen möchte:

InputReport = device.ReadReport();

wobei InputReport ist:

HidLibrary.HidReport InputReport = new HidLibrary.HidReport(device.Capabilities.InputReportByteLength);

Es ist ein sehr großer Leckspeicher, insbesondere wenn ich Berichte im asynchronen Modus vom Gerät lese (z. B. 100 Mal für eine Sekunde). In wenigen Minuten kann es Hunderte von Megabyte dauern.

Ich bin Anfänger in der c#-Programmierung und habe keine Lösung für das oben beschriebene Problem gefunden ;(

Schöne Grüße!

Hilfreichster Kommentar

Hier ist meine vorgeschlagene Problemumgehung für das Leistungsproblem, das kaczart (und ich) bemerkt haben:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

Die Nutzung erfolgt nach dem Vorbild:

device.ConnectionCheckOverride = device.IsConnected;
methodRequiringFasterUSBReadWrite();
device.ConnectionCheckOverride = false;

Dies reduzierte die Ausführungszeit meines Massen-USB-Transfer-Testfalls von 159 Sekunden auf 47 Sekunden.

Ich war nicht an der Lösung von kaczart interessiert, nur weil die IsConnected-Eigenschaft in HidDeviceEventMonitor verwendet wird, also benötigt wird, um die ursprüngliche Funktionalität des Aufzählens aktuell angeschlossener USB-Geräte beizubehalten. Einfach gesagt; Ich glaube nicht, dass die Inserted- und Removed-Ereignisse jemals im Code von Kaczart aufgerufen werden (nach einem kurzen Blick darauf).

Alle 9 Kommentare

Kaczart,

Leider ist dieser Code ziemlich alt und ich hatte keine Zeit, ihn zu geben
jede DC. An dieser Stelle habe ich es nur als Referenz da draußen. Ihr Bestes
Wette ist zu Gabeln/Verbessern.

m

Am So, 14. August 2011 um 10:37 Uhr, kaczart <
[email protected]> schrieb:

Tolle Bibliothek Mike, vielen Dank für diese riesige Arbeit.

Das Problem ist, wenn ich InputReport mit Daten füllen möchte:

InputReport = device.ReadReport();

wobei InputReport ist:

HidLibrary.HidReport InputReport = neu
HidLibrary.HidReport(ukp.Capabilities.InputReportByteLength);

Es ist ein sehr großer Speicherleck, besonders wenn ich Berichte asynchron lese
Modus vom Gerät (zB 100 mal für eine Sekunde). In wenigen Minuten kann es
braucht Hunderte von Megabyte.

Ich bin Anfänger in der c#-Programmierung und habe keine Lösung für das Problem gefunden
oben beschrieben ;(

Schöne Grüße!

Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an:
https://github.com/mikeobrien/HidLibrary/issues/11

Kaczart,

Haben Sie eine Lösung gefunden? Mir ist gerade das gleiche aufgefallen.
Tolle Bibliothek Mike, vielen Dank! Ich arbeite mit einer Endicia-USB-Waage und das macht ziemlich viel Spaß.

jrockfl,

Leider hatte ich keine Zeit und keine Fähigkeiten, um dieses Problem zu beheben :(

Schöne Grüße

Das Problem ist, dass HidReport und Devicedata nicht freigegeben werden, also auf eine Garbagecollection wartet.
Es ist jedoch eine einfache Lösung, es freizugeben, nachdem es verarbeitet wurde ...

Endlich musste ich dieses Problem beheben und ich teile, was ich gefunden habe

1) Zuallererst überprüft jede einzelne Read/Write-Methode in der Bibliothek, ob das Gerät angeschlossen ist, was viel Leistung kostet, da die IsConnected-Methode jedes Mal EnumerateHidDevices() aufruft. In der Praxis, wenn ich große Datenpakete vom Gerät sende, ist PC Host langsamer als das HID-Gerät und einige Pakete gehen aufgrund des begrenzten Ringpuffers verloren (32 Berichte standardmäßig, können auf 512 erweitert werden, aber es ist keine endgültige Lösung).
ps. Sie können Ihren Ringpuffer von 32 auf maximal 512 Anrufe erweitern:
NativeMethods .HidD_SetNumInputBuffers((int)device.ReadHandle, 512); //Es wird für XP und höher funktionieren.
2) Zweitens gibt es in EnumerateHidDevices() einen RIESIGEN Speicherverlust aufgrund von "yield return devicePath;" in Zeile 69 und NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet); wird nie angerufen.

Meine Lösung:
1) Rufen Sie IsConnected nicht bei jedem Lesen/Schreiben auf. Machen Sie eine zusätzliche isConnected-Variable in HidDevice:
public bool isConnected;
Setzen Sie die Variable nach erfolgreichem Connect auf true (zB in Ihrer Connect()-Funktion):
device.isConnected = true;
Aktualisieren Sie es in allen DeviceEventMonitorInserted()- und DeviceEventMonitorRemoved()-Ereignissen, zB:
if (Eingefügt != null ) Eingefügt();
ersetzen mit:
if (Eingefügt != null )
{
isConnected = wahr;
Eingefügt();
}
und:
if (Entfernt != null ) Entfernt();
ersetzen mit:
if (Entfernt != null )
{
isConnected = false ;
ENTFERNT();
}
Dann überprüfen Sie diese Variable bei jeder Read/Write-Aufruffunktion:
if (isConnected) statt if (IsConnected)
Jedes Mal, wenn Sie überprüfen müssen, ob das Gerät verbunden ist, überprüfen Sie den Status der öffentlichen Variablen isConnected. Es funktioniert für mich - 0-1% Prozessorauslastung anstelle von 10-20% für Lesethread.

2) in HidDevice.cs Zeile #69 löschen:
// Rückgabe DevicePath;
Es ermöglicht NativeMethods .SetupDiDestroyDeviceInfoList(deviceInfoSet); richtig aufgerufen werden.
Als nächstes fügen Sie nach NativeMethods .SetupDiDestroyDeviceInfoList(deviceInfoSet) hinzu:
foreach (Zeichenfolge devicePath in Geräten)
return return devicePath;
Es wird ein riesiges Speicherleck beheben (in meinem Fall etwa 256 MB für jedes 1 MB empfangene Daten).

Hoffe es hilft.

super, danke für eure tipps, kaczart!!!

Hier ist meine vorgeschlagene Problemumgehung für das Leistungsproblem, das kaczart (und ich) bemerkt haben:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

Die Nutzung erfolgt nach dem Vorbild:

device.ConnectionCheckOverride = device.IsConnected;
methodRequiringFasterUSBReadWrite();
device.ConnectionCheckOverride = false;

Dies reduzierte die Ausführungszeit meines Massen-USB-Transfer-Testfalls von 159 Sekunden auf 47 Sekunden.

Ich war nicht an der Lösung von kaczart interessiert, nur weil die IsConnected-Eigenschaft in HidDeviceEventMonitor verwendet wird, also benötigt wird, um die ursprüngliche Funktionalität des Aufzählens aktuell angeschlossener USB-Geräte beizubehalten. Einfach gesagt; Ich glaube nicht, dass die Inserted- und Removed-Ereignisse jemals im Code von Kaczart aufgerufen werden (nach einem kurzen Blick darauf).

Die Überprüfung einer Geräteverbindung bei jedem Lese- und Schreibvorgang ist ein großer Leistungsengpass bei Hochfrequenzanwendungen. In meinem speziellen Fall war es 30x schneller, anzunehmen, dass das Gerät angeschlossen war, anstatt erneut nach einer Geräteverbindung zu suchen. Rundfahrten sanken von etwa 70 ms auf 2 ms.

Also habe ich gerade ein paar Erweiterungsmethoden geschrieben, um meine eigenen IO für eine schnelle Pooling-Nutzung zu handhaben:

        [DllImport("hid.dll", SetLastError = true)]
        static internal extern bool HidD_SetOutputReport(IntPtr hidDeviceObject, byte[] lpReportBuffer, int reportBufferLength);

        [DllImport("kernel32.dll", SetLastError = true)]
        static internal extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
        public static bool FastWrite(this HidLibrary.HidDevice device, byte[] outputBuffer)
        {
            try
            {
                if (NativeMethods.HidD_SetOutputReport(device.Handle, outputBuffer, outputBuffer.Length))
                    return true;
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }
        public static ReadStatus FastRead(this HidLibrary.HidDevice device, byte[] inputBuffer)
        {
            try
            {
                uint bytesRead;
                if (NativeMethods.ReadFile(device.Handle, inputBuffer, (uint)inputBuffer.Length, out bytesRead, IntPtr.Zero))
                {
                    return ReadStatus.Success;
                }
                else
                {
                    return ReadStatus.NoDataRead;
                }
            }
            catch (Exception)
            {
                return ReadStatus.ReadError;
            }
        }
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen