LSL Script Efficiency/ja

From Second Life Wiki
Jump to navigation Jump to search

効率とは

効率は、特定のスクリプトが目標を成し遂げるためにどの程度のリソースを用いるか、ということです。これは、しばしば動作速度と相互して作用しますが、常にそうなるわけではありません。

気をつけるべき、劣悪な事例

  • 何かを成し遂げるためにスクリプトを多く使う。 効率的デザインを参照
  • llSleepをスクリプトを停止させる間、フレームあたり0.2から0.3ミリ秒以上使用する。timerでもよし。
  • 短く、頻繁にtimerをかける。(5秒以内)
  • Listenは普段から0チャンネル。
  • しばしばテクスチャを切り替える。(ほかにテクスチャをダウンロードしなければならない場合)
  • 不適切にomegaの代わりにサーバ/物理にて回転させる。
  • イベントハンドラをいずれも使用しない (touch、collision、...)
  • emailもしくはIMの規模の大きさ
  • 能率的でないアルゴリズム(順次探索のような)
  • かたっぱしからループさせっぱなし

効率的デザイン

オブジェクト内の各アイドル状態のスクリプトは Script timeの使用量へ、フレームあたり0.001から0.003ミリ秒追加します。少ないスクリプトファイル数が推奨されます。

  • もしボタンの一覧を持つ必要がある場合、プリム毎にスクリプトをいれてはいけません。 スクリプトの代用に、それぞれのボタンをタッチされた場合に検出するllDetectedLinkNumberを使用しましょう。
  • もし子プリム群の色や透過率、テクスチャを変える必要がある場合、それぞれのプリムにスクリプトを入れてはいけません。代わりにllSetLinkAlphallSetLinkColorllSetLinkTexture、かllSetLinkPrimitiveParamsを使用しましょう。
  • 0チャンネルでのlistenを各プリムに入れることはありえません。これは効率のために最も悪いことであるのは確かです。全てにおいて不適当なことです。
  • XyTextの代わりにXyzzyTextを使用しましょう。

最後に、もし各プリムにスクリプトを入れることの自動化を試みているなら、中断して少ないスクリプト数で異なるやり方と取るべきだと思いましょう。大概常に別の選択肢があります。アプリケーションにとって有効な選択肢であるかどうか決めるのはあなた自身です。

細かい最適化

a++の代わりに++aを使うように、スクリプトのスピードアップの方法は数多く存在しますが、これらの多くの細かい最適化は将来においても保障されているわけではありません。


どのようにしてコードを早く動かすか

補足されているコードは、ミリ秒で各関数を呼んだ際かかるであろう時間を取得するものです。

始めに、discussionを変えることを提案します。正確な計測ではない些細な変化によるもの、もしくは議論なしでのコード変更はしないでください。Efficiency Testerにコードとコメントを、正確にそのまま記録してください。

オリジナルコードはXaviar Czervikの提供で、更に正確な計測を行えるコードになったのはStrife Onizukaのおかげで、そして、この箇条書きの経過を一覧化した方々の力添えによって成り立っています。

//重要: 空のregionでのみテストしています。
// 重複しているものを削減して、必ずアタッチメントを外してください。
// 願わくばプライベートシム上にてテストを行ってください。
// テストを行っている間は動かないでください。
// 誤差の余裕を持たせるため、複数回に分けてテストを行います。

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.");
  }
}

効率

以下のデータは先ほど展開した空の(完全にプライベートではない)SIMで、HUDアタッチメントのスクリプトのみを走らせて、上記の関数を使って収集されました。20回程度のテストの平均値です。

  ++a:     0.173780 ms    std. dev.:  0.003393 ms
  a += 1:  0.181720 ms    std. dev.:  0.013267 ms
  a++:     0.243500 ms    std. dev.:  0.013816 ms

このように、a++ は ++a よりも(概算で)実行に40%長くかかります。

以下のデータの時間は、上記の関数を使用していない不正確なものです。Xaviar Czervikによって書かれた、そこまで最適化されていないものを使用しました。もし誰かが繰り返しテストするなら、上記の関数を用いてください。

  ++a:     0.364700 millis
  a += 1:  0.346900 millis
  a++:     0.413700 millis

ループで同じ関数をテストした結果

  ++a:     0.358370 millis
  a += 1:  0.351200 millis
  a++:     0.424600 millis

llOwnerSayllSayllShoutllWhisper (0チャンネル状態にて)

  llOwnerSay(): 4.359000 millis
  llWhisper():  5.201000 millis
  llSay():      5.226000 millis
  llShout():   14.877000 millis

異なるチャンネルにて(llSay()を使用):

  -100000000: 1.226400 millis
  -100000:    1.254300 millis
  -100:       1.296100 millis
  -1:         1.292400 millis
  0:          5.226000 millis
  1:          1.242300 millis
  100:        1.249100 millis
  100000:     1.219700 millis
  100000000:  1.228700 millis

文字量の差(llSay()にて1チャンネルを使用):

   1 Character:    1.242300 millis
   10 Characters:  1.309700 millis
   100 Characters: 1.965600 millis