Sophie

Sophie

distrib > Mandriva > 9.0 > i586 > by-pkgid > 0d5cd12c82d627a82c59047e1ba7b8a9 > files > 1775

howto-html-fr-9.0-0.2mdk.noarch.rpm

<HTML>
<HEAD>
<TITLE>R&eacute;glages de haute pr&eacute;cision</TITLE>
</HEAD>
<BODY>
<H1>2. <A NAME="s2"></A>R&eacute;glages de haute pr&eacute;cision</H1>
<P>
<A HREF="IO-Port.html#toc2">Contenu de cette section</A></P>

<P></P>
<H2>2.1 <A NAME="ss2.1"></A> Temporisations</H2>

<P></P>
<P>Tout d'abord, je dois pr&eacute;ciser que, du fait de la nature
multi-t&acirc;ches
pr&eacute;emptive de Linux, on ne peut pas garantir &agrave; un programme en
mode
utilisateur un contr&ocirc;le exact du temps. Votre processus peut perdre
l'usage
du processeur &agrave; n'importe quel instant pour une p&eacute;riode allant
d'environ 
20 millisecondes &agrave; quelques secondes (sur un syst&egrave;me lourdement
charg&eacute;). N&eacute;anmoins, pour la plupart des applications utilisant
les ports
d'E/S, cela ne pose pas de probl&egrave;mes. Pour minimiser cet
inconv&eacute;nient, vous
pouvez augmenter la priorit&eacute; (avec <B>nice</B>) de votre programme.</P>
<P>Il y a eu des discussions sur des projets de noyaux Linux temps-r&eacute;el
prenant
ce ph&eacute;nom&egrave;ne en compte dans
<EM>comp.os.linux.development.system</EM>, mais
j'ignore leur avancement ; renseignez-vous dans ce groupe de discussion. Si
vous en savez davantage, envoyez-moi un message...</P>
<P>Maintenant, commen&ccedil;ons par le plus facile. Pour des d&eacute;lais de
plusieurs
secondes, la meilleure fonction reste probablement <B>sleep(3)</B>. Pour
des attentes de quelques dixi&egrave;mes de secondes (20 ms semble un minimum),
<B>usleep(3)</B> devrait convenir. Ces fonctions rendent le processeur aux
autres processus, ce qui ne g&acirc;che pas de temps machine. Consultez les
pages
des manuels pour les d&eacute;tails.</P>
<P>Pour des temporisations inf&eacute;rieures &agrave; 20 millisecondes environ
(suivant la
vitesse de votre processeur et de votre machine, ainsi que la charge du
syst&egrave;me), il faut proscrire l'abandon du processeur car l'ordonnanceur de
Linux ne rendrait le contr&ocirc;le &agrave; votre processus qu'apr&egrave;s
20 millisecondes
minimum (en g&eacute;n&eacute;ral). De ce fait, pour des temporisations courtes,
<B>usleep(3)</B> attendra souvent sensiblement plus longtemps que ce que
vous avez sp&eacute;cifi&eacute;, au moins 20 ms.</P>
<P>Pour les d&eacute;lais courts (de quelques dizaines de microsecondes
&agrave; quelques
millisecondes), la m&eacute;thode la plus simple consiste &agrave; utiliser
<B>udelay()</B>, d&eacute;finie dans <B>/usr/include/asm/delay.h</B>
(<B>linux/include/asm-i386/delay.h</B>). <B>udelay()</B> prend comme
unique argument le nombre de microsecondes &agrave; attendre (unsigned long)
et ne
renvoie rien. L'attente dure quelques microsecondes de plus que le
param&egrave;tre
sp&eacute;cifi&eacute; &agrave; cause du temps de calcul de la dur&eacute;e
d'attente 
(voyez <B>delay.h</B> pour les d&eacute;tails).</P>
<P>Pour utiliser <B>udelay()</B> en dehors du noyau, la variable (unsigned
long) <B>loops_per_sec</B> doit &ecirc;tre &ecirc;tre d&eacute;finie avec
la bonne valeur.
Autant que je sache, la seule fa&ccedil;on de r&eacute;cup&eacute;rer cette
valeur depuis le
noyau consiste &agrave; lire le nombre de BogoMips dans
<B>/proc/cpuinfo</B> puis
&agrave; le multiplier par 500000. On obtient ainsi une &eacute;valuation
(impr&eacute;cise) 
de <B>loops_per_sec</B>.</P>
<P>Pour les temporisations encore plus courtes, il existe plusieurs solutions.
Ecrire n'importe quel octet sur le port 0x80 (voyez plus haut la
mani&egrave;re de
proc&eacute;der) doit provoquer une attente d'exactement 1 microseconde, quelque
soit le type et la vitesse de votre processeur. Cette &eacute;criture ne devrait
pas avoir d'effets secondaires sur une machine standard (et certains
pilotes de p&eacute;riph&eacute;riques du noyau l'utilisent). C'est ainsi que
<B>{in|out}{b|w}_p()</B> r&eacute;alise normalement sa temporisation (voyez
<B>asm/io.h</B>).</P>
<P>Si vous connaissez le type de processeur et la vitesse de l'horloge de la
machine sur laquelle votre programme tournera, vous pouvez coder des
d&eacute;lais
plus courts "en dur" en ex&eacute;cutant certaines instructions
d'assembleur
(mais souvenez-vous que votre processus peut perdre le processeur &agrave; tout
instant, et, par cons&eacute;quent, que l'attente peut, de temps &agrave;
autres, 
s'av&eacute;rer beaucoup plus importante). Dans la table suivante, la
dur&eacute;e d'un 
cycle d'horloge est d&eacute;termin&eacute;e par la vitesse interne du
processeur~; 
par exemple, pour un processeur &agrave; 50MHz (486DX-50 ou 486DX2-50), un
cycle prend
1/50000000 seconde.</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
Instruction   cycles sur i386     cycles sur i486
nop                   3                   1
xchg %ax,%ax          3                   3
or %ax,%ax            2                   1
mov %ax,%ax           2                   1
add %ax,0             2                   1

{source : Borland Turbo Assembler 3.0 Quick Reference}
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>(d&eacute;sol&eacute;, je n'ai pas de valeurs pour les Pentiums~ ce
sont probablement
les m&ecirc;mes que pour i486)</P>
<P>(Je ne connais pas d'instruction qui n'utilise qu'un seul cycle sur i386)</P>
<P></P>
<P> Les instructions <B>nop</B> et <B>xchg</B> du tableau n'ont pas
d'effets de bord. Les autres peuvent modifier le registre des indicateurs,
mais cela ne devrait pas avoir de cons&eacute;quences puisque <B>gcc</B> est
sens&eacute; le d&eacute;tecter.</P>
<P>Pour vous servir de cette astuce, appelez <B>asm("intruction");</B> dans
votre programme. Pour "instruction", utilisez la m&ecirc;me syntaxe que dans la
table pr&eacute;c&eacute;dente ; pour avoir plusieurs instructions dans un
m&ecirc;me
<B>asm()</B>, faites <B>asm("instruction; instruction;
instruction");</B>. Comme <B>asm()</B> est traduit en langage
d'assemblage "inline" par gcc, il n'y a pas de perte de temps
cons&eacute;cutive &agrave; un &eacute;ventuel appel de fonction.</P>
<P>L'architecture des Intel x86 n'autorise pas de temporisations
inf&eacute;rieures &agrave;
un cycle d'horloge.</P>
<P></P>

<H2>2.2 <A NAME="ss2.2"></A> Chronom&eacute;trages</H2>

<P></P>
<P>Pour des chronom&eacute;trages &agrave; la seconde pr&egrave;s, le plus
simple consiste
probablement &agrave; utiliser <B>time(2)</B>. Pour des temps plus fins,
<B>gettimeofday(2)</B> fournit une pr&eacute;cision d'une microseconde (voyez
toutefois, plus haut, les remarques concernant l'ordonnancement).</P>
<P>Si vous d&eacute;sirez que votre processus re&ccedil;oive un signal
apr&egrave;s un certain 
laps de temps, utilisez <B>setitimer(2)</B>. Consultez les pages des manuels
des diff&eacute;rentes fonctions pour les d&eacute;tails.</P>
<P></P>

<HR>
<P>
Chapitre <A HREF="IO-Port-3.html">suivant</A>,
Chapitre <A HREF="IO-Port-1.html">Pr&eacute;c&eacute;dent</A>
<P>
Table des mati&egrave;res de <A HREF="IO-Port.html#toc2">ce chapitre</A>,
 <A HREF="IO-Port.html#toc">Table des mati&egrave;res</A> g&eacute;n&eacute;rale</P>
<P>
<A HREF="IO-Port.html">D&eacute;but</A> du document,
 <A HREF="#0"> D&eacute;but de ce chapitre</A></P>
</BODY>
</HTML>