GTAOnline.net

San Andreas Multiplayer (sa:mp) => Scripting SA-MP [Pawn center] => Discussion démarrée par: 3klips le 21 Novembre 2009, 22:43:13

Titre: Timer imprécis.
Posté par: 3klips le 21 Novembre 2009, 22:43:13
Bonjour, voila, je suis en train de créé un petit FS de course, alor pour le chrono, je calle un peu car les Timer sont très imprécis, 1 seconde = 1,1 seconde, des fois 1 seconde = 1,5, y a-t-il des soluces pour contourner ce probleme? Merci
Titre: Re : Timer imprécis.
Posté par: Ssk le 21 Novembre 2009, 23:08:39
non dommage

Pour t expliquer pourquoi c' est imprecis c 'est un peu long mais c' est comme ca sur les ordinateur car le CPU travail sur un process a la fois donc c' est jamais precis


trop flemard pour expliquer lol
Titre: Re : Timer imprécis.
Posté par: cristab le 21 Novembre 2009, 23:24:21
en gros cpu qui travaille comme toi a l'ecole il ralentit
Titre: Re : Timer imprécis.
Posté par: 3klips le 21 Novembre 2009, 23:44:27
Argh dommage, je dois faire un chrono avec un gettime un truc comme sa pour avoir quelque chose de précis alor..
Je vais regarder d'autre FS.
Titre: Re : Timer imprécis.
Posté par: Ssk le 22 Novembre 2009, 11:59:38
Je te recherche la page qui explique tout ca ^^


Apres avoir tout reinstaller mon tit frere ma retirer Windows >.<
Titre: Re : Timer imprécis.
Posté par: Syg le 25 Novembre 2009, 12:21:58
Un timer n'est pas liés au CPU mais à l'horloge du PC qui elle est très précise.
Il ne serait donc pas normal qu'un timer identique varie selon qu'il est exécuté sur une machine ou sur une autre.
Sous Windows, en C, les timers sont très précis.

Je me suis donc décidé à faire des tests sur les timers pour découvrir le pourquoi du comment des timers de SAMP.

Voici le gamemode que j'ai utilisé pour mes tests :
#include <a_samp>

#define VALEUR_TIMER 300

forward MonTimer ();
new T1, T2;

main ()
{
}

public OnGameModeInit ()
{
// Set timer of 1 second.
SetTimer ("MonTimer", VALEUR_TIMER, 1);
T1 = GetTickCount ();
return 1;
}

public MonTimer ()
{
T2=GetTickCount();
printf("Difference :  %d %%", (T2-T1-VALEUR_TIMER)/(VALEUR_TIMER/100));
T1=T2;
}

J'ai fait plusieurs tests en modifiant la valeur de VALEUR_TIMER
Le résultat est encourageant, la différence est toujours de 17 % (du moins sur ma machine du boulot).
En affinant les calculs, la différence est en fait de 17.2 %
Il semblerait que ce soit un bug de SAMP.

NB : J'aimerais savoir si cette valeur est la même sur d'autres machines. Donc si quelqu'un pouvait faire le test et poster les résultats ici, ce serait cool, merci.

Mais il est très facile de trouver la valeur qui permet d'avoir exactement le temps qu'on veut.
Par exemple pour avoir un timer  qui "tombe" toutes les 1000 ms, il suffit de mettre la valeur du timer à 1000/1.172 = 853 ms.

Exemple :
#include <a_samp>

#define VALEUR_TIMER 853

forward MonTimer ();

main ()
{
}

public OnGameModeInit ()
{
// Set timer of 1 second.
SetTimer ("MonTimer", VALEUR_TIMER, 1);
return 1;
}

public MonTimer ()
{
printf ("GetTickCount = %d", GetTickCount());
}

Voici le résultat :
[12:01:28] GetTickCount = 786283984
[12:01:29] GetTickCount = 786284985
[12:01:30] GetTickCount = 786285987
[12:01:31] GetTickCount = 786286989
[12:01:32] GetTickCount = 786287991
[12:01:33] GetTickCount = 786288993
[12:01:34] GetTickCount = 786289995
[12:01:35] GetTickCount = 786290997
[12:01:36] GetTickCount = 786291999
[12:01:37] GetTickCount = 786293001
[12:01:38] GetTickCount = 786294003
[12:01:39] GetTickCount = 786295005
[12:01:40] GetTickCount = 786296007
[12:01:41] GetTickCount = 786297009
[12:01:42] GetTickCount = 786298011
[12:01:43] GetTickCount = 786299013


