Hidlibrary: ReadReport () pérdida de memoria

Creado en 14 ago. 2011  ·  9Comentarios  ·  Fuente: mikeobrien/HidLibrary

Gran biblioteca Mike, muchas gracias por este enorme trabajo.

El problema es cuando quiero llenar InputReport con datos:

InputReport = dispositivo.ReadReport ();

donde InputReport es:

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

Es una pérdida de memoria muy grande, especialmente cuando leo informes en modo asíncrono desde el dispositivo (por ejemplo, 100 veces por segundo). En pocos minutos puede ocupar cientos de megabytes.

Soy un principiante en la programación de C # y no encontré una solución para el problema descrito anteriormente; (

¡saludos!

Comentario más útil

Aquí está mi solución alternativa sugerida para el problema de rendimiento que kaczart (y yo) notamos:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

El uso está en la línea de:

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

Esto redujo el tiempo de ejecución de mi caso de prueba de transferencia USB masiva de 159 segundos a 47 segundos.

No estaba interesado en la solución de kaczart simplemente porque la propiedad IsConnected se usa en HidDeviceEventMonitor, por lo que necesitaba conservar la funcionalidad original de enumerar los dispositivos USB conectados actualmente. Simplemente pon; No creo que los eventos insertados y eliminados se invoquen nunca en el código de kaczart (a partir de un breve vistazo).

Todos 9 comentarios

Kaczart,

Desafortunadamente, ese código es bastante antiguo y no he tenido tiempo de proporcionarlo.
cualquier TLC. En este punto, lo tengo como referencia. Tu mejor
la apuesta es bifurcar / mejorar.

metro

El domingo 14 de agosto de 2011 a las 10:37 a. M., Kaczart <
[email protected]> escribió:

Gran biblioteca Mike, muchas gracias por este enorme trabajo.

El problema es cuando quiero llenar InputReport con datos:

InputReport = dispositivo.ReadReport ();

donde InputReport es:

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

Es una pérdida de memoria muy grande, especialmente cuando leo informes en asincrónico
modo desde el dispositivo (por ejemplo, 100 veces por segundo). En pocos minutos puede
toma cientos de megabytes.

Soy un principiante en la programación de C # y no encontré la solución al problema
descrito arriba; (

¡saludos!

Responda a este correo electrónico directamente o véalo en GitHub:
https://github.com/mikeobrien/HidLibrary/issues/11

Kaczart,

¿Encontraste una solución? Solo noté lo mismo.
Gran biblioteca Mike, ¡muchas gracias! Estoy trabajando con una báscula USB Endicia y esto es bastante divertido.

jrockfl,

Desafortunadamente, no tuve tiempo ni habilidad suficiente para solucionar este problema :(

saludos

El problema es que HidReport y Devicedata no se liberan, por lo que espera una recolección de basura.
Sin embargo, es una solución fácil liberarlo después de que se haya procesado ...

Finalmente tuve que solucionar este problema y comparto lo que encontré.

1) En primer lugar, todos los métodos de lectura / escritura en la biblioteca verifican si el dispositivo está conectado, lo que cuesta mucho rendimiento porque el método IsConnected llama cada vez que EnumerateHidDevices (). En la práctica, cuando envío un gran paquete de datos desde el dispositivo, PC Host es más lento que el dispositivo HID y algunos paquetes se pierden debido al búfer de anillo limitado (32 informes de forma predeterminada, se pueden extender a 512 pero no es la solución final).
PD. puede ampliar su búfer de anillo de 32 a un máximo de 512 informes llamando:
NativeMethods .HidD_SetNumInputBuffers ((int) device.ReadHandle, 512); // Funcionará para XP y posteriores.
2) En segundo lugar, en EnumerateHidDevices () hay una ENORME pérdida de memoria debido a "yield return devicePath"; en la línea 69 y NativeMethods.SetupDiDestroyDeviceInfoList (deviceInfoSet); nunca será llamado.

Mi solución:
1) No llame a IsConnected cada lectura / escritura. Haga una variable isConnected adicional en HidDevice:
public bool isConnected;
Establezca la variable en verdadero después de una conexión exitosa (por ejemplo, en su función Connect ()):
device.isConnected = true;
Actualícelo en todos los eventos DeviceEventMonitorInserted () y DeviceEventMonitorRemoved (), por ejemplo:
if (Insertado! = nulo) Insertado ();
reemplazar con:
si (Insertado! = nulo)
{
isConnected = true;
Insertado();
}
y:
if (Eliminado! = null) Eliminado ();
reemplazar con:
si (eliminado! = nulo)
{
isConnected = falso;
Remoto();
}
Luego verifique esta variable en cada función de llamada de lectura / escritura:
if (isConnected) en lugar de if (IsConnected)
Cada vez que necesite verificar si el dispositivo está conectado, verifique el estado de la variable pública isConnected. Me funciona: 0-1% de uso del procesador en lugar de 10-20% para el hilo de lectura.

2) en HidDevice.cs línea # 69 eliminar:
// rendimiento return devicePath;
Permitirá NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet); ser llamado propiamente.
A continuación, después de NativeMethods .SetupDiDestroyDeviceInfoList (deviceInfoSet) agregue:
foreach (string devicePath en dispositivos)
rendimiento return devicePath;
Arreglará una GRAN pérdida de memoria (aproximadamente 256 MB por cada 1 MB de datos recibidos en mi caso)

Espero que ayude.

impresionante, gracias por tus pistas, kaczart !!!

Aquí está mi solución alternativa sugerida para el problema de rendimiento que kaczart (y yo) notamos:
https://github.com/macaba/HidLibrary/commit/8f1864e1351ccca4772d5bbc18a0f94d7ba07fe7

El uso está en la línea de:

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

Esto redujo el tiempo de ejecución de mi caso de prueba de transferencia USB masiva de 159 segundos a 47 segundos.

No estaba interesado en la solución de kaczart simplemente porque la propiedad IsConnected se usa en HidDeviceEventMonitor, por lo que necesitaba conservar la funcionalidad original de enumerar los dispositivos USB conectados actualmente. Simplemente pon; No creo que los eventos insertados y eliminados se invoquen nunca en el código de kaczart (a partir de un breve vistazo).

Verificar la conexión de un dispositivo en cada lectura y escritura es un cuello de botella importante en el rendimiento en aplicaciones de alta frecuencia. En mi caso particular, fue 30 veces más rápido asumir que el dispositivo estaba conectado en lugar de volver a verificar la conexión del dispositivo; los viajes de ida y vuelta se redujeron de unos 70 ms a 2 ms.

Así que acabo de escribir un par de métodos de extensión para manejar mi propio IO para un uso rápido de la agrupación:

        [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;
            }
        }
¿Fue útil esta página
0 / 5 - 0 calificaciones