Question

Je travaille sur un projet Linux intégré qui interface un ARM9 avec une puce d’encodeur vidéo et écrit la sortie vidéo sur une carte SD ou une clé USB. L’architecture logicielle implique un pilote de noyau qui lit les données dans un pool de mémoires tampons et une application utilisateur qui écrit les données dans un fichier sur le périphérique amovible monté.

Je constate qu’au-delà d’un certain débit de données (environ 750 ko / s), je commence à voir l’application d’écriture vidéo se perdre pendant environ une demi-seconde, environ toutes les 5 secondes. Cela suffit pour que le pilote du noyau manque de tampons - et même si je pouvais augmenter le nombre de tampons, les données vidéo doivent être synchronisées (idéalement dans un délai de 40 ms) avec d'autres événements en temps réel. Entre ces 5 secondes "pics de décalage", l'écriture est terminée dans un délai de 40 ms (en ce qui concerne l'application, j'apprécie le fait qu'elles soient tamponnées par le système d'exploitation).

Je pense que ce décalage est lié à la manière dont Linux transfère les données sur disque. Je remarque que pdflush est conçu pour se réveiller toutes les 5 secondes. Je crois comprendre que c’est ce que c’est ce qui est écrit. Dès que le décrochage est terminé, l’application de l’utilisateur est en mesure de traiter et d’écrire rapidement les retards de mémoire tampon (qui ne débordent pas).

Je pense que le périphérique sur lequel j'écris a un débit ultime raisonnable: copier un fichier de 15 Mo à partir d'un ff mémoire et attendre que la synchronisation soit terminée (et le voyant de la clé USB pour arrêter de clignoter) m'a donné une vitesse d'écriture d'environ 2,7 Mo. / sec.

Je cherche deux sortes d'indices:

  1. Comment puis-je empêcher l'écriture en rafale de caler mon application - par exemple, traiter les priorités, les correctifs en temps réel ou ajuster le code du système de fichiers pour écrire en continu plutôt que de manière brusque?

  2. Comment puis-je informer mes applications de ce qui se passe avec le système de fichiers en termes de backlog en écriture et de débit sur la carte / clé USB? J'ai la possibilité de changer le débit vidéo dans le codec matériel à la volée, ce qui serait bien mieux que de laisser tomber des images ou d'imposer une limite artificielle au débit maximum autorisé.

Quelques informations supplémentaires: il s’agit d’un ARM9 à 200 MHz utilisant actuellement un noyau basé sur Montavista 2.6.10.

Mises à jour:

  • Le montage du système de fichiers SYNC provoque un débit beaucoup trop faible.
  • Le support amovible est au format FAT / FAT32 et doit être conçu dans le but de permettre au support de pouvoir être branché sur tout PC sous Windows et lu.
  • Si vous appelez régulièrement sync () ou fsync (), chaque seconde provoque des blocages réguliers et un débit inacceptable.
  • J'utilise write () et open (O_WRONLY | O_CREAT | O_TRUNC) plutôt que fopen (), etc.
  • Je ne trouve rien immédiatement en ligne sur les "systèmes de fichiers Linux temps réel" cités. Liens?

J'espère que cela a du sens. Première question Linux intégrée sur stackoverflow? :)

Était-ce utile?

La solution

Pour mémoire, il s’est avéré que deux aspects principaux semblaient avoir éliminé le problème dans tous les cas sauf les plus extrêmes. Ce système est encore en développement et n’a pas encore été soumis à un test de torture rigoureux, mais il fonctionne assez bien (toucher du bois).

La grande victoire provient de la création de l’application d’écriture utilisateur multithread. Ce sont les appels à write () qui bloquent parfois: d'autres processus et threads sont toujours exécutés. Tant que mon thread gère le pilote de périphérique et met à jour le nombre de trames et d'autres données à synchroniser avec d'autres applications en cours d'exécution, les données peuvent être mises en mémoire tampon et écrites quelques secondes plus tard sans dépasser les délais. J'ai d'abord essayé un simple tampon double ping-pong, mais cela ne suffisait pas; les petites mémoires tampons seraient surchargées et les plus grandes ne feraient que causer de plus grandes pauses pendant que le système de fichiers digérerait les écritures. Un pool de 10 tampons de 1 Mo mis en file d'attente entre les threads fonctionne bien maintenant.

L’autre aspect consiste à surveiller le débit d’écriture ultime sur un support physique. Pour cela, je garde un œil sur la statistique Dirty: rapportée par / proc / meminfo. J'ai un code approximatif et prêt à étrangler l'encodeur si Dirty: grimpe au-dessus d'un certain seuil, semble fonctionner vaguement. Plus de tests et de réglages sont nécessaires plus tard. Heureusement, j’ai beaucoup de mémoire vive (128 Mo), ce qui me laisse quelques secondes pour voir mon arriéré s’accumuler et s’accélérer sans à-coups.