A 1 ou 2 ms seconde près, ce timer de 1 seconde n'est pas mal !!

On peut même se faire une fonction qui recalcule l'intervalle du timer automatiquement :
MonSetTimer (Fonction[], Intervalle, Repetition)
{
   SetTimer (Fonction, Intervalle/1.172, Repetition);
}

NB : Il n'est malheureusement pas possible de la faire pour la fonction SetTimerEx car elle a un nombre variable de paramètres

++
Syg
Titre: Re : Timer imprécis.
Posté par: cristab le 25 Novembre 2009, 12:35:45
voila de mon coter
[12:34:34] Difference :  8 %
[12:34:34] Difference :  8 %
[12:34:35] Difference :  8 %
[12:34:35] Difference :  12 %
[12:34:35] Difference :  10 %
[12:34:36] Difference :  11 %
[12:34:36] Difference :  11 %
[12:34:36] Difference :  11 %
[12:34:37] Difference :  10 %
[12:34:37] Difference :  10 %
[12:34:37] Difference :  11 %
[12:34:38] Difference :  9 %
[12:34:38] Difference :  6 %
[12:34:38] Difference :  10 %
[12:34:39] Difference :  10 %
[12:34:39] Difference :  7 %
[12:34:39] Difference :  10 %
[12:34:40] Difference :  11 %
[12:34:40] Difference :  10 %
[12:34:40] Difference :  11 %
[12:34:41] Difference :  10 %
[12:34:41] Difference :  8 %
[12:34:41] Difference :  8 %
[12:34:42] Difference :  10 %
[12:34:42] Difference :  9 %
[12:34:42] Difference :  11 %
[12:34:43] Difference :  8 %
[12:34:43] Difference :  10 %
[12:34:43] Difference :  8 %
[12:34:44] Difference :  8 %
[12:34:44] Difference :  6 %
[12:34:44] Difference :  10 %
[12:34:45] Difference :  5 %
[12:34:45] Difference :  10 %
[12:34:45] Difference :  11 %
[12:34:46] Difference :  11 %
[12:34:46] Difference :  11 %
[12:34:46] Difference :  12 %
[12:34:47] Difference :  10 %
[12:34:47] Difference :  11 %
Titre: Re : Timer imprécis.
Posté par: Ssk le 25 Novembre 2009, 12:52:14
7 à 13 %

Avec firefox et MediaPlayer Ouvert


