LSL Script Efficiency/fr

From Second Life Wiki
Jump to: navigation, search

Qu'est-ce que l'efficacité?

L'efficacité est l'inverse des ressources consommées pour effectuer une tâche donnée. Plus le script est efficace, moins il consomme de ressouces. L'efficacité va souvent de pair avec la rapidité, mais cela n'est pas une généralité.

Les points qui ont un impact négatif sur l'efficacité sont, à peu près par ordre d'importance :

  • Le nombre de scripts utilisés pour accomplir une même tâche. Cf. Conception Optimale.
  • llSleep - Cette fonction consomme 0.2 à 0.3 milliseconde par tranche de temps pendant que le script dort. Les timers (llSetTimerEvent) sont bien plus efficaces.
  • Les timers "courts" (< 5 sec) sont grands consommateurs de ressources.
  • Listen - particulièrement sur le canal 0
  • Les changements fréquents de texture (les autres utilisateurs sont contraints de les charger)
  • L'utilisation des rotations côté serveur au lieu de llTargetOmega
  • Les gestionnaires d'évènements inutiles (touch, collision, ...)
  • Un grand volume de mails ou d'IM
  • Les algorithmes non optimaux (recherche linéaire par exemple, par opposition à dichotomie)
  • Les boucles d'attente actives

Conception optimale

Chaque script dormant dans un objet ajoute de 0.001 à 0.003 milliseconde par tranche de temps. Moins il y a de scripts, meilleure est l'efficacité.

  • Si vous avez besoin d'un tas de "boutons", évitez de mettre un script dans chaque prim. Utilisez llDetectedLinkNumber dans le prim racine pour détecter quel sous-prim a été touché.
  • Si vous avez besoin de changer la couleur, la transparence (alpha) ou la texture d'un sous-prim, évitez encore de mettre un script dans chaque prim. Utilisez plutôt llSetLinkAlpha, llSetLinkColor, llSetLinkTexture ou llSetLinkPrimitiveParams.
  • Ne mettez jamais un script qui écoute sur le canal 0 (ou autre) dans chaque prim d'un objet complexe . C'est sans doute la pire des choses à faire. Malheureusement, elle est trop fréquente.
  • Pensez à utiliser XyzzyText à la place de XyText.

En résumé, si vous êtes sur le point de mettre un script dans chaque prim d'un objet, arrêtez et cherchez comment faire autrement avec moins de scripts. Il existe pratiquement toujours une autre solution. À vous de décider si elle est viable dans le contexte de votre application.

Micro-optimisation

Il existe beaucoup d'astuces pour accélérer les scripts, comme utiliser ++a au lieu de a++. Cependant, ce genre d'optimisations peut se révéler sans effet dans le futur (en cas de changement d'implémentation de LSL).

Combien de temps prend ce code ?

Le code suivant mesure le temps passé dans chaque appel de fonction, en millisecondes.

Atention, ne modifiez pas ce code sur le wiki sans une discussion préalable. Un changement même mineur peut entraîner des discordances dans les mesures. Ce code est un étalon de mesure et doit être recopié exactement, commentaires inclus, tel que figurant ici.

Merci à Xaviar Czervik pour le code original, à Strife Onizuka pour l'amélioration de sa précision, et à tous les autres contributeurs listés dans l'historique de cette page.

//IMPORTANT: Only perform tests in an empty region.
// To reduce contamination and be sure to wearing no attachments.
// Preferably do tests in a private sim with one on it.
// Don't move while performing the test.
// There is a margin of error so run the tests multiple times to determine it.

integer time() { // count milliseconds since the day began
    string stamp = llGetTimestamp(); // "YYYY-MM-DDThh:mm:ss.ff..fZ"
    return (integer) llGetSubString(stamp, 11, 12) * 3600000 + // hh
           (integer) llGetSubString(stamp, 14, 15) * 60000 +  // mm
           llRound((float)llGetSubString(stamp, 17, -2) * 1000000.0)/1000; // ss.ff..f
}

default {
  state_entry() {
    llOwnerSay((string) llGetFreeMemory());

    //test variables
    float counter;

    //framework variables
    float i = 0;
    float j = 0;
    float max = 10000; // 2ms of work takes 20 seconds to repeat 10,000 times, plus overhead

    float t0 = time();
    do {

      //test
      counter += 1;
      
    }while (++i < max);
    float t1 = time();
    do ; while (++j < max);
    float t2 = time();//remove the time required by the framework
    float elapsed = ((t1 - t0) - (t2 - t1))/max;
    llOwnerSay("The function in the loop took a total of " + (string)elapsed + " milliseconds.");
  }
}

Mesures d'efficacité

Les mesures suivantes ont été collectées avec la fonction ci-dessus dans un simulateur récent et vide, avec ce seul script s'exécutant dans un ATH. Elles sont la moyenne de 20 exécutions.

  ++a :     0,173780 ms    dév. std. :  0,003393 ms
  a += 1 :  0,181720 ms    dév. std. :  0,013267 ms
  a++ :     0,243500 ms    dév. std. :  0,013816 ms

a++ prend en gros 40% de temps de plus que ++a.

Bien que les données qui suivent soient correctes, elles n'ont pas été obtenues avec le code de référence ci-dessus, mais avec une version légèrement moins optimisée écrite par Xaviar Czervik. Si quelqu'un pouvait répéter les tests avec la version de référence, merci.

  ++a :     0,364700 ms
  a += 1 :  0,346900 ms
  a++ :     0,413700 ms

Même test pour la boucle for :

  ++a :     0,358370 ms
  a += 1 :  0,351200 ms
  a++ :     0,424600 ms

llOwnerSay par rapport à llSay, llShout еt llWhisper (canal 0) :

  llOwnerSay() : 4,359000 ms
  llWhisper() :  5,201000 ms
  llSay() :      5,226000 ms
  llShout() :   14,877000 ms

Autres canaux (llSay() utilisé dans tous les cas) :

  -100000000 : 1,226400 ms
  -100000 :    1,254300 ms
  -100 :       1,296100 ms
  -1 :         1,292400 ms
  0 :          5,226000 ms
  1 :          1,242300 ms
  100 :        1,249100 ms
  100000 :     1,219700 ms
  100000000 :  1,228700 ms

Longueur du texte (llSay() et canal 1) :

   1 Caractère :    1.242300 ms
   10 Caractères :  1.309700 ms
   100 Caractères : 1.965600 ms