Forum Programmation.autre Polling ou Interrupt ?

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
4
25
mar.
2019

Bonjour,

Dans le cas de lecture socket, sous quelles conditions doit-on préférer faire du polling plutôt que des interruptions ?
J'image peut-être à tort, que le traitement de l'interruption est assez long (Ne serait-ce que le réveil du processus et du chargement de son contexte par le noyau).

Imaginons que cela prenne 4 secondes. Cela donne le schéma suivant : (m==messayge, tt==traitement, p==processus)

                    tt1
                    ^
     p2  ───────xxxx────────────────────────────────>t
                ^              
                │              
                │              
     p1  ───────┴───────────────────────────────────>t
                m1              

Dans le cas du polling :

Polling 10s

            tt1                 tt2
            ^                   ^
 p4 ───────x┼─────────┼──xxxxxxx┼─────────┼───>t
           ^             ^
           │             │
           │             │
 p3 ───────┴─────────────┴─────────────────────>t
           m1            m2

Pro:
Si le message arrive 1s avant la tentative de lecture. On aura attendu qu'1s.

Cons:
Si le message arrive 7s avant la tentative de lecture. On aura attendu 7s ! Alors que par interruption, on aurait attendu 4s.
Le choix du polling est totalement arbitraire :
Un polling trop réduit et on prend inutilement du cpu.
Un polling trop long et l'application manque de réactivité avec toutes les conséquences qu'on imagine.
```
Comment trouver une valeur correcte ?

  • # Ce que j'aurais fais avec le polling

    Posté par  . Évalué à 3.

    Hello,

    Je ne suis clairement pas confirmé là dedans mais avec le polling j'aurais pris une valeur de temps variable en fonction de ce que tu traites.

    Par exemple si lors de la lecture il n'y a aucun message polling += 1s (jusqu'à une valeur max)
    et à l'inverse si tu as du traitement tu diminues cette valeur (jusqu'à une valeur min pareil).

    C'est ce que je ferai je ne sais pas si c'est ce qu'il y a de mieux :D

    • [^] # Re: Ce que j'aurais fais avec le polling

      Posté par  . Évalué à 2.

      Bonne idée !

      Peut-être que ce temps variable pourrait être ajuster au carré [1, 2, 4, 8..]
      J'ai peur qu'incrémenter d'une seconde à chaque tentative échouée de lecture, induise un latence quand subitement des messages arrivent.

      A tester en tout cas ! merci :)

      • [^] # Re: Ce que j'aurais fais avec le polling

        Posté par  . Évalué à 2. Dernière modification le 25 mars 2019 à 16:05.

        De rien :)

        Oui après tu as pleins de scénarios que tu peux tester et optimiser en fonction de ton besoin.
        Comme par exemple rendre le polling bas dès que tu as un message : Commencer à la valeur max, passer à la valeur min dès que tu as des messages puis remonter au fur et à mesure vers la valeur max. Comme ça si tu commences à avoir beaucoup de trafic tu es sûr que ton polling est au plus rapide, et dès que ça se calme le polling remonte doucement pour ne pas avoir trop d'impact :) Le soucis avec celui-ci c'est lors de la réception de ton premier message après une période de blanc

        • [^] # Re: Ce que j'aurais fais avec le polling

          Posté par  . Évalué à 1. Dernière modification le 25 mars 2019 à 16:14.

          Oui exactement, je crois que tu as finalement bien résumé mon problème : Le souci du premier message après une période de blanc.

          Peut-être qu'un début de solution serait, dans ce cas là, quand le polling est trop espacé, basculer sur de l'interruption. Encore une fois : A tester !

          Bon, je garde bien à l'esprit qu'il ne semble pas y avoir de solution miracle ;)

  • # Problématique Temps Réel

    Posté par  . Évalué à 3.

    Pour maîtriser le temps Réel, il faut voir ça comme de l’échantillonnage en fréquence. Il te manque une donnée : le temps de réponse voulue.

    Question 1 : À la réception du message au bout de combien de temps, l’action doit être réalisée ?

    Question 2 : À la lecture du message, en combien de temps l’action est réalisée ?

    À partir de là, tu peux déterminer et prouver que ton logiciel répond en temps et en heure.

    Dans ton exemple, la réponse à la question 2 est : 4s.

    Avec 4s de traitement, ta période ne peut descendre en dessous de 4s (voir un poil plus).
    Disons 5s. Donc, tu peux garantir que le traitement sera réaliser 10s après la réception. Des fois ce sera 4,1s des fois 9,1s. Mais toujours moins de 10s.

    Si tu n’as pas cette problématique de temps de réponse voulu, j’aurais tendance à utiliser des solutions bloquante de type : select pour la lecture et communication inter thread pour prévenir en sécurité de la réception. Cette solution sera sûrement plus réactive, mais le temps non garanti.

    Question : As-tu vraiment besoin de la maîtrise de ton temps réel pour ton application ? Tu ne donne pas beaucoup de détail (OS ou Bare metal), plateforme, etc.

    Si tu as un CPU multi cœur par exemple, et que tu peux dédier un cœur à ça, alors, tu peux faire un thread bloquant qui va te garantir une réponse en moins de 5s. Mais ton cœur n’est pas disponible pour autre chose… c’est un choix de design à faire.

    • [^] # Re: Problématique Temps Réel

      Posté par  . Évalué à 1.

      Merci de me faire mettre le doigt sur des idées et des questions que je ne me posais pas ! J'avoue n'avoir aucune compétence en temps-réel.

      L'application était la suivante. Je désirais dans le cadre du développement d'un très modeste jeu clients/server à forts échanges asynchrones, développer une couche réseau. Avant que je ne pose ma question, on m'a recommandé d'utiliser des bibliothèques qui feront le taf toujours mieux que moi. Soit. Mais ma question reste entière, vraiment.

      Pour répondre à la question 1, même si c'est assez subjectif, l'action doit être réalisée suffisamment vite pour rendre le jeu fluide et cohérent. Même si des mécanismes de compensation et prédiction sont mis en place coté client, ces mécanismes ont leurs limites. Il faut rapidement que le client est la même vision que le serveur.

      Je reste avec le sentiment que même si les échanges sont à mon échelle très nombreux, à l'échelle d'un cpu moderne c’est peut-être peanuts et en cas de polling, 99% de mes lectures sockets n'aboutiront pas car rien n'a été reçu. C'est nul, tu en conviendras :(

  • # Avec des boucles d'event

    Posté par  . Évalué à 2.

    D'expérience, c'est pas une bonne idée de gérer ça dans des handler de signaux (je pense que c'est ce que tu veux dire par interruption ?).

    Je comprends pas bien ce que tu veux faire, mais ça devrait t'aider à mieux voir le truc :

    Si tu as des impératifs de temps de traitement rapide de plusieurs connections, je pense qu'il vaut mieux sauver les événements dans ton cycle de read (ou de poll) sur to FD et laisser le traitement de ceux-ci dans un autre thread.

    C'est plus simple avec un bout de code genre :

    int event_process_step(void)
    {
       struct event ev;
    
        if (pop_event(&ev) == 0)
            return 0;
    
        return process_event(&ev);
    }
    
    int event_read_step(int fd)
    {
        struct event ev;
        int ret;
    
        ret = read(fd, &ev, sizeof ev);
        if (ret == sizeof ev)
           ret = push_event(&ev);
        else
            ret = -1;
    
        return ret;
    }
    
    /*
     * Soit avec des threads
     */
    void *thread_read(void *arg)
    {
        struct poll_table *table = arg;
    
        for (;;) {
            fd = poll_get_fd(table);
            if (fd < 0)
                break;
            if (fd == 0)
                break;
           if (event_read_step(fd) < 0)
                   break;
        }
    
       return NULL;
    }
    
    void *thread_process(void *arg)
    {
        for (;;) {
            int worked;
    
            worked = event_process_step();
            if (workded < 0)
                break;
            if (worked == 0)
                more_work();
        }
    
       return NULL;
    }
    
    /*
     * Soit sans thread
     */
    void loop_process(struct poll_table *table)
    {
    
        for (;;) {
            int worked;
    
            fd = poll_get_fd(table);
            if (fd < 0)
                break;
            if (fd == 0)
                break;
           if (event_read_step(fd) < 0)
                   break;
    
            worked = event_process_step();
            if (workded < 0)
                break;
            if (worked == 0)
                more_work();
         }
    }
    
    /*
     * Ou même avec un peu de repartition de charge
     */
    void loop_process_fair(struct poll_table *table)
    {
    
       for (;;) {
            int worked;
    
            worked = 0;
            while (worked < MAX_READ_WORK) {
    
                fd = poll_get_fd(table);
                if (fd < 0)
                    break;
                if (fd == 0)
                    break;
               if (event_read_step(fd) < 0)
                       break;
    
               worked ++;
           }
    
            while (worked < MAX_PROCESS_WORK) {
    
                done = event_process_step();
                if (done < 0)
                    break;
                if (done == 0)
                    break;
    
                worked ++;
            }
    
            more_work();
    
        }
    }

    Bref, tu vois l'idée …

    • [^] # Re: Avec des boucles d'event

      Posté par  . Évalué à 1.

      (je pense que c'est ce que tu veux dire par interruption ?).

      Tout à fait !

      Ton code est intéressant, mais tu fais le choix de faire du polling. Dans un thread dédié, mais du polling quand même.

      Bon, après avoir pris le problème dans tous les sens, il semble que ce soit la meilleure solution.

      merci !

Suivre le flux des commentaires

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