Je vais essayer de ne pas oublier de revenir et de mettre à jour cette réponse si j’ai besoin de faire autre chose pour régler ce problème. Merci aux autres intervenants.

Autres conseils

Je vais faire quelques suggestions, les conseils ne coûtent pas cher.

  • assurez-vous que vous utilisez une API de niveau inférieur pour écrire sur le disque, n'utilisez pas de fonctions de mise en cache en mode utilisateur telles que fopen, fread, fwrite utilisez les fonctions de niveau inférieur ouvertes, lire, écrire .
  • passez l'indicateur O_SYNC lorsque vous ouvrez le fichier. Chaque opération d'écriture sera bloquée jusqu'à ce qu'elle soit écrite sur le disque, ce qui supprimera le comportement en rafale de vos écritures ... au détriment de chacune d'elles. écrire étant plus lent.
  • Si vous effectuez des lectures / ioctls à partir d'un périphérique pour récupérer un bloc de données vidéo, vous pouvez envisager d'allouer une région de mémoire partagée entre l'application et le noyau, sinon vous risquez de vous faire mal avec un tas de copy_to_user appelle lors du transfert de tampons de données vidéo de l'espace noyau vers l'espace utilisateur.
  • Vous devrez peut-être vérifier que votre périphérique flash USB est suffisamment rapide avec des transferts continus pour écrire les données.

Quelques réflexions, espérons que cela vous aidera.

Voici des informations sur le réglage de pdflush pour l'écriture opérations lourdes.

On dirait que vous recherchez des systèmes de fichiers Linux en temps réel. Assurez-vous de rechercher ces informations sur Google et autres.

XFS a une option en temps réel, bien que je n’ai pas joué avec.

hdparm peut vous permettre de désactiver complètement la mise en cache.

Le réglage des options du système de fichiers (désactivez tous les attributs de fichier superflus) peut réduire le volume à vider, accélérant ainsi le vidage. Je doute que cela aiderait beaucoup, cependant.

Mais je suggérerais d'éviter d'utiliser la clé en tant que système de fichiers et de l'utiliser plutôt comme un périphérique brut. Remplissez les données comme si vous utilisiez 'dd'. Ensuite, ailleurs, lisez ces données brutes et écrivez-les après la cuisson.

Bien sûr, je ne sais pas si c'est une option pour vous.

Possède une aide au débogage, vous pouvez utiliser strace pour voir quelles opérations prennent du temps. Il pourrait y avoir quelque chose d’étonnant avec le FAT / FAT32.

Est-ce que vous écrivez dans un seul fichier ou dans plusieurs fichiers?

Vous pouvez créer un fil de lecture qui maintiendra un pool de mémoire tampon vidéo prêt à être écrit dans une file d'attente. Lorsqu'une trame est reçue, elle est ajoutée à la file d'attente et le fil d'écriture est signalé

Données partagées

empty_buffer_queue
ready_buffer_queue
video_data_ready_semaphore

Lecture du fil de discussion:

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)

Fil d'écriture

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 votre thread d'écriture est bloqué dans l'attente du noyau, cela pourrait fonctionner. Cependant, si vous êtes bloqué dans l’espace kerne, vous ne pouvez rien faire de plus, si ce n’est à la recherche d’un noyau plus récent que votre 2.6.10

Sans en savoir plus sur votre situation particulière, je ne peux que vous proposer les hypothèses suivantes:

Essayez d’utiliser fsync () / sync () pour forcer le noyau à vider les données plus fréquemment sur le périphérique de stockage. On dirait que le noyau met toutes vos écritures en mémoire tampon, puis bloque le bus ou bloque autrement votre système lors de l’écriture proprement dite. Avec des appels soignés à fsync (), vous pouvez essayer de planifier les écritures sur le bus système de manière plus fine.

Il peut être judicieux de structurer l’application de manière à ce que le codage / capture (vous n’avez pas mentionné la capture vidéo, c’est pourquoi je suppose ici que vous voudrez peut-être ajouter davantage d’informations). son propre thread et met sa sortie en mémoire tampon dans le domaine utilisateur. Un second thread peut alors gérer l’écriture sur le périphérique. Cela vous donnera un tampon de lissage pour permettre au codeur de toujours terminer ses écritures sans bloquer.

