MinimalSampleをテンプレートに追加

prefabをちょっと試したいだけの場合に
File>Newscene>Empty  の並びに
MinimalSample.unity を追加してみました
Unityシーンテンプレートの機能です
◯ 前置き
Cluster CCKの場合は
File>Newscene>Empty では 不都合ですね
play gameすると と叱られます
「ワールドをプレビューするためには以下のコンポーネントが必要です
・・・・ SpawnPoint, DespawnHeight」
そこで
ClusterCreatorKitTemplate の
MinimalSample.unity をいちいち読み込んでいました
これが面倒ですね
そこで
Unity2020.2から追加されたシーンテンプレートの機能を使います
◯ 問題点
メニューの
File > Save As Scene Template
これを実行しても手順がよくわかりませんでした。
やたらファイルを保存するばかりでした
そこで やってみた手順は以下の通り
◯ 手順------------
ProjectのAssetsから MinimalSampleを選択して
右クリック>Create>SceneTemplatefromScene
を実行する

(何も選択してないと コマンドはグレーです)
(Unity上に ファイルの読み込みは不要です)
assetに ファイルができます
MinimalSample.unity の近くに
MinimalSample.scenetemplate というファイルができます
これを選択してInspectorで見ると 図のように
Cloneの並びのcheckがはいっていますが これをはずします
(これをしないと毎回保存するという邪魔がはいります)

設定の保存ボタンもなく これで完成です
File>Newscene>Empty  の並びに MinimalSample が現れています

必要なら Inspector で サムネイルやtitle名をカスタマイズできます

-----------------以上
 
自分用に覚書を残しただけです
もっと正しいやり方があるかもしれません
optionや使い方が他にもあって 検証していないので
誰か正しい記事を書いてね
Watさんのヒント記事ありがとう
 #cluster

処理時間測定その4--lambdaを探せ

profilerの使い方のおさらいです   2024.0407 更新
特にprofiler hierarchy(階層)の使い方の再確認してみました
profilerを使って script1つ に相当するマーカーを探します
実験的に負荷の高いscriptを作って、問題の絞り込みを確かめてみます
◯ 今回の負荷の高いscriptは以下のとおりです。logを残すことで負荷になります
---------
$.onUpdate(deltaTime => {
let j_end = 100
for (let j = 0; j < j_end; j++) {
   $.log("無駄にlogを残す");
}
});
-----------
発見しやすいように負荷を誇張しています。100回ループぐらいで1F=60msぐらいの負荷になりました
今回は、10回ループのscriptの付いたitemを10個複製して100回分の負荷としました
まず deep profile modeで測定します。適当な時刻を選択します。
profiler timeline は直感的に洞察するのによいですね、末端が10個に割れているのが見えます。
scriptが 10個複製 されたことに対応していることが視覚的に見えます

◯ マーカーって何?
profiler timeline で横長のブロックがDocumentでいうところのマーカーのようです
でかいマーカーを探せば負荷の原因を探しやすいという理屈です
しかしマーカーが小さく 多数に散らばっているなら とても探しきれません
マーカーのtimelineでの様子は壮大で複雑で精密でケース・バイ・ケースで 様変わりします
この横文字のゴチャゴチャに深入りしたくないものです
◯ そこで  Profilerのhierarchy(階層)の検索機能を使います
目的のマーカーのスペルまで わかっていれば 階層で検索すると手っ取り早いでしょう
しかし、当てずっぽうの推理で検索を繰り返すのも不毛です
(偶然ヒットすることもありますが安定したやり方ともおもえません)
そこで、ずばりのマーカー名がわからなくても 着目するとよいマーカー名のリストがあれば
そのキーワード候補で検索して その上下近くを探すと段取りがよいように思います
現時点の有力候補は [lambda]ですが 別の目的で別のマーカーを探す場合に備えて
profilerの使い方をおさらいしていきます

◯ もしマーカー候補がまったくわからない状態から探すなら
▼マークを闇雲にポチポチ開いて探すことになり無数のマーカーと深い階層に出くわします
あるいは▼マークをALTキーを押しながらclickすると全ての階層が末端まで展開することができます。
やはり無数のマーカーと深い階層に出くわします
◯ では、検索機能をつかってみましょう
キーワードとして[KaomoLab]の文字で検索してみます script関係を絞り込めて手っ取り早いです
先頭文字がKaomoLab~~のマーカーがヒットするはずです
後述しますが階層表示でないと素直にソート操作が使えます
◯ 検索でうまくヒットしない場合の注意点が2つ
1. DeepProfileモードで測定したかどうか点検します
2. フルネーム(show full scripting Method Names )表示になっているか点検します
( runner  lambdaは deep測定でないとヒットしない)
  フルネームでないとKaomoLab~~がヒットしない  

◯ Profilerのhierarchy(階層)の検索に文字を入れると
階層という名前なのに[階層]でない一覧表示になるようです
▼マークが見当たらないことで区別ができます
アルファベット順にしたり降順・昇順にしたりソート操作が素直に使えます

◯ 処理時間も加味して絞り込みましょう。今回はそのために処理時間を誇張しています
ミリ秒=msが大きいものから下へたどります
(total %に着目するのもありですね 負荷に対する%表示の方がわかりやすいかもしれません)
小さい▼のあるところが ソート項目で defaultは Time ms のようです
 図参照

◯ 先頭文字ではなく末端文字に着目します
先頭文字がライブラリ名とか大きな分類のようです
末端文字がなにやら具体的な内容に近いヒントになっているのでしょうか
キーワード候補の[KaomoLab~~CodeRunner] が見つかりました calls数10 ですから scriptの数を反映しています
「script1つ に相当するマーカー」 の候補がみつかりました。それだけではなく
「コマンド1つに相当するマーカー」 が見つけられました
深くたどると Log~何とか~というMarkerがいくつか見つかります
例えば[KaomoLab~~DebugLogger.Info]に着目すると
100回callしたという数値もあるので これが $.log コマンドひとつに相当すると思われます
飽くまで 憶測です。(立証する必要もないと思います 飽くまで作業上の仮定でいいと思います)
このようにどのMarkerに着目すればよいか 候補がいくつか見つかります
◯ このままでは[KaomoLab]しばりで、偏っています。
それ以外のマーカーにも捜索範囲を広げたいと思います
検索項目を空欄に戻します。▼マークを使った 階層表現に戻りますが
特定のマーカーを選択していれば そこに着目して階層を展開した状態になるようです
今回は [CodeRunner] や [DebugLogger.Info] を選択しておきます