Puis comme je sais que ca depend du CPU ( meme si tu le contredit syg ca depend du CPU j' en suis sur )


J ai ouvert Visual Studio

Et la ca a fait des pique a 85 % donc cela depend du CPU avec les programme Ouvert ^^


EDIT:

Voici un test que j ai fait

#include <a_samp>

#define VALEUR_TIMER 300

forward MonTimer ();
new T1, T2;

main ()
{
}

public OnGameModeInit ()
{
SetTimer("MonTimer",VALEUR_TIMER,1);
return 1;
}
public MonTimer ()
{
T1 = GetTickCount();
printf("Ms ecouler %d",T1 - T2);
T2 = T1;
}

Voici les valeurs


Ms ecouler 1145608
Ms ecouler 333
Ms ecouler 332
Ms ecouler 338
Ms ecouler 331
Ms ecouler 332
Ms ecouler 334
Ms ecouler 335
Ms ecouler 319
Ms ecouler 307
Ms ecouler 463
Ms ecouler 320
Ms ecouler 349
Ms ecouler 373
Ms ecouler 324
Ms ecouler 323
Ms ecouler 326
Ms ecouler 331
Ms ecouler 335
Ms ecouler 336
Ms ecouler 326
Ms ecouler 330
Ms ecouler 329
Ms ecouler 388
Ms ecouler 340
Ms ecouler 373
Ms ecouler 321
Ms ecouler 344
Ms ecouler 331
Ms ecouler 328
Ms ecouler 335
Ms ecouler 328
Ms ecouler 326
Ms ecouler 329
Ms ecouler 331
Ms ecouler 334
Ms ecouler 331
Titre: Re : Timer imprécis.
Posté par: Mr_C30 le 25 Novembre 2009, 13:22:58
tu as fait le test en C sausuke ?
Titre: Re : Timer imprécis.
Posté par: Ssk le 25 Novembre 2009, 13:27:27
non en pawn ^^


Je test en C dans quelque minutes pour voir ^^
Titre: Re : Timer imprécis.
Posté par: Syg le 25 Novembre 2009, 14:09:07
C'est quand même très bizarre car sur ma machine du boulot (Core 2 Duo), j'ai toujours 17 % de différence, ni plus ni moins.
Même lorsque j'ouvre des programmes.

En en réfléchissant, je pensais que les timers SAMP sont des timers Windows (qui fonctionne sur l'horloge du PC) mais en fait, ce n'est peut-être pas vrai car les timers Windows n'existent pas sous Linux.La team SAMP a certainement du les récrire pour que le code soit compatible avec les deux plateformes (Linux et Windows).

++
Syg
Titre: Re : Timer imprécis.
Posté par: Ssk le 25 Novembre 2009, 14:13:58
Voila la preuve de ce que je disais ^^


Qu'est-ce que vient faire l'OS là-dedans ?

Oh mais l'OS a tout à faire là-dedans : c'est lui qui contrôle les programmes qui tournent !
Votre programme va donc dire à l'OS : "Je dors, réveille-moi dans 1 seconde". Mais l'OS ne va pas forcément le réveiller au bout d'une seconde exactement.

En effet, il aura peut-être un peu de retard (un retard de 10ms en moyenne environ, ça dépend des PC). Pourquoi ? Parce que votre CPU ne peut travailler que sur un programme à la fois. Le rôle de l'OS est de dire au CPU ce sur quoi il doit travailler : "Alors, pendant 40ms tu vas travailler sur firefox.exe, puis pendant 110ms tu vas travailler sur explorer.exe, et ensuite pendant 80ms tu vas travailler sur programme_sdl.exe, puis tu vas retravailler sur firefox.exe pendant 65ms" etc etc...
L'OS est le véritable chef d'orchestre de l'ordinateur !

Maintenant, imaginez qu'au bout d'une seconde un autre programme soit encore en train de travailler : il faudra qu'il ait fini de travailler pour que votre programme puisse "reprendre la main" comme on dit, c'est-à-dire être traité à nouveau par le CPU.

Tout ça pour dire quoi ? o_O


Ooops, excusez-moi j'étais en train de dériver :-°
En gros, j'essayais de vous expliquer que votre CPU ne pouvait pas gérer plus d'un programme à la fois. Pour donner l'impression que l'on peut faire tourner plusieurs programmes en même temps sur un ordinateur, l'OS "découpe" le temps et autorise les programmes à travailler au tour par tour.

Or, cette gestion des programmes est très complexe et on ne peut donc pas avoir la garantie que notre programme sera réveillé au bout d'une seconde exactement.

Toutefois, ça dépend des PC comme je vous l'ai dit plus haut. Chez moi, la fonction SDL_Delay est assez précise.

A cause de ce problème de "granularité du temps", vous ne pouvez donc pas mettre en pause votre programme pendant un temps trop court. Par exemple, si vous faites :
Code : C

1



SDL_Delay(1);


Vous pouvez être sûrs que votre programme ne sera pas mis en pause 1ms mais un peu plus (peut-être 9-10ms).


En résumé : SDL_Delay c'est cool, mais ne lui faites pas trop confiance. Elle ne mettra pas en pause votre programme pendant le temps exact que vous indiquez.
Ce n'est pas parce que la fonction est mal codée, c'est parce que le fonctionnement d'un ordinateur est très complexe et ne permet pas d'être très précis à ce niveau.

Source: http://www.siteduzero.com/tutoriel-3-14136-maitrisez-le-temps.html (http://www.siteduzero.com/tutoriel-3-14136-maitrisez-le-temps.html)


Sinon Syg ton CPU est cadence a combien de Hertz ?


EDIT: Voici des test sur des timer d' une secondes c' est vraimenent pas précis quand on met secondes

Ms ecouler 1111
Ms ecouler 1117
Ms ecouler 1105
Ms ecouler 1109
Ms ecouler 1110
Ms ecouler 1110
Ms ecouler 1116
Ms ecouler 1107
Ms ecouler 1074
Ms ecouler 1096
Ms ecouler 1119
Ms ecouler 1115
Ms ecouler 1116
Ms ecouler 1110
Ms ecouler 1101
Ms ecouler 1113
Ms ecouler 1117
Ms ecouler 1109
Ms ecouler 1108
Ms ecouler 1112
Ms ecouler 1101
Titre: Re : Timer imprécis.
Posté par: Syg le 25 Novembre 2009, 22:41:02
Ce que tu cites dates un peu, les CPU de maintenant peuvent effectuer 2, 4 ou 8 instructions à la fois (dualcore, quadcore ou quadcore+hyperthreading comme le i7).
De plus, ton article parle d'un retard de 10 ms en moyenne, ce qui en vrai, c'est en fait la précision des timers sous Windows.
D'ailleurs, c'est de ça que parles cette article, qui est aussi valable pour la fonction Sleep() de Win32.

Les timers sous Windows sont gérés par interruptions (logicielles certes) mais reste à un niveau très bas.

Dans notre cas, et mes test le montre bien, le décalage n'est pas de 10 ms mais est proportionnel au temps du timer :
17 % dans le cas de ma machine au boulot (Core2 Duo 2.8 Ghz je crois)
17 % encore dans le cas de mon PC perso principal à la maison (Core2 Duo 3.16Ghz)
17 % encore dans le cas de mon deuxième PC perso (i7 920)

Je n'ai pas fait de tests sur un serveur Linux.

Les valeurs que tu montres sont conformes à ce que je trouve mais dans ton cas, la décalage est de 11 %.
Essaies le même test que celui que tu as fais avec 2 secondes puis 10 secondes pour ton timer, tu trouveras des valeurs de 2220 environs dans le premier cas et 11100 environs dans le second.

Voici un très court programme en C qui ressemble à celui de sazuke, il affiche le GetTickCount à chaque échéance du timer. Sa précision est impeccable si rien d'autre ne tourne et il y a un décalage de 10-15 ms lorsque je fait un "dir c: /s" en même temps, ce qui est conforme à l'article que tu cites (Je te conseille de l'essayer sazuke) :
#include <stdio.h>
#include <windows.h>

VOID CALLBACK MaFonctionTimer (HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
   /* Fonction nécessaire mais non utilisée */
}

void main (void )
{
HWND hwndTimer;
MSG msg;

   if (SetTimer (NULL, 0, 1000, MaFonctionTimer)==0)
   {
      printf ("Impossible de creer le timer\n");
   }
    while (GetMessage(&msg, // message structure
            NULL,           // handle of window to receive the message
            NULL,           // lowest message to examine
            NULL))          // highest message to examine
    {
 
        // Post WM_TIMER messages to the hwndTimer procedure.
 
        if (msg.message == WM_TIMER)
        {
            msg.hwnd = hwndTimer;
            printf ("GetTickCount = %d\n", GetTickCount ());
        }
 
        TranslateMessage(&msg); // translates virtual-key codes
        DispatchMessage(&msg);  // dispatches message to window
    }
}

Ma conclusion c'est que la team SAMP a réécrit les timers de SAMP pour que le code soit portable entre Windows et Linux (pour qu'il soit plus facile à maintenir).
Mais en faisant ça, ils ont introduit un décalage proportionnel au temps du timer.
Et comme on ne sait pas comment ils ont écrit leurs timers, on ne peut faire que des suppositions sur la façon de contourner le problème.

++
Syg
Titre: Re : Timer imprécis.
Posté par: Ssk le 25 Novembre 2009, 23:03:58
Apres avoir essayez et arranger le code pour me simplifier les calcules voila ce que j ai !!

Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014
Temps pour timer d' une seconde = 1014

impecable et precis ( tres propre meme )

je test avec samp et j' edit ^^


Pawn pour un timer de deux secondes !

Ms ecouler 2207
Ms ecouler 2224
Ms ecouler 2224
Ms ecouler 2241
Ms ecouler 2227
Ms ecouler 2237
Ms ecouler 2213
Ms ecouler 2204
Ms ecouler 2224
Ms ecouler 2212
Ms ecouler 2209
Ms ecouler 2220


C

Pour un timer de deux secondes

Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2012
Temps pour timer d' une seconde = 2013

Encore plus precis que pour une secondes ^^



Sinon je tient a preciser que les test en pawn sont bien sur fait sur des GM vide on est pas sur des resultat sur de gros GM avec joueurs
Titre: Re : Timer imprécis.
Posté par: Syg le 26 Novembre 2009, 09:32:32
Ca confirme que les timers SAMP n'ont rien à voir avec les timers Windows.
Il faudra donc faire avec leur imperfection.
En espérant que la team SAMP puisse les corriger.

Et j'ai fait comme toi sazuke, tous mes tests sous SAMP ont été fait avec un GM vide.

++
Syg
Titre: Re : Timer imprécis.
Posté par: 3klips le 05 Décembre 2009, 15:40:02
Merci pour toute vos réponses :p
Titre: Re : Timer imprécis.
Posté par: BuBuNo le 06 Décembre 2009, 19:31:18
Bas alors voila moi je vien de faire des testes sur un serveur linux avec environ 5 personne dessus + une course lancer et voila ce que sa donne :
8:52:29] Time elapsed: 385927
[18:52:30] Time elapsed: 386950
[18:52:31] Time elapsed: 387993
[18:52:32] Time elapsed: 389085
[18:52:33] Time elapsed: 390056
[18:52:34] Time elapsed: 391112
[18:52:35] Time elapsed: 392148
[18:52:36] Time elapsed: 393202
[18:52:37] Time elapsed: 394256
[18:52:38] Time elapsed: 395306
[18:52:39] Time elapsed: 396344
[18:52:40] Time elapsed: 397402
[18:52:41] Time elapsed: 398400
[18:52:42] Time elapsed: 399437
[18:52:44] Time elapsed: 400494
[18:52:45] Time elapsed: 401550
[18:52:46] Time elapsed: 402603
[18:52:47] Time elapsed: 403655
[18:52:48] Time elapsed: 404800
[18:52:49] Time elapsed: 405786
[18:52:50] Time elapsed: 406815
[18:52:51] Time elapsed: 408012
[18:52:52] Time elapsed: 408897
[18:52:53] Time elapsed: 409928
[18:52:54] Time elapsed: 411024
[18:52:55] Time elapsed: 412050

Donc voila je vous laisse constater :P
Titre: Re : Timer imprécis.
Posté par: S!m le 08 Décembre 2009, 02:14:16
Salut,

Il semble qu'il y ait une variation importante dans ton cas, même que certains des temps sont inférieurs à 1 seconde d'autres environ 1,2 seconde..

Citer
[18:52:32] Time elapsed: 389085
[18:52:33] Time elapsed: 390056
...
[18:52:51] Time elapsed: 408012
[18:52:52] Time elapsed: 408897
...
[18:52:50] Time elapsed: 406815
[18:52:51] Time elapsed: 408012

Que conclut-on?
Chacun doit ajuster lui-même ses timers s'il désire un temps plus près de la réalité, ils dépendent de la machine sur laquelle ils sont exécutés. De plus certains offrent un temps très stable (comme Syg) d,autres instables (comme master-bru et sasuke).
amusons nous donc,
sinon il serait sans doute possible de faire un plugin qui utilise les timer windows afin d'obtenir une fiabilité plus intéressante... toute fois une autre version serait nécessaire pour linux... et je doute qu'un scripteur de ce niveau ait le goût d'y perdre son temps.

++Sim++
Titre: Re : Timer imprécis.
Posté par: Ssk le 08 Décembre 2009, 07:55:25
Béh c' est probleme la ne surviennent qu' avec le pawn comme tu as du le voir en C c' est hyper précis ^^
Titre: Re : Timer imprécis.
Posté par: Syg le 08 Décembre 2009, 12:11:21
D'où l'intérêt de faire un plugin.
La problème c'est que si on fait un plugin Windows, il ne sera pas utilisable sous Linux.

Mais il faudrait que je regarde ça un de ces quatres.

++
Syg