Une chose qui semble suspecte est que vous ne voyez ce problème qu’à un certain débit de données - s’il s’agissait vraiment d’un problème de mise en mémoire tampon, je pense que le problème se produirait moins souvent à des débits de données plus faibles, mais je l’attendrais quand même. pour voir ce problème.

Dans tous les cas, davantage d’informations pourraient s’avérer utiles. Quelle est l'architecture de votre système? (En termes très généraux.)

Compte tenu des informations supplémentaires que vous avez fournies, il semble que le débit de l'appareil soit plutôt faible pour les petites écritures et les vidages fréquents. Si vous êtes certain que pour de plus grandes écritures, vous pouvez obtenir un débit suffisant (et je ne suis pas sûr que ce soit le cas, mais le système de fichiers peut faire quelque chose de stupide, comme mettre à jour le FAT après chaque écriture), puis avoir des données de canalisation de thread d'encodage. à un fil d'écriture avec suffisamment de mémoire tampon dans le fil d'écriture pour éviter les blocages. Dans le passé, j’utilisais autrefois des tampons en anneau de mémoire partagée pour mettre en œuvre ce type de schéma, mais tout mécanisme IPC permettant à l’écrivain d’écrire dans le processus d’E / S sans blocage, à moins que le tampon ne soit plein, devrait faire l’affaire.

Une fonction utile de Linux et une alternative à la synchronisation ou à fsync est sync_file_range. Cela vous permet de planifier l'écriture des données sans attendre que le système de mémoire tampon du noyau y accède.

Pour éviter les longues pauses, assurez-vous que votre file d'attente d'E / S (par exemple: / sys / block / hda / queue / nr_requests) est suffisamment grande. Cette file d'attente est l'endroit où les données sont stockées entre le vidage de la mémoire et l'arrivée sur le disque.

Notez que sync_file_range n'est pas portable et n'est disponible que dans les noyaux 2.6.17 et ultérieurs.

On m'a dit qu'après l'envoi d'une commande par l'hôte, les cartes MMC et SD "devaient répondre entre 0 et 8 octets".

Cependant, la spécification permet à ces cartes de répondre avec "occupé". jusqu'à ce qu'ils aient terminé l'opération, et apparemment, il n'y a pas de limite à la durée pendant laquelle une carte peut prétendre être occupée (s'il vous plaît, dites-moi s'il existe une telle limite).

Je constate que certaines puces flash à faible coût, telles que le M25P80, ont un "délai d'effacement maximal sur un secteur" garanti. de 3 secondes, bien qu’il soit typiquement "seulement" nécessite 0,6 seconde.

Ces 0,6 secondes semblent étrangement similaires à votre "perte de vitesse pendant peut-être une demi-seconde".

Je soupçonne que le compromis entre des puces flash lentes et bon marché et des puces flash chères et rapides a quelque chose à voir avec la grande variation des résultats des clés USB:

J'ai entendu dire que chaque fois qu'un secteur de flash est effacé puis reprogrammé, cela prend un peu plus longtemps que la dernière fois.

Ainsi, si vous avez une application urgente, vous devrez peut-être (a) tester vos cartes SD et vos clés USB pour vous assurer qu'elles respectent le temps de latence, la bande passante, etc. requis par votre application, et (b) péridiquement. testez à nouveau ou remplacez de manière préventive ces dispositifs de mémoire.

Bien évident d’abord, avez-vous essayé de dire explicitement que le fichier était vide? Je pense aussi que vous pouvez utiliser un ioctl pour le faire, mais honnêtement, je n’ai pas fait beaucoup de programmation de fichiers C / POSIX.

En voyant que vous êtes sur un noyau Linux, vous devriez être en mesure d’accorder et de reconstruire le noyau à quelque chose qui correspond mieux à vos besoins, par exemple. beaucoup plus fréquentes mais aussi de plus petites chasses au stockage permanent.

Une vérification rapide dans mes pages de manuel trouve ceci:

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.

Faire votre propre flush () ing me semble juste - vous voulez garder le contrôle, ne pas le laisser aux caprices de la couche tampon générique.

Cela peut sembler évident, mais assurez-vous de ne pas appeler write () trop souvent - assurez-vous que chaque write () dispose de suffisamment de données pour être écrit afin que la surcharge système en vaille la peine. De même, dans l’autre sens, n’appelez pas cela trop rarement, sinon il se bloquera suffisamment longtemps pour causer un problème.

Sur une piste plus difficile à réimplémenter, avez-vous essayé de passer à l'entrée / sortie asynchrone? En utilisant aio, vous pouvez déclencher une écriture et lui remettre un ensemble de tampons pendant que vous aspirez des données vidéo dans l’autre ensemble. Lorsque l’écriture est terminée, vous changez d’ensemble de tampons.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top