◯ 所属関係が見やすい階層表示にして観察してみます
(見つけたMarkerを選択しておかないと▼マークをいちいち開いて探すはめになります)
どういうわけかきれいな階段状に並んでいます。条件によっては違うのでしょうか
これが正しい使い方のような気がします。
ここで下手に降順を昇順に変えるとわけのわからない並び順になります
階層が絡んでいるからでしょう。どういうルールか解説してほしいです。
ただし、選択したマーカーは見失ってはいないようです。
エレベータを動かして探すと見つかります。
◯ それと、profilerの階層の折りたたみと展開はどういうルールになっているのでしょうか
階層を折りたたんでも  CPUUsageをClickまたはスクラブルすると階層が展開します
あくまで選択したマーカーを基準に開くようです
測定をclearしても 直前に使っていたマーカーを覚えているようです
これは便利そうです(文献上の根拠はありません 発見したTipsです)
◯ 検索項目が空欄なら ▼マークのある階層表示になっているはずです これをじっくり観察します
かおもさんのエミュレーターが機能するのにいろんなライブラリが
後になったり先になったり 入り組んで 処理をしているようです
    UnityEngine.UI.dll!
    ClusterVR.CreatorKit.Preview.dll!
    mscorlib.dll!
    Jint.dll!
・・・などが見受けられます
横文字アルファベットのゴチャゴチャに深入りしたくなかったのですが
正常な状態を観察しておくことは
いざというデバグや負荷対策の時に役立つでしょうか
◯ この状態を画像ではなくテキストでコピーして記録したり整理したい場合は
profiler timelineの黒字に白のフキダシから show>selected Sample Stack でcopyできます

◯ 「scriptひとつに相当しそうなマーカー」の候補がさらに増えました
実験の詳細は省きますが
onUpdate、onInteract、onCollision、onGrab、onUse でいくつか調べたところ
[CodeRunner]は共通ではありませんでした
発見したのは [mscorlib.dll!System::Object.lambda_method()] です
これが共通して存在していました
理論的根拠に乏しいですが lambdaは 覚えやすいので お勧めかもしれません 
「lambda」の読み方は? ギリシャ文字「Λ (ラムダ)」です 
このようにケースバイケースで 目的とするマーカーを絞り込めるでしょう
◯ 環境その他
無謀にもprofiler学習直後の勢いでprofilerの使い方を自分用に書いています
参考になれば幸いですが 検証できていない 憶測も含みます
参考にする方は自己責任でお願いします
#cluster #ClusterScript
環境 Unity 2021.3  CCK2.9.0      かおもさんのエミュレータ(CSEmulator2.22)  
Profile Analyzer 1.1.1 cluster v2.116(2024/03/18)
謝辞    ヒントをくれたかおもさんに感謝

 

処理時間測定その3--Deepでフリーズ

かおもさんよりヒントを頂きました
「 EngineFacade.Update がCSEでのUpdate1回分
  CodeRunner.Update jsファイル1個分
これでscriptの処理時間が測定できそうです
そもそも Deep profile mode を使う手順を知りませんでした
恥ずかしい~~
さっそく体験記を追記しておきます
2024.0331 更新

手順E DeepProfileオンの場合----------------------------------

手順AにDeepProfileオンを加味します    前回の手順Aを参照のこと

今回の実験データはscript付きitemを20数個に複製し
script負荷を強調したものです 
省略されていたブロックも全部表示されるらしく 印象が変わります
測定前にオンにしないと効果がないようです
画面では Deep profile mode の灰色がオンかオフか見分けにくいですね
Timelineの階層が増えて さらに複雑になっています
見慣れないアルファベットがびっしりで拒否反応が起きるところです
ここまで深入りしたくなかったというヒトもいるでしょう
ヒントの [EngineFacade.Update]のブロックを探します 
timelineでは 探しにくいので
Profilerのhierarchy(階層)で検索します

ちなみにDeepProfileオフで測定してもヒットしません。
スペルミス に注意ですね(大文字・小文字の区別はないようです)
[KaomoLab]で検索するのもいいでしょう script関係がヒットします

(KaomoLab~~が たぶんscript関係でしょう 検証しきれていませんが)
ミリ秒順にソートされているらしく 処理時間の長いものが先頭にあります
今回は[EngineFacade.Update] をピンポイントで探せばよい
・・・という目処があるので心強いです
図のミリ秒を見ると   処理時間 51.88msとか 
 1フレーム63.92msに近い値です ぴったり一致はしてませんが
処理負荷の主な原因を表しているようです
今回の実験データではscript付きitemを20数個に複製し
script負荷を強調したものです 
No Details  を Related data にすると内訳が表示されます
(選択しておかないと何も見えません)20数個ならんでいます
なるほど [CodeRunner.Update]    は jsファイル1個分のようです
ひとつのscriptの処理時間が約2msであることも表示されています
この値が信用できるかどうか 後で検討します
自分の作ったscript名がそのままマーカー名とか
ブロック名として登場はしないようです 
慣れてくれば timelineよりは hierarchy(階層)の方が使い良いのでしょう
念のため、これを timelineで視覚的に確認してみます
hierarchy(階層)で選択してあれば 黒地に白文字の吹き出しが 表示されています
ショートカット[F]やホイールボタンや 
下段のエレベータを駆使して見え方をスケールします
図では[EngineFacade.Update]の長いブロックの下に
 [CodeRunner.Update]が20数個ぶらさがっている様子が見えます

