locked
Thread TIME_CRITICAL / Synchro RRS feed

  • Question

  • Bonjour,

    J'ai un probléme avec la callback de WinMM (WaveIn) qui est a priori appellée par un thread TIME_CRITICAL.
    J'ai un traitement un peu gourmand dans ma callback et j'ai l'impression que ce thread (du coup non préhemptable) me bouffe plusieurs Quantum CPU d'autre thread tres important (aussi TIME_CRITICAL).

    Je me demande comment forcer un thread  TIME_CRITICAL a rendre la main de temps a en temps.

    Mes autre thread ne font qu'attendre des resosurces :
    Port COM : ReadFile bloquant
    Socket : Recv Bloquant

    Par contre il doivent être réactif, et comme à priori WinMM leur bouffe leur quantum CPU je me retrouve avec des erreurs de synchro de précisement 128 ms (en comptant les echantillons audio par 8 à 8000 Khz) Cette valeur m'intrigue un peu car c'est toujours 128 ms.

    * Est ce que quelqu'un connait le moyen de "suspendre" le thread TIME_CRITICIAL seulement pour 1 quantum (je ne souhaite pas le suspendre définitivement).

    * Je me demandais si je mettait un WaitForMultipleObject() dans la callback WinMM avec 2 evenements controlés par le COM et/ou par le Socket et un timeout à 0. Est ce que mon Thread thread sera préhempté a ce moment la pour laisser le temps au 2 autres threads mettre a 1 leur Event ou est ce que je me retrouverais avec le même probléme ?
    Je veux dire par la est ce que WaitForMultipleObject avec un timeout à 0 mettra mon thread dans la file d'attente pour le prochain quantum, laissant le temps au autres de mettre l'envent a l'etat haut ?

    J'espere que ce n'est pas trop incompreenssible...
    (désolé pour l'expression)

    Molux
    vendredi 25 juillet 2008 11:19

Toutes les réponses

  • Bonjour,

     

    La fonction CeSetThreadQuantum() permet de fixer le quantum d'un thread sous WinCE. La valeur 0 vaut pour "run to completion" et la valeur par défaut est 100 ms.

     

    Attention toutefois à la priorité des threads car la commutation de contexte sur quantum ne se fait que si aucun thread de priorité supérieure n'est en exécution. C'est à dire qu'il est possible que le thread WinMM ne soit préempté par aucun autre thread si sa priorité est la plus haute.

     

    Il est possible connaitre les priorités des threads ainsi que de voir le chronogramme d'exécution avec les outils "Remote Perf monitor" et "Kernel Tracker".

     

    Pour forcer un passage dans la file d'attente on peut faire un Sleep(0) mais si le thread a une priorité plus haute cela devrait être sans effet. Pour le forcer à donner la main il faudrait faire un Sleep(1) ce qui donnera 1 ms aux autres Threads pour tourner.

     

    Une autre solution consisterait peut être à forcer une descente de priorité du thread en appelant CeSetThreadPriority(GetCurrentThread()) en début de routine WinMM (Attention à ne pas utiliser SetThreadPriority qui ne donne pas accès aux 256 niveaus de CE).

     

    Thierry Joubert - THEORIS

     

     

    samedi 26 juillet 2008 06:55
  • Bonjour Thierry,

    Wahou, je suis impressionné de la precision des informations et des conseils.
    Concernant le sleep, je ne sais même pas pourquoi je n'y est pas pensé avant, (le tête dans le guidon surement....)
    En tous les cas un enorme MERCI pour ce coup de main

    Je vais essayer ca et je reviens donner le resultat

    Merci encore

    Molux
    lundi 28 juillet 2008 09:32
  • Bonjours,

     

    Je viens de faire quelques essais sur les priorités et les quantum de mes threads pour essayer d'y voir plus clair avec les fonctions proposées (CeGetQuantum, CeGetThreadPriority, etc...) j'ai fais quelques essais empirique avec le Sleep() mais cela ne donne pas grand chose de mieux. Tous ça est codé en C++ (EVC4)

     

    J'ai un comportement assez étrange avec la partie réseau.

     

    1/ MES RELEVES

    Voici les paramètres par défaut que j'obtiens après avoir démarré mes 3 threads.

     

    * Thread PORT COM :

    Se bloque sur ReadFile et attend un octet (octets par octets). Une fois la fin de trame détectée le buffer est interprétée.

    - Priority : 251

    - Quantum : 50 ms

     

    * Thread NET :

    J'ai en fait 2 threads, J'ai un thread qui me sert a reconnecté automatiquement et qui lance le seconde thread qui bloque sur le Recv() du socket (TCP) et traite les trames reçus. (Mode dit a priori "Synchro")

    - Priority : 251

    - Quantum : 50 ms

     

    * Thread WINMM :

    WinMM est lancé en mode CALLBACK a chaque buffer, j'ai un traitement qui calcul le Leq du signal

    Voici les parametres que j'obtiens dans la Callback de WinMM sur le WIM_OPEN

    - Priority : 249

    - Quantum : 50 ms

    Je fais mes essais avec 20 buffers de 512 octets chacun en 16 bits

    soit 32 ms par buffer et 640 ms de tampon au total.

     

    J'ai aussi bien sur un thread de la pompe a message de l'interface (une Dialog).

     

    2/ EXPLICATION:

    En gros un variable MS est incrémentées toutes les millisecondes (8 échantillons) dans la CALLBACK WinMM (Tread WINMM) et réinitialisée lors de la réception du TOP Synchro sur le port COM (Thread PORT COM) Le thread NET reçois des trames du serveur, dont une qui demande le nombre d'échantillons écoulés depuis le début du Top Syncro.

     

     

    3/ PROBLEME:

    Presque Tout fonctionne et avec une bonne réactivité sauf que lorsque je demande le nombre de seconde écoulée depuis le top synchro je récupère que des multiples de 128 ms Etrange. (J'ai aussi très rarement cette dérive sur mon calcul de Leq).

     

    4/ INVESTIGATIONS:

    J'ai déjà regardé mes codes et essayé de les optimiser et simplifier au maximum (J'ai enlevé tous les appel a l'interface, et le superflu) jusqu'a me demandé si ce n'était pas un problème de synchro de thread.

     

    Si je regarde la documentation (MSDN) je lis que la priorité d'un thread va de 0 à 254. 0 étant la plus prioritaire.

     

    Mon thread WinMM semble être le plus prioritaire que les 2 autres. J'ai donc essayé de modifier les priorités et rien n'y fait, j'ai toujours ce problème de 128 ms lors de la demande par le serveur. J'ai même essayé des mettre les 2 threads PORT COM et NET en priorité 0. et Toujours rien enfin toujours mes multiples de 128 J'ai alors rajouté un Sleep(0) ou Sleep(1) et la rien non plus

     

    5/ INTUITION:

    J'ai l'impression peut être à tord que WinMM ou autre chose me bouffe des quantums du thread Reseau (ou Port COM).

    Je m'attendais bien à avoir des multiples de 32 ms (taille de mes buffers) à la limite mais la 128 ms ça me fait 4 buffers WinMM avec le sleep par exemple WinMM aurait au moins du être préempté par le thread NET toutes les 32 ms non ?

    De plus j'ai fais plusieurs essais avec différentes taille et nombres de buffer et je constate toujours ces multiples de 128 ms

     

    J'ai bien sûr vérifié que j'avais coupé tous les autres processus, enfin ce du gestionnaire de tache des PPC.

    Je sais aussi qu'il existe les processus system du noyau qui tourne en tache de fond, ne serait il pas eux qui me bouffe des multiples 128 ms

     

    Y'a t'il un moyen de rendre une application (Ensembles de thread) encore plus prioritaire que les autres applications (Enfin la question qui se cache derrière c'est est ce que WinCE schedule un seul et unique ensemble de thread toutes appli confondues ou bien y'a t'il une priorité pour les applications aussi ?)

     

    Merci de me donner vos intuitions sur ce cas.

     

    Molux

     

    PS je n’ai pas encore eu le temps d’évaluer la solution de diagnostique, il faut que je considère le budget.

    mardi 29 juillet 2008 10:44
  • Bonjour,

     

    Il n'est pas évident de comprendre le fonctionnement de l'application multi-tâches d'après les qq lignes de description (disons que je n'ai pas le temps de reprendre tt cela sur un chronogramme), deux remarques toutefois:

     

    1/ Le scheduler ne connait QUE les threads, les processus sont des zones mémoire.

     

    2/ La granularité des mesures de temps est peut-etre tout simplement due à la granularité de l'horloge sur cette plateforme (128 ms ça me parait beaucoup mais un test confirmerait).

     

    Encore une fois l'outil "Kernel Tracker" devrait permettre de visualiser si un thread "vole des cycles" pendant la transmission des buffers.

     

    Attention aussi au comportement du ReadFile sur Port série, il peut être dépendant du paramétrage du pilote (fonctions CommDCB)

     

    Cordialement,

    Thierry Joubert - THEORIS

    samedi 2 août 2008 04:50
  • Bonjour Thierry,

    Effectivement, je vous remercie déja de m'ecouter et de me conseillez comme vous le faites.

    * Concernant le "Kernel Tracker" je ne peux pas l'utiliser sur les HTC ils n'ont pas compilé l'option sur cette plateforme cc'est tres domage j'aurais gagné un temps fou
    * Concernant le Port série j'ai fais très attention au parametrage j'ai fais plein d'essais "Mono threadé" pour trouver l'utilisation optimales du ReadFile.

    Je vais essayé de vous fournir un chronogramme si cela ne vous pose pas de probléme de jeter un oeil dessus

    Cordialement

    Molux






    lundi 4 août 2008 07:15
  • Bonjour

     

    Je suis en congés à partir de mercredi, de retour fin aout...

     

    Concernant la routine MMtimer, ce n'est pas une bonne idée de la faire "longue", il serait préférable du lui faire déclencher rapidement un évènement qui libère un thread de priorité inférieure dans lequel se déroule le traitement "long".

     

    Cordialement,

    Thierry Joubert - THEORIS

     

     

    lundi 4 août 2008 20:50