micro - Bursty escribe en SD/USB estancando mis aplicaciones de tiempo crítico en Linux incorporado
formatear usb linux gparted (10)
Bien obvio primero, ¿has intentado explícitamente decirle al archivo que se descargue? También creo que podría haber alguna ioctl que puedas usar para hacerlo, pero honestamente no he hecho mucha programación de archivos C / POSIX.
Al ver que estás en un kernel de Linux, deberías ser capaz de sintonizar y reconstruir el kernel a algo que se adapte mejor a tus necesidades, ej. mucho más frecuentes, pero luego también descargas menores al almacenamiento permanente.
Una revisión rápida en las páginas de mi manual encuentra esto:
SYNC(2) Linux Programmer’s Manual SYNC(2) NAME sync - commit buffer cache to disk SYNOPSIS #include <unistd.h> void sync(void); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500 DESCRIPTION sync() first commits inodes to buffers, and then buffers to disk. ERRORS This function is always successful.
Estoy trabajando en un proyecto de Linux embebido que conecta un ARM9 a un chip de codificador de video de hardware y escribe la salida de video en una tarjeta SD o dispositivo USB. La arquitectura del software implica un controlador del núcleo que lee los datos en un grupo de almacenamientos intermedios, y una aplicación de usuario que escribe los datos en un archivo en el dispositivo extraíble montado.
Estoy descubriendo que por encima de cierta velocidad de datos (alrededor de 750kbyte / seg) empiezo a ver la aplicación de escritura de video de userland perdiendo aproximadamente medio segundo, cada 5 segundos. Esto es suficiente para hacer que el controlador kernel se quede sin búferes, e incluso si pudiera aumentar el número de búferes, los datos de video deben estar sincronizados (idealmente dentro de 40 ms) con otras cosas que están sucediendo en tiempo real. Entre estos 5 segundos "picos de retardo", los guiones se completan bien dentro de los 40 ms (en lo que respecta a la aplicación, aprecio que el SO los amortigüe).
Creo que este pico de retraso tiene que ver con la forma en que Linux está descargando datos al disco. Noto que el pdflush está diseñado para reactivarse cada 5s, mi entendimiento es que esto sería lo que hace la escritura. Tan pronto como finaliza el establo, la aplicación userland puede realizar un servicio rápido y escribir la acumulación de búferes (que no se desbordaron).
Creo que el dispositivo con el que estoy escribiendo tiene un rendimiento final razonable: copiar un archivo de 15MB de una memoria fs y esperar a que se complete la sincronización (y la luz del dispositivo USB deja de parpadear) me dio una velocidad de escritura de alrededor de 2.7MBytes / sec.
Estoy buscando dos tipos de pistas:
¿Cómo puedo evitar que la escritura en ráfagas bloquee mi aplicación? ¿Tal vez las prioridades del proceso, los parches en tiempo real o el ajuste del código del sistema de archivos para escribir continuamente en lugar de a latas?
¿Cómo puedo hacer que mis aplicaciones estén al tanto de lo que está sucediendo con el sistema de archivos en términos de retraso de escritura y rendimiento en la tarjeta / memoria? Tengo la capacidad de cambiar la velocidad de bits del video en el códec de hardware sobre la marcha, lo que sería mucho mejor que dejar caer marcos o imponer un límite artificial en la velocidad de bits máxima permitida.
Algo más de información: este es un ARM9 de 200MHz que actualmente ejecuta un Kernel de Montavista 2.6.10.
Actualizaciones:
- Al montar el sistema de archivos SYNC, el rendimiento es demasiado pobre.
- Los medios extraíbles están formateados en FAT / FAT32 y deben serlo ya que el propósito del diseño es que los medios se puedan conectar a cualquier PC con Windows y leer.
- Llamar regularmente a sync () o fsync () decir, cada segundo provoca paradas regulares y un rendimiento inaceptablemente bajo
- Estoy usando write () y abierto (O_WRONLY | O_CREAT | O_TRUNC) en lugar de fopen () etc.
- No puedo encontrar nada inmediatamente en línea sobre los mencionados "sistemas de archivos en tiempo real de Linux". ¿Campo de golf?
Espero que esto tenga sentido. ¿Primera pregunta de Linux incorporada en stackoverflow? :)
Hacer tu propia descarga () me suena bien: quieres tener el control, no dejarlo a los caprichos de la capa de memoria intermedia genérica.
Esto puede ser obvio, pero asegúrese de no llamar a write () con demasiada frecuencia: asegúrese de que cada escritura () tenga datos suficientes para escribir para que valga la pena la sobrecarga de los syscall. Además, en la otra dirección, no lo llame con demasiada frecuencia, o se bloqueará durante el tiempo suficiente como para causar un problema.
En una pista más difícil de reimplementar, ¿ha intentado cambiar a E / S asíncrona? Usando aio puedes disparar una escritura y entregarle un conjunto de búferes mientras estás chupando datos de video en el otro conjunto, y cuando la escritura finaliza, cambias conjuntos de búferes.
Lanzaré algunas sugerencias, el consejo es barato.
- asegúrese de estar utilizando una API de nivel inferior para escribir en el disco, no use funciones de caché en modo usuario, como
fopen, fread, fwrite
use las funciones de nivel más bajoopen, read, write
. - pase el indicador
O_SYNC
cuando abra el archivo, esto hará que cada operación de escritura se bloquee hasta que se escriba en el disco, lo que eliminará el comportamiento de ráfaga de sus escrituras ... con el gasto de cada escritura que es más lenta. - Si está realizando lecturas / ioctls desde un dispositivo para tomar una porción de datos de video, puede considerar asignar una región de memoria compartida entre la aplicación y el kernel; de lo contrario, recibirá un montón de llamadas
copy_to_user
al transferir búferes de datos de video desde el espacio del kernel hasta el espacio del usuario. - Es posible que deba validar que su dispositivo flash USB sea lo suficientemente rápido con transferencias sostenidas para escribir los datos.
Solo un par de pensamientos, espero que esto ayude.
Me han dicho que después de que el host envíe un comando, las tarjetas MMC y SD "deben responder dentro de 0 a 8 bytes".
Sin embargo, la especificación permite que estas tarjetas respondan con "ocupado" hasta que hayan terminado la operación, y aparentemente no hay límite en cuánto tiempo una tarjeta puede reclamar estar ocupada (por favor, dígame si existe tal límite).
Veo que algunos chips flash de bajo costo como el M25P80 tienen un "tiempo máximo de borrado de un sector" garantizado de 3 segundos, aunque típicamente "solo" requiere 0.6 segundos.
Que 0,6 segundos suena sospechosamente similar a su "estancamiento durante aproximadamente medio segundo".
Sospecho que la compensación entre los chips flash lentos y baratos y los flash flash caros y rápidos tiene algo que ver con la amplia variación en los resultados de la unidad flash USB:
- http://www.testfreaks.com/blog/information/16gb-usb-drive-comparison-17-drives-compared/
- http://www.tomshardware.com/reviews/data-transfer-run,1037-10.html
He escuchado rumores de que cada vez que se borra un sector de flash y luego se lo programa de nuevo, tarda un poco más que la última vez.
Entonces, si tiene una aplicación de tiempo crítico, es posible que necesite (a) probar sus tarjetas SD y memorias USB para asegurarse de que cumplan con la latencia mínima, ancho de banda, etc. requeridos por su aplicación, y (b) volver a realizar pruebas peridicamente o reemplaza de manera preventiva estos dispositivos de memoria.
Para el registro, resultaron ser dos aspectos principales que parecen haber eliminado el problema en todos menos en los casos más extremos. Este sistema todavía está en desarrollo y no ha sido sometido a pruebas exhaustivas todavía, pero funciona bastante bien (toque de madera).
La gran victoria vino de hacer que la aplicación userland writer tuviera varios subprocesos. Son las llamadas a write () las que bloquean a veces: otros procesos y subprocesos aún se ejecutan. Siempre que tenga un hilo que atienda el controlador del dispositivo y actualice los recuentos de cuadros y otros datos para sincronizar con otras aplicaciones que se estén ejecutando, los datos pueden almacenarse temporalmente y escribirse unos segundos más tarde sin romper los plazos. Primero probé un doble buffer doble de ping-pong, pero eso no fue suficiente; los pequeños búferes se verían abrumados y los grandes solo provocarían pausas más grandes mientras el sistema de archivos digería las escrituras. Un conjunto de 10 búferes de 1 MB en cola entre subprocesos funciona bien ahora.
El otro aspecto es vigilar el rendimiento máximo de escritura en los medios físicos. Para esto estoy vigilando la estadística Sucio: reportado por / proc / meminfo. Tengo un código áspero y listo para estrangular el codificador si Sucio: sube por encima de un cierto umbral, parece funcionar vagamente. Se necesitan más pruebas y ajustes más tarde. Afortunadamente, tengo mucha memoria RAM (128M) para jugar, dándome unos segundos para ver cómo mi acumulación de tareas se acumula y baja sin problemas.
Trataré de recordar volver atrás y actualizar esta respuesta si encuentro que necesito hacer algo más para tratar este problema. Gracias a los otros contestadores.
Parece que estás buscando sistemas de archivos en tiempo real de Linux. Asegúrese de buscar Google y otros para eso.
XFS tiene una opción en tiempo real, aunque no he jugado con ella.
hdparm podría permitirle apagar el almacenamiento en caché por completo.
Ajustar las opciones del sistema de archivos (desactivar todos los atributos de archivo adicionales innecesarios) puede reducir lo que necesita para enjuagar, acelerando así el color. Sin embargo, dudo que eso ayude mucho.
Pero mi sugerencia sería evitar usar el dispositivo como un sistema de archivos y usarlo como un dispositivo en bruto. Rellene los datos en él como lo haría con ''dd''. Luego, en otro lugar, lea los datos sin procesar y escríbalos después de hornear.
Por supuesto, no sé si esa es una opción para ti.
Sin saber más acerca de sus circunstancias particulares, solo puedo ofrecer las siguientes suposiciones:
Intente usar fsync () / sync () para forzar al kernel a enjuagar datos al dispositivo de almacenamiento con mayor frecuencia. Parece que el núcleo almacena temporalmente todas sus escrituras y luego ata el bus o de lo contrario detiene su sistema mientras realiza la escritura real. Con llamadas cuidadosas a fsync () puede intentar programar las escrituras sobre el bus del sistema de una manera más fina.
Puede tener sentido estructurar la aplicación de tal manera que la codificación / captura (no mencionó la captura de video, entonces estoy asumiendo aquí - es posible que desee agregar más información) la tarea se ejecuta en su propio hilo y almacena en búfer su salida en el dominio del usuario; luego, un segundo subproceso puede manejar la escritura en el dispositivo. Esto le dará un buffer de suavizado para permitir que el codificador termine siempre sus escrituras sin bloqueos.
Una cosa que suena sospechosa es que solo ve este problema a cierta velocidad de datos: si esto realmente fuera un problema de almacenamiento en búfer, esperaría que el problema ocurriera con menor frecuencia a menores velocidades de datos, pero aún esperaría ver esto. problema.
En cualquier caso, más información puede ser útil. ¿Cuál es la arquitectura de tu sistema? (En términos muy generales)
Dada la información adicional que proporcionó, parece que el rendimiento del dispositivo es bastante pobre para escrituras pequeñas y frecuentes descargas. Si está seguro de que para escrituras más grandes puede obtener el rendimiento suficiente (y no estoy seguro de que sea así, pero el sistema de archivos podría estar haciendo algo estúpido, como actualizar la FAT después de cada escritura) y luego tener un hilo de codificación de datos de tuberías a un hilo de escritura con suficiente buffering en el hilo de escritura para evitar puestos. He usado memorias intermedias de anillos de memoria compartidos en el pasado para implementar este tipo de esquema, pero cualquier mecanismo de IPC que permita al escritor escribir en el proceso de E / S sin detenerse a menos que el búfer esté lleno debería hacer el truco.
Tiene un auxiliar de depuración, puede usar strace para ver qué operaciones están tomando tiempo. Puede haber algo sorprendente con la FAT / FAT32.
¿Escribes en un solo archivo o en múltiples archivos?
Puede hacer un hilo de lectura, que mantendrá un grupo de búfer de video listo para escribirse en una cola. Cuando se recibe un marco, se agrega a la cola, y el hilo de escritura se señala
Datos compartidos
empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore
Hilo de lectura:
buf=get_buffer()
bufer_to_write = buf_dequeue(empty_buffer_queue)
memcpy(bufer_to_write, buf)
buf_enqueue(bufer_to_write, ready_buffer_queue)
sem_post(video_data_ready_semaphore)
Hilo de escritura
sem_wait(vido_data_ready_semaphore)
bufer_to_write = buf_dequeue(ready_buffer_queue)
write_buffer
buf_enqueue(bufer_to_write, empty_buffer_queue)
Si su escritura enhebrada está bloqueada esperando el kernel, esto podría funcionar. Sin embargo, si está bloqueado dentro del kerne, entonces no hay mucho que pueda hacer, excepto buscar un kernel más reciente que su 2.6.10
Una función útil de Linux y una alternativa para sincronizar o fsync es sync_file_range. Esto le permite programar datos para escribir sin esperar a que el sistema de búfer interno se acerque.
Para evitar largas pausas, asegúrese de que su cola IO (por ejemplo: / sys / block / hda / queue / nr_requests) sea lo suficientemente grande. Esa cola es donde se almacenan los datos entre el borrado de la memoria y la llegada al disco.
Tenga en cuenta que sync_file_range no es portable, y solo está disponible en los kernels 2.6.17 y posteriores.
Aquí hay información sobre tuning pdflush para operaciones de escritura pesada.