これで、
「 EngineFacade.Update が1フレームのscriptの総計らしい
  CodeRunner.Update    がscript1個分であるらしい」
・・・ということを確認しました。めでたしめでたし


補足---------------
◯ 右肩の点3つメニューに show full scripting Method Names のoptionがあります
これだと先頭にKaomoとついているものがscriptがらみとして探しやすいです
慣れてくると短いほうが [CodeRunner.Update]を 探しやすいかもしれません

◯ Deep profile mode でフリーズの危険性
Script付きザリガニ50匹の重いシーンデータを測定できたのですが 
analyzeしようと load dataしたら フリーズしました 10分待っっても終了しません
Deep profile + analyze の組み合わせは危険です
文献によると
「ディーププロファイリングはリソースを大量に消費し、多くのメモリを使用します。
 ディーププロファイリングは、簡単なスクリプトで動く小さなゲームに適しています。
 複雑なスクリプトコードを使用している場合、
 アプリケーションでディーププロファイリングをまったく使用できない場合があります。」
・・・なるほどdefaultでオンになっていなかった理由があるのですね 一長一短があります

◯ Scriptの処理時間がそのまま信用できるかどうか
Deep profile モードでは profiler自体の負荷が影響して 
ほぼ同じ条件でも1フレームの測定値が異なりました
実験データでは 5倍も違いました
  DeepProfile オフ 1フレーム=12ms
   DeepProfile オン 1フレーム=63ms   
この状態で測定されたscript1つの処理時間をそのまま信用できるのでしょうか
何分の1か比率を掛けて補正すればよいのでしょうか 
Profilerは飽くまで 負荷原因を絞り込むツールであって・・・・
数値をよそに持ちだせるほど 本番に近い測定ツールでしょうか

◯ 手順Eが当てはまらない場合
scriptの本文が OnUPdateなら当てはまることが
scriptの本文が OnInteractなら その手順が当てはまらないようです
例えば 前前回の負荷測定用データ  test_ms_009B.unity  は Interact タイプなので
[EngineFacade.Update]や[CodeRunner.Update]が小さすぎて
1フレームの負荷を反映していませんでした
そこで [KaomoLab]で検索したところ
[InteractItemTrigger_TriggerEven] に着目したほうがよいみたいだと思われます
時間切れで 検証しきれていません。


・・・・・以上追記しておきます
飽くまで体験記です。
検証できていない 憶測も含みます 参考にする方は自己責任でお願いします

#cluster #ClusterScript

処理時間測定その2--profilerやってみた

x

作ったscriptが重いかどうか知りたいだけだった
・・・なのに深みにはまってしまいました
誰かが正しい解説記事を書いてくれると期待して体験記を書きます
読者対象は中級者向けのCluster記事を書けそうな人です
  2024.0328 更新
目次----------------
記事の目的 
信頼できるミリ秒を探し求めた経緯
時間についてのエッセイ
Unity profiler お勧め手順案A
その他の手順と疑問点
参考文献
環境その他


記事の目的 ---------------
作ったscriptの処理時間を知るためにUnity profiler を再勉強してみました
Unity profiler の一般の記事は ありますが 難しく奥が深く発展途上のようです
さらに Cluster CCK で成立するのかという 条件付きで学習せざるを得ません
どこかに不具合やちょっとしたバグがあれば なおさらつまづきます
そこで 条件として
  CCK + かおもさんのエミュレーター + Unity profiler 
の環境で解説記事がほしいです
問題提起をかねて体験記を書いてみます

 

信頼できるミリ秒を探し求めた経緯-------------------------------------------
処理負荷をどれで判断するか深入りした経過です
簡単なものから難しいものの順で述べます

1. Cluster本番の 統計  ------------------v
Clusterのワールドに入った時の右上に表示される統計です
他人のワールドも測定できます  ms=ミリ秒があります
   FPS:(CPU  ms Render  ms)
リアルタイムで数値が変化するので最初のうちは頼りにしていました
アバターの見る風景を動かす・・つまりカメラを動かすと
即刻にrenderのミリ秒が変化して わかりやすかったです
重たいバーカウンタや鏡や多数のアバターに視線を向けると
グラフィックの処理負荷が重くなるのがわかります
しかし、script負荷や厳密な分析や比較には不便を感じます        
数値が刻々と変化するのでどの値を記録すればいいのでしょう
VRの場合はsteamの ミリ秒表示を使う手もあります
Clusterの値とは同じではないようです

2. Cluster本番の Consoleのエラーと警告------------^
ワールド制作者にしか見えないアレです
処理時間に関する警告が出ることがあります
WARN: script execution (383ms) exceeded the soft limit (50ms). 
Scriptに関するエラーもあります
Script has allocated too much memory
これが不便であるということは別記事に書きました

3. UnityのPlay Gameの statistics (統計表示)    ------------
このなかで SetPass calls の値は グラフィック負荷の判断に使えました
しかし、処理時間を表すミリ秒は不安定でコロコロ変わりすぎます
しかも3種類あります 
  FPS(  ms) CPU:main msの値 render Thread msと 
これらは何を意味しているのでしょうか
簡易的に瞬間的な変動を知るぐらいにしか役立たないように思います
目視で平均値を推定して記録しようとしても 
script負荷や厳密な分析や比較には不便を感じます

4. Unity Profilerで フレームのミリ秒を確認できます ------------
ProfilerのTimeLineの並びに  CPU GPU のミリ秒が表示されています
グラフのどのあたりを抽出するかはユーザーがClickでえらべます
スパイクもえらべます。
平均的な値をしりたければ 
後述の  Unity Profile Analyzer で 中央値の時刻(フレーム)を選べます
Medianのms値の横の数字がフレームで
それをclickすると Profiler側が変化します
Profiler側で その時刻(フレーム)をclickしたのと同じことになるようです
選択したフレームの秒数は Analyzerの値と一致します
グラフをじっくり観察して原因を洞察するには向いています
しかし症状を記録したり報告書にするにはちょっと不便です
 

