Forum Programmation.c Délai pendant l'exécution d'un fwrite

Posté par  (site web personnel) .
Étiquettes :
2
15
déc.
2009

Bonjour,

j'ai un programme qui enregistre sur le disque dur des images en provenances de plusieurs caméras. Il tourne en roue libre, le plus vite possible.

L'enregistrement se fait via la bibliothèque gdk-pixbuf. Je fais un appel à gdk_pixbuf_save, qui enregistre l'image dans le format que j'ai choisi. J'ai accès au code de gestion de ce format graphique (je l'ai écrit), et l'écriture des données se fait via un unique fwrite (mais sans fflush ensuite, mais il est normalement fait automatiquement quand le fichier est fermé juste après).

Problème : souvent, je n'ai plus d'enregistrement pendant près de 0,2 à 0,8 secondes, tandis que d'autres fois je tourne à 29 images/secondes. Le pire c'est que le comportement n'est assez différent d'une exécution à l'autre. Exemple avec ces graphiques représentant en abcisse le numéro d'image et en ordonnée le temps d'enregistrement de l'image en question.

image_perdue
image_perdue
image_perdue
image_perdue
image_perdue

J'ai d'abord pensé à une lenteur du disque dur, mais en enregistrant sur un ramdisk, même problème. Je n'ai aucun autre processus qui consommerait beaucoup de CPU et pourrait ralentir le bestiau. J'ai tenté d'augmenter la priorité coté processus et E/S avec nice et ionice, sans succès. Et puis En utilisant strace, j'ai pu me rendre compte que mon fwrite est traduit en deux appels à write, et que le "décrochage" survient toujours au même endroit : entre ces deux write.

Tout ça s'exécute sur une Fedora Core 6 (base de RHEL 5).

Quelqu'un aurait une idée d'où ça peut venir ? Un cache quelconque qui coince ?

Je suis preneur de toute piste…

  • # Mauvais OS

    Posté par  (site web personnel) . Évalué à 2.

    Ah bé non, sorry, c'est une CentOS 5 (équivalent RHEL 5) et pas une Fedora 6.
    • [^] # Re: Mauvais OS

      Posté par  (site web personnel) . Évalué à 2.

      fflush suivi de fsync n'a rien changé. Mais j'ai vu un pattern de ralentissement apparaître plus facilement, toutes les 7 secondes environ.
    • [^] # Re: Mauvais OS

      Posté par  (site web personnel) . Évalué à 2.

      Autre remarque : la taille des données écrites influence peu ce comportement. En temps normal j'écris 80Ko, mais même avec des écritures de 1Ko cela se produit.
      • [^] # Re: Mauvais OS

        Posté par  (site web personnel) . Évalué à 2.

        Ah bé non, j'ma gourré. Plus c'est gros plus la latence est élevée. Est-ce que ça pourrait être un problème de temps de latence de l'ordonnanceur du kernel ?
  • # Faut faire du Realtime!

    Posté par  . Évalué à 3.

    Bonjour,

    à mon avis, ce qui se passe c'est que de temps en temps le système de fichier à besoin de faire quelques opérations, par exemple réorganiser la liste des fichiers, ou alors il y a un autre programme qui accède au disque, qui font que tes requêtes sont mises en attentes.

    Personnellement, je verrais deux solution:
    - il y a beaucoup de gens qui ont déjà réfléchi à ce genre de problèmes, de la est apparu la notion de "temps réel" (real-time). La bonne solution consiste donc à utiliser un noyau avec les patchs qui vont bien (je ne suis plus au courant de l'actualité de ce côté là) et d'utiliser l'API correspondante dans ton programme.

    - l'autre solution consiste à repenser ton programme. Tu sait que le système ne va pas te garantir les temps de sauvegarde, il faut donc séparer en deux:
    * un process ou thread qui va récupérer les images au fur et à mesure;
    * un autre, qui prend en charge la sauvegarde au fur et à mesure.
    Attention à la communication entre les deux si tu ne veux pas voir réapparaître de limite!

    Bon courage,
    Christophe.
    • [^] # Re: Faut faire du Realtime!

      Posté par  (site web personnel) . Évalué à 3.

      J'ai quelques notions de temps réel mais je n'en ai fait qu'à l'école, il y a déjà quelques années. Mon noyau n'est pas patché temps réel. J'en arrive à peu près à la même conclusion que toi, mais j'ai encore du mal à réaliser... Est il vraiment possible que le kernel m'impose une latence de l'ordre de la seconde ?!! Dans mes tests j'ai vu du 0,8 s, et cela augmente avec la taille des données à écrire. Ce serait le système de fichier qui me bloquerait alors...

      Heureusement c'est un mode non-nominal de mon programme, normalement j'analyse les images à la volée sans les stocker. Alors je pense que je vais stocker les images dans une file d'attente et les écrire en fin de capture, afin de ne pas ralentir cette dernière.
      Merci pour tes conseils.
      • [^] # Re: Faut faire du Realtime!

        Posté par  . Évalué à 2.

        Est il vraiment possible que le kernel m'impose une latence de l'ordre de la seconde ?!!
        Oui.
        Le noyau Linux vanilla n'est pas temps réel.
        Tu pourrais essayer avec d'autres ordonnanceurs d'E/S.
        Je suppose que RHEL utilise CFQ par défaut, tu peux essayer avec deadline.
    • [^] # Re: Faut faire du Realtime!

      Posté par  . Évalué à 4.

      Effectivement, il a probablement atteint les limites d'une écriture bufferisée, donc la solution serait effectivement de passer à un noyau temps-réel ou de repenser les I/O.

      Même si un noyau patché PREEMPT-RT n'est pas un noyau temps-réel à strictement parler (on parle plutôt de qualité de service), même fortement stressé, on arrive à des latences max de moins de 10 ms. L'avantage par rapport à un vrai noyau temps-réel comme Xenomai, c'est que c'est assez simple à mettre en oeuvre, et ça demande peu de modifications pour un bon programme.
      http://rt.wiki.kernel.org/index.php/HOWTO:_Build_an_RT-appli(...)

      Pour optimiser les I/O, quelques pistes :
      * écriture vectorisé (writev) : ça permet au noyau d'optimiser les I/O, les opérations sont atomiques, en général ça pulse bien. C'est une technique souvent utilisée dans la vision industrielle.
      * écriture asynchrone (man aio.h) : ça revient plus ou moins à l'idée de Christophe d'une gestion concurrente des écritures sans l'overhead lié à la gestion des threads. Un excellent article sur la question :
      http://www.ibm.com/developerworks/linux/library/l-async/?ca=(...)
  • # cache disque ?

    Posté par  (site web personnel) . Évalué à 1.

    Et si tu fsync à chaque fois, c'est plus regulier ?
    • [^] # Re: cache disque ?

      Posté par  (site web personnel) . Évalué à 2.

      Non, comme j'ai écrit plus haut, même comportement avec un fsync, ça décroche. Au départ j'avais pensé que j'étais peut être préempté, mais strace m'a montré que le décrochage avait toujours lieu au même moment, entre les 2 write des deux morceaux de mon image. Je n'imaginais pas que le kernel pouvait me bloquer pendant près d'une seconde, même sans patch temps réel, ça me paraissait énorme.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.