5. Unity Profile Analyzer    ------------
原因を洞察するには向いていませんが症状を記録したり報告書にするのに便利です
平均値や中央値を算出してくれています。 
詳細は手順の章を参照ください
いまのところ この中央値が 信頼できて再現性の高い 記録向きの値と思っています
1フレームの処理時間です    
scriptを使ったワールドの比較に使えそうです

追記    その他の測定方法    ------------
profilerの使い方の資料を見聞きすると
実機での測定や ビルドしてからの測定が書かれています
editorのよけいな影響を受けずに理想的と書かれています
Cluster CCKの場合  そういう条件での測定がなさそうです
なお、standalone(profiler)での測定は未調査です
 
時間についてのエッセイ-----------------------------------
時間についての エッセイ または我流の解釈です
1フレームってどうなっているの?-----------------------------------
◯ わかっていたつもりが どこかで混同していたかもしれません
用語が同じでも 畑が違うと前提や使い方が違うということがあります
そもそも映像業界の時間の観念とゲームの時間の観念が違うようです
1フレームという用語が AfterEffectとUnityで同じとは限らないようなものです
身についた時間の観念と思い込みが邪魔をします。この際に整理してみました
◯ 映像編集で 1フレームの時間の刻みは一定であること
を疑ったことはありませんでした
1フレームの時間の長さが毎回不揃いで 
一定間隔ではないなんて 映像編集では考えたことがありません
数百フレーム集計したときに だいたい11msに辻つまがあってればいいなんて
なんと泥臭いテクノロジーでしょうか
◯  交通機関に例えてイメージしてみました・・・
例えば 「CPU と GPUのどちらの処理時間に注目するべきか」
・・・という疑問を考えたときのことです
CPUとGPUは 同じ一つの線路上にあるのではなく
交通機関に例えると電車とバスという 異なる路線にあると考えました
想像してみてください、環状線は一定のサイクルで
列車(スレッドやタスク)を処理していきます
環状線から吐き出された乗客は バスに乗り継ぎます
もし、バスが過剰積載で市内循環の到着に遅れが生じたら
環状線は発車時刻を少しずらして対応するかもしれないし
ダイヤグラムを変えずに1周遅れの列車で運行するかもしれないし
プラットフォームにあぶれた乗客をまとめて運ぶ
特別列車を繰り出すかも知れない
 
こうして1サイクルの時間が変動すると考えます 
時間が映像編集のような絶対的なものでなく
動的に曖昧で不揃いでケースバイケースで目標値に合わせよう
といろんな工夫があるらしい
 
構造や階層が複雑です CPUとGPUの処理時間を分けて表示すれば
どちらに原因があるか絞りやすいのでしょう
災害時に交通網が乱れた時に環状線とバス路線でどちらに原因があったか
追求するようなものです
正常なときにどのように働いているか見ておかないと
いざというときに使えない profilerはそういう泥臭いツールのようです
では、もう少し具体的な体験を語ってみましょう
◯ Visual Studio Code だけでは処理時間の手がかりがほとんどありません
「 onUpdate  は0.02秒に1回程度呼ばれる。0.02秒=20ms」
・・・という理解を  どこで読んだのでしょうか 20msは不適切な数字です
1÷60=0.016666…秒(≒0.02秒)これを四捨五入するなら 17msではないでしょうか
◯ 以下の文章では かおもさんのエミュレーターに合わせて
1フレームが約11msを目標値とするという文章で進めます
英語動画では Budget=予算 という言葉が使われていました
VR環境90FPSを想定して  1÷90=0.011111…秒(≒0.011秒) 四捨五入して11msですね
◯◯ どのミリ秒の数値を判断基準にすればよいのでしょうか-------------------------
◯ scriptの処理負荷を検討するときは主にCPUの数値だけでいいのだと思います
最初は (CPUミリ秒 - GPUミリ秒) = script処理時間  だろうかと考えました
1フレームの総計に グラフィックやscriptやその他の
処理時間が含まれていると思われたからです
厳密にはそうではないようです
◯ CPUとGPUの時間きざみはレンガ積みのようにズレているようです
いくつか測定しているとたまに GPUの方が大きい値になることがあります
これは変だぞと気づいて理解を変えてみました 
交通機関に例えるのは別に書きました。ダイヤグラムではないですが
レンガ積みのようにズレている というイメージです。
これは動画資料の 解説図にも登場しています
  -------------------------0秒------------------------------約11ms
 
         一つ前のCPU処理-----||--------CPUの1フレーム----------||--------次のCPU処理---
             |---一つ前のGPU処理------|             |--------GPU---------|

CPU処理が 計算準備して GPUに処理を投げる・・・と表現されていました
図はGPU処理がCPUの次の処理に食い込むケースを想定しています
計算負荷がふえると どちらも待ち時間を調整してタイミングをあわせているようです
GPUバウンド  CPUバウンドをほのめかしましたが 間違っているかもしれません)
timlineを見ると idleとかwaitというブロックが目につきます 
そういう待ち時間や調整が見受けられます
いくつか測定していて  大幅にGPUの処理時間がCPUを上回り続けることがありませんでした
これは多分、GPUの方が大きい値になった場合は次のCPUの待ち時間に食い込んで 
次のCPUの処理時間を長くすることに吸収されるからだろうと思います
 

 

手順案 準備部分    -------------------v
Window > Analysis > Profilerを開いています
Window > Analysis > Profile Analyzer     を開いています
これは標準ではメニューにありません PackageManagerからインストールしています
なお今回の測定データは CCKTemplateの    MinimalSample.unity を使っています

 

手順案A    [ playMode  +  PlayGame]    の場合    -------------------v
◯ 文献や動画を参考に現時点のまとめです  間違っていたらごめんなさい
まずProfiler Modulesは defaultで Play Mode のはずです
Profiler の赤丸ボタンをオンの状態で playgameオンにして 測定します
適度に測定グラフが安定したところで止めます 
ちなみに defaultでは300フレームしか記録できません
CPU usage windowで クリックすると止まります
これは playgame pause || をクリックしたのと同じことのようです
ProfilerのCPU usage windowで 適当な時刻(フレーム)を選べます
肉眼でグラフのスパイクの時刻を選んだりできます
今回は平均的な処理時間を知りたいので 
肉眼でグラフの平均的な時刻を選んでいましたが、それよりは
Profile Analyzerの Frame  Summary の Median の値を使いたいと思います
平均値ではなく中央値を使います 数値の再現性と信頼性が上がりました
今回の測定では11.08ミリ秒です
ちなみに測定データは     CCKTemplateの    MinimalSample.unity    です
床と空しかない軽いデータですが かおもさんのエミュレーターの FPS制限90FPS設定によって
11msに調整されているはずです 予定どおりでした

この手順に間違いない・・・と思いたいわけです。 
なので他の手順も調べます

 
手順案B      [ game画面が見えない状態]     -------------------v
◯ 考察・・・これはたぶん測定失敗だと思います
profilerを最大化したり game画面が見えない状態で 測定すると
TimeLineのrender Threadに    緑ブロックがびっしり出現します
測定データが    MinimalSample.unity でない場合も同様でした
拡大するとピアノ鍵盤のようです
CCKのみ場合 ピアノ鍵盤症状は現れないので
かおもさんのエミュレーターFPS制限の副作用と考えられます
文献にそのような注意事項が見当たらないので どなたか解説してほしいです
とにかく 測定時には 念のためそうならないように注意することにします
ちなみに game画面は freeAspectよりも    FullHD1920x1080固定にしています

 
手順案C      [ EditMode ]  だけの場合    -------------------v
1フレームが4msという小さい値がでます
シーンの内容にかかわらずほぼ同じ値になるので
これは    UnityEditorだけでの処理負荷のようです
かおもさんのエミュレーターの FPS制限90FPS設定が効いてないようです
◯ 考察・・・風袋引きのようなものでしょうか マシンによる差異を差し引きするのでしょうか

 

手順案D      [ EditMode + Play  ]   の場合    -------------------v
EditMode  で PlayGameすると 別の測定結果がでます
かおもさんのエミュレーターの FPS制限90FPS設定が効いてないようです
TimeLineの構造がシンプルなので何かに使えそうです どなたか解説してほしいです
◯ 考察・・・たまに変な値になるし、文献にもないし  よくわかりません

◯ 補足    profilerのCPU USAGEグラフの見方-------------
profilerのCPU USAGEのグラフの横軸はフレームです。縦軸がミリ秒です。
横軸が普通の時間ではなく  面積が時間ということになります
1フレームの時間が一定という暗黙の前提ならば横軸も普通の時間軸だろう
・・とうっかり勘違いしていました。 
映像編集で身についた時間の観念と思い込みが邪魔をします。
◯ 補足    profilerのtimelineの見方-------------
CPU USAGEで適当なフレームを選択しないと何も見えてきません
横軸は時間です  0秒とは何でしょう
どこからどこまでが1フレームか
表示をスケールすると 白い枠線が2本見えてきます
 
手順を 自分用にまとめましたが疑問点 未検証点 多々あります
この理解であっているのかどうかの検証するための文章です
参考にするかたは 自己責任でお願いします
 
 
参考文献------------------------------------------------
 【Unity】CPUプロファイラでパフォーマンスを改善する 前編
テラシュールブログ  2016.0509 山村 達彦 後にユニティ・テクノロジーズ・ジャパン
【Unity】Profilerの実用的な使い方!パフォーマンス改善に必要な部分だけサクッとまとめ2019-09-19
Haruki Yano   Unityエンジニア
プロファイリング入門  英語 2020/05/25
スピーカー:Ciro Continisio(EMEA 地域リードエヴァンジェリスト
パフォーマンス最適化 入門~2021年版~ - Unityステーション 42分
黒河 優介   
Unity2021.2から始めるプロファイリング入門 - CEDEC2021 2021/08/26   動画21分
講演者:黒河 優介(ユニティ・テクノロジーズ・ジャパン株式会社 
 
環境その他-------------------------
環境 Unity 2021.3  CCK2.9.0      かおもさんのエミュレータ(CSEmulator2.22)  
Profile Analyzer 1.1.1 cluster v2.116(2024/03/18)
・・以上  専門家ではないので理解に間違いがあればお許しください
#cluster #ClusterScript

Cluster J script 処理時間測定

Cluster J script 処理時間測定
---------soft limit (50ms)  って何?-----------
測定してみたところの体験と
エラーメッセージの考察と提案です
ここ最近(12月~2月) こういう黄色の警告をみかけました

> WARN: script execution (383ms) exceeded the soft limit (50ms). The limit will be enforced in the future.
直訳すると
> 警告: スクリプトの実行 (383 ミリ秒) がソフト制限 (50 ミリ秒) を超えました。 この制限は将来的に施行される予定です。
もちろん、ワールド制作者だけに見えるコンソールに表示される警告ですね
scriptの処理時間が長いという警告なので
どういう場合にその警告がでるのか、無視して支障ないのか
script を改善して残すべくscript の処理時間をまず測定してみました
・・・・図参照
実験方法---------
Date.now()
このコマンドで時刻を調べて その差から処理時間を算出します
それを発展させて調査用の script に改造していきました
ループ回数を徐々に多くして処理時間が長くなったら例の黄色の警告がでるはずです
ところがこの黄色の警告がなかなか再現できずに苦労しました
代わりに赤!マークのエラーが出ることもあります
 [Script has allocated too much memory]
 
調査用の script をつくったときに
驚いたのは scriptが途中で放棄されていることでした
文末に 処理時間の表示を書いていたのですが 
負荷を重くしてエラーを出した場合に その処理時間が表示されないので、
おかしいと気づきました
それは本番Clusterの場合だけの現象でした
Unity上のpreviewでは そんな途中放棄はありませんでした
previewとは かおもさんの(CSEmulator2.20)を使用したということです)
本番Clusterつまり、サーバーに「ワールドをアップロード」して入室して測定すると
ワールドは落ちずに続行されているのは良いのですが
Scriptが途中で実行が放棄されているではありませんか
Scriptを作る立場からすると 許しがたい行為ですね
スパイクが生じてでも文末まですべて実行するのがルールだと思っていました
実験-----------------
さて、計測Scriptを修正して前進することにします。
エラーでいつ中断されてもいいように
負荷ループごとに処理時間を表示するように修正しました
ようやく調査用のscriptとギミックができました
この調査用のシーンで実験したところ エラーと警告を再現できるようになりました
負荷が ギリギリだと 赤!マークのエラーが出ます 
[Script has allocated too much memory]
負荷を大きくすると 黄色の警告も出現しはじめました
WARN: script execution (51ms) exceeded the soft limit (50ms). The limit will be enforced in the future.
しかし、どのscriptの何行目でerrorかというヒントも表示されず不便です
エラーのでる負荷を記録してもマチマチな値で 調査しにくいです
 

もしも、かおもさんのエミュレータがなければ
unity editor上で profiler分析ができません
するとこんな手探りしかできないのではないでしょうか

 

負荷を変えて測定して 10回づつ測定しました
scriptが最終行まで実行されたら◯
errorが出たらxとしました
数字は scriptが処理にかかった時間です

負荷が小さく16ms以内ならリニアな関係だろうと予想できます
負荷が大きくなれば16msを境に x ばかりと予想しましたが
測定では 負荷が大きくなると 結果がばらついて
ラチがあきません  再現性がなさすぎます

 
 考察-----------------
そもそも 処理時間なら Unity profilerで分析したほうが
よいと思い出しました
Clusterのこの警告とerrorは いずれも
profilerが使えないという前提で
 [スパイクを簡易的に表現しようとしている]
・・・のではないかと思い当たりました
・・・・図参照

 

この赤!マークのエラー  を考察してみます
 [Script has allocated too much memory]
直訳では「メモリーをたくさん喰っています」という文ですが
いままでも 入室の最初に見かけることが多く 実態に合わない的外れなエラーという印象でした
おそらく言葉どおりの意味ではなく 出現するタイミングから 黄色警告と同じような
「処理時間が長いよ」という意味に解釈したほうがいいように思います
あるいは 分類不能なエラーは何でもこれに紐づけしているのかもしれません
そういえば Unity profilerで観察しているとplay game直後に スパイクが生じがちなので
結局 スパイクを表現しようとしていると勝手に解釈しています
(個人の見解です。検証実験や文献上の根拠はありません)

この黄色の警告を考察してみます
> WARN: script execution (383ms) exceeded the soft limit (50ms). 
1つのscriptの処理時間ではなく 複数のスクリプトの合計
たぶん ワールド全体の処理時間を意味しているようです
だとすると どのスクリプトの何行目なのかという 情報は期待できないかもしれません

未解決なことが多々あります
 soft limit (50ms)     hard limit (500ms)の意味が不明です
ソフトウエア上の制限とハードウエア上の制限でしょうか
単にゆるい制限ときつい制限という意味でしょうか
「将来的に施行される予定」とか 500msに緩和されたとか 
よくわからないことが多々ありますが 報告を一旦ここまでとします
考察はいくつかの実験から仮説を立てたもので 文献上の裏付けがありませんので誤解なきように
提案------------------
ここでさらに稚拙な提案をしておきます
別の開発環境ではlua言語で nilトラップ というテクニックがありました
「ユーザーの作ったscriptを中断するならば
処理時間が制限を超えた時に何らかの信号を出して 
ユーザーがそれにトラップをかけて
対策処理を書けるようにしたらどうでしょうか」
処理時間を短くしろという警告だけでは工夫が足りないように思います


・・以上  測定の体験と考察と提案です
なお専門家ではないので理解に間違いがあればお許しください


環境    CCK2.8.0      かおもさんのエミュレータ(CSEmulator2.20)  

  

測定用の scriptとuntityデータを置きました
https://drive.google.com/file/d/1pnkYNNRRa1jhXuPtkqwuxpBgsYMdiGAX/view?usp=sharing
test_ms_009.unitypackage
test_ms_009_readme.txt
この2つを含む zipファイルです

#cluster #ClusterScript



 

人数カウントやっとできた。JavaScriptのトホホ

この記事は

Cluster Creator Advent Calendar 2023 の記事です

今まで簡単にはできなかったことが CCK2.5.0ベータ機能を使うと
数行のscriptで 実現できるようになりました。ほんとなの?
やってみました。室内人数のカウントができました
その過程で・・・勉強したことを書いてみます
 
この記事が役立つ人
webデザインのjavaをやっていない人 数学は得意でも英語が苦手な人向けでしょうか
解説というより学習中の体験記です
解消できていない投げっぱなしの疑問もあります悪しからず

目次1==スペルミスを減らす。キャメル方式のルール==

今まで簡単にはできなかったことが 数行のscriptで 実現できるようになりました。
その一方で、cluster scriptが難しくなったのでしょうか、
バグ取りに半日費やしたら原因がタイプミスでした。
もっと楽しかったはずなのに、自分の脳が衰えたのでしょうか・・・トホホ
 
今までは秀丸エディターで事足りていましたが、脳の衰えを補完すべく
そこで、VScodeを導入しました
  『VScodeの使い方がわからん!機能が多すぎる』 ・・・心の叫びです
javascriptVscodeのちょうどよい解説が見当たらないです
みなさんは、webがらみでjavaVScodeを使う機会があったのでしょうか
WindowsのほかにMac環境の情報も混じっています
検索しても畑違いのHtmlとかwebの例だったりするのでスキップしちゃいます
当方はそういう機会も興味もないのでさっぱりです
  『VScodeの文字の色分けがわからん!!』  ・・・心の叫びです
文字の色がカラフルで多機能そうですが
この色は 必ずこうだという 確証もなく 一覧表も見当たらず
結局、無視していることが多いですね、気休めに過ぎないのでしょうか
  『そもそも大文字小文字の区別が必要だった』がっくし orz  ○| ̄|_ 
日常生活ではグダグダですから・・・・
grep検索でも大文字小文字区別なしで使っていました
ところが未だに プログラム関係では 『大文字小文字の区別』がシビアでした
そんなことは承知していたはずでした。
自分としては、 ユーザー定義の変数名やメッセージやsignal名は 
小文字に統一して命名していたので罠にはかからないはずでしたが
・・・・甘かったようです

例えば・・・・・

『過去形じゃないよ IDだよ!』
 ItemTemplateId(正) これが肉眼では 過去形に見えています
 ItemTemplated(誤)   ・・・という具合にミスタイプしそうです
scriptが テキストで提供されていなかったので
画像を google のOCRで文字化するという手を使いました
大丈夫だろうと点検してみると・・・・
てっきり間違っているではありませんか
 ItemTemplateId(正)
 ItemTemplateld(誤)  アイディーIDが エルディーlDになっています
フォントによっては 微妙に区別できたり似通ってたりするので
スライドの文字では[  l  I  1  ]=[アイ エル いち] の判別がしにくいですから
google OCRが間違うのも無理ないですね
そもそも google OCRでは 妙な半角がコマンドを分断したり
括弧 {(  が違う行にぶっ飛んだりしていますので手直しが必要です
(追記 VScodeにスペルチェカーをインストールした今となっては
 これでも点検できると思います)
次の例は 何と言ってもベータ機能でよく見かける単語
[ playerHandle ]のタイプミスでした
『 playerHandle と  PlayerHandle とどっちが正しいの?』
  playerHandle(正) ・・・後述
  PlayerHandle(誤) script内では使うことはないようです
documentを見ると PlayerHandle という文字も見かけます
playerHandle と  PlayerHandle とどっちを使えばよいのかわからなくなりました
コピペだけでは突破できません。何かルールがあるようです
英単語の真ん中あたりに大文字があるなんて、おかしな英文だと思ったら
キャメル方式だそうです
数学は得意ですが 英語は苦手です。
camel caseってなんだろ?
キャメルってラクダですね ヒトコブラクダとか フタコブラクダとかありますね

programでは半角スペースが使えないから 半角を詰めて
単語の区切りに大文字を使っているようです
それがキャメル方式だそうです
さらにJavascript命名規則によると
クラス名は大文字で始まるというルールがあるようです
アッパーキャメル方式(upper camel case )  UCC と言うらしい
缶コーヒーみたいな用語ですね。アルファベット3文字ってだめなのよね
フルスペルが思い出せないのよね
ローワーキャメルケース(lower camel case)LCC の覚え方はないのでしょうか
小文字先頭ラクダ->小文字ラクダ->子持ちラクダ・・・・ばんざ~い
・・・絵にしてみました、単なる覚え方です 根拠はありません
変数名は 小文字先頭のキャメル方式です
メソッド名は 小文字先頭のキャメル方式です
プロパティ名は 小文字先頭のキャメル方式です 
大文字先頭のキャメル方式の出番はありません 
おお~~ これでスペルミスの頻度を下げれそうです
o.object.playerHandle プロパティ名は小文字先頭のキャメル方式
PlayerHandle  documentだけで見かける 先頭大文字のキャメルケース
気がついたのですがreferenceになにやら
 P とか M のマークがあるのは Property method  のことかもしれない
なにか重要な区別らしい・・・『クラスって何だ?』
『property と methodの違いって何だ?』 
・・・それはもっとまともな記事を読んでいただくとして・・・
referenceの使いかたがちょっとわかってきたかもしれません
 
 

目次2==== データ構造を知る JSON.stringify====

徹底解説「ベータ機能完全に理解した!」に挑戦してみることにします
フェイドラさんの   モーションブース スライド70の 次の4~5行が
キモらしいですが さっぱりわかりせん
アロー関数が1行に2つもあるし ドットが深いし、 
どれが予約語でどれがユーザー変数なんだか?
どれがClusterベータ新機能か  
どれが最近のjavascript用語なのか 『わからん!』・・と心の中で叫んでいます
・・・ということで  勉強に半年ぐらいかかると思っています
  let previousOverlapPlayers = $.state.overlapPlayers;
  let currentOverlapPlayers = $.getOverlaps().map(o => o.object.playerHandle).filter(p => p!= null);
  let newOverlapPlayers = currentOverlapPlayers.filter(c => !previousOverlapPlayers.some(p => p.id==c.id ));
  let exitPlayers = previousOverlapPlayers.filter(p =>!currentOverlapPlayers.some(c => c.id == p.id));
  $.state.overlapPlayers = currentOverlapPlayers;

とはいえ、わかってないのに知ったかぶりで改造を試してみました
当然、エラーがでます
ヒントになるエラーがほしいところですが[ Undefined  ]のエラーが多いです
スペルミスでもドット表記ミスでもこれが返ってくる
Undefined は未定義という意味だそうですがヒントになりませんね
ちなみに Under fined というと 罰金未満だそうです
TypeError: Cannot read property 'filter' of undefined 
TypeError: Cannot read property 'playerHandle' of undefined
Cannot read property '0' of undefined
『エラーメッセージが見当違い!』
『エラーメッセージが不親切!』・・・と叫びたいですが、
それは以前からそうでした  programのデバグはそういうものでしたね
どこから 解き明かしていけばよいでしょうか
map , filter とか  知らないコマンドも多いですし どうも配列関係らしい
当方は 配列って あんまし いじった記憶がないので 探索は迷走します
どうも getOverlapsが 大物らしい 
JSONCSV、 連想配列のkeyとドット表記のpropertyと何か関係あるらしい
(正確な用語が検証できていません 悪しからず)
ジェイソンファイルって聞いたことがあります
初期設定用に setting.json  ファイルをいじれと読んだ記憶があります
ジェイソン(JSON)(JavaScript Object Notation)といえば
ホラー映画『13日の金曜日』のジェイソン(Jason )が想い浮かびます
データ構造がわからないとデバグが迷走するばかりのようです
$.log だけでは足りないので JSON.stringify を 使って可視化することにします
その件は以下の記事にも書きましたが その続きです
-----------以下はgetOverlapsの配列の中身の1例です
"selfNode":{"state":{}
 ,"useGravity":false
 ,"velocity":{"x":0,"y":0,"z":0}
 ,"angularVelocity":{"x":0,"y":0,"z":0}
 }
,"object":{"itemHandle":null
 ,"playerHandle":{"id":"cf0015a4-xxxx-xxxx-891c-1a60c0adaa27"}
 }
------------さらに わかりやすく
getOverlapsの中身を見やすい表に書き直しました  図参照

最下段横が 数値データ です
縦にたどると ドット記法 になります
   例  selfNode.velocity.y
   例 object.playerHandle.id
「お~~なるほど!こういうことか」
データ構造がわかれば、ドット記法が正確に書けるので
コピペや当てずっぽうでミスしなくなり undefinedエラーが減りました
これで 配列も怖くない・・・
(単純な配列でないこれをなんというのだろう?)
連想配列 オブジェクト配列 JSON配列・・だろうか?)
これは、 誰かの参考になるでしょうか
自分としては レファレンスの getOverlaps の 戻り値の例として
図解を補足すればいいんじゃないかと思うぐらいの大発見でした。

目次3==== 室内人数カウント別解 ====

再び室内人数カウントの話しです
getOverlapsが どうも大物で 配列データも複雑で階層が深いようなので
getItemNearの方が 配列の深みに足を取られず 扱いやすいように思います
(~Nearは2通りあります getItemsNear と getPlayersNear です )
(両者ともベータから本採用になるそうです)
というわけで 室内人数カウント を Nearで作りなおしてみました 
getOverlapsとgetItemNearはScriptの扱いが案外と似ています
何が違うか どう使い分けるのか
getItemsNearの方が 原始的で単純です
getItemsNearの接触結界の形は球体の一種類だけです
(Collider , shape , 数値半径 ひっくるめて 接触結界と呼んでみました)
getItemsNearに Colliderは不要です 数学的な半径を指定するだけです 
script内でいくつにでも増やせられるメリットがあるように思います
それに対して
getOverlapsの方が item,player両方に感知できるとか汎用性が高いです
何と言っても shape という新機能が使えます
『shapeって何だ colliderとどう違うのか!』・・という心の叫びです
『何を新しく開発したのか』
getOverlapsの方はdetector shapeを複数配置できるので 
接触結界の形はいろいろ工夫できそうです
複雑な輪郭の部屋や迷路にも対応可能でしょう
mesh collider は convexオンに限るので中途半端でした
注  sampleワールドでは 半透明に可視化しましたが 
実際の運用ではそんな可視化optionはありません。悪しからず

このときにメモったTipsを書いておきましょう

「getOverlapsのScriptを getItemNear に書き換える場合は 主に2箇所ですみます」
変更前    let overlaps = $.getOverlaps();       //detector shapeが必要
変更後    let overlaps = $.getItemsNear($.getPosition() , maxDistance); //それが不要
変更前    let itemHandle = overlap.object.itemHandle;// 配列が深い
変更後    let itemHandle = overlap;     // getItemsNearでは配列が単純
これで何かすごい展開があるのでしょうか
コマンドを比較検証して確かめた時のメモなので
実用性があるかどうかはわかりません
・・・トホホ    
・・・・以上 体験記でした 完全理解にはまだまだ道が遠いです
勘違い、誤字脱字ありましたらごめんなさい
 
感謝 かおもエミュレータに感謝。
   ベータ関係以外にも参考資料を提示されているかたに感謝 
参考tool かおもさんの CSEmulator V2 2.0以後
参考文献 かせーさんの https://note.com/kasei_s/n/nf6a30f35a2b5
    Cluster Script関係メモ(基本β)
参考文献 びわんさんの ClusterScript Beta playerHandle重複排除 
参考文献 フェイドラさんの   ベータ機能完全に理解した!
参考文献 滝 竜三さんの 【ベータ機能】
  近くのプレイヤーについてくるペットをつくる(プレイヤー情報取得)
 
 #cluster #ClusterScript

 

getOverlapsの配列の中身

 
$.getOverlaps()の中身を知りたくて
JSON.stringify を使ってみました
 
 
-----------以下のようなデータ構造になっているようです
"selfNode":{"state":{}
,"useGravity":false
,"velocity":{"x":0,"y":0,"z":0}
,"angularVelocity":{"x":0,"y":0,"z":0}
}
,"object":{"itemHandle":null
,"playerHandle":{"id":"cf0015a4-xxxx-xxxx-891c-1a60c0adaa27"}
}
 
-----------ちなみにアバターではなくitemの場合は以下の通り
"selfNode":{"state":{}
,"useGravity":false
,"velocity":{"x":0,"y":0,"z":0}
,"angularVelocity":{"x":0,"y":0,"z":0}
}
,"object":{"itemHandle":{"id":"10800xxx109285xxx488"}
,"playerHandle":null}
}
------------
配列の中にオブジェクト配列(連想配列)が
複合的にふくまれているようです
これで、
CCL2.5.0ベータ機能で 接触した相手が 
アバターか物か区別できるようになったと思います
従来ならlayerを工夫したり 簡単ではなかったと思います
また、docには書いてなかったようにおもいますが
接触した相手の 速度や回転速度を参照できるようです 
これも何かトリックに使えるかもしれません
アバターが回転しないと入れないドアとかどうでしょう
(まだ試していないので提案にすぎません)
 
一方で、よくわからないことが多々あります
getpositionで アバターの位置を知ることができるのですが
$.getOverlaps()の中身には 見当たりません 不思議です
 
このようにデータ構造が分かれば
ダミーデータを使って配列コマンドの練習ができると思います
サブ垢をつかったり大勢協力して貰う前に 多人数の場合の
ドラフトでのscript 実験ができそうに思います・・・
・・・用語や理解に思い違いがありましたらごめんなさい
配列操作やjavaの学習中なので 途中経過をメモってみました
 #clusterベータ