root/as3/ThreadViewer/ThreadViewer.as

リビジョン 1306, 25.9 kB (コミッタ: daoki2, コミット時期: 3 年 前)

機能追加&アイコン作成

  • svn:executable 属性の設定値: *
Line 
1 /**
2  * ThreadViewer for ActionScript Thread Library
3  *
4  * @author      Copyright (c) 2008 daoki2
5  * @version     0.6
6  * @link        http://www.libspark.org/wiki/daoki2/ThreadViewer
7  * @link        http://homepage.mac.com/daoki2/
8  *
9  * Copyright (c) 2008 daoki2
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27  * THE SOFTWARE.
28  */
29
30 import flash.events.*;
31 import flash.filesystem.*;
32 import flash.data.*;
33 import flash.desktop.NativeApplication;
34 import flash.net.LocalConnection;
35
36 import mx.events.*;
37 import mx.collections.ArrayCollection;
38 import mx.controls.*;
39
40 import org.libspark.snippets.AIRUtils.PreferenceUtil;
41 import org.libspark.thread.ThreadState;
42 import org.libspark.utils.SqlUtil;
43 import org.libspark.snippets.controls.ChartData.FusionCharts.SingleChartData;
44
45 private static const LEFT_PADD:uint = 38; // スレッド名のX座標
46 private var _conn:LocalConnection; // LocalConnection接続用
47 private var threadList:ArrayCollection = new ArrayCollection(); // スレッドリスト
48 private var threadNameLabel:ArrayCollection = new ArrayCollection(); // スレッド名Labelのリスト
49 private var threadStatus:ArrayCollection = new ArrayCollection(); // スレッド状態のリスト
50 private var threadLog:ArrayCollection = new ArrayCollection(); // スレッド遷移グラフのリスト
51 private var pos_x:Number = 0; // スレッド遷移グラフのX座標
52 private var isLogging:Boolean = false; // ログ収集中か否か
53 private var framePerSecond:uint = 24; // フレーム/秒
54 private var frameInterval:Number = 1000/24; // 時間(ms)/フレーム
55 private var _dbconn:SQLConnection; // ローカルデータベース接続用
56
57 /* ######## アプリケーション関連のハンドラ ######## */
58
59 /*
60  * アプリケーションの初期化
61  */
62 private function init():void {
63     // イベントハンドラの登録
64     addEventListener(Event.CLOSING, onAppClosing);
65     addEventListener(FlexNativeWindowBoundsEvent.WINDOW_RESIZE, onWinResize);
66     threadName.addEventListener(MouseEvent.MOUSE_DOWN, threadName_MouseDownHandler);
67
68     // プリファレンス(初期値)の読み込み
69     var result:Object = PreferenceUtil.load(this, "preference.xml");
70     if (!result.status)
71         trace(result.message);
72
73     // 注:最小サイズを設定した時の動作が謎すぎるので、とりあえずコメントアウト
74     //this.minWidth = 780;
75     //this.minHeight = 520;
76     // ウィンドウサイズが最小サイズより小さければ是正
77     //if (this.width < this.minWidth)
78     //  this.width = this.minWidth + 16;
79     //if (this.height < this.minHeight)
80     //  this.height = this.minHeight + 16;
81
82     this.visible = true;
83
84     // LocalConnectionの作成
85     _conn = new LocalConnection();
86     _conn.client = this;
87
88     try {
89         // LocalConnectionに接続
90         _conn.connect("AS3ThreadLibV1"); // 接続名
91         _conn.allowDomain("*"); // どこからの接続でも許す
92
93         // nopの生成
94         createNop();
95
96         // ローカルデータベースをオープン
97         var dbFile:File = File.applicationDirectory.resolvePath("thread.db");
98         _dbconn = new SQLConnection();
99         _dbconn.open(dbFile, SQLMode.UPDATE);
100         SqlUtil.executeSQLStatement(_dbconn, "delete from threadTime"); // 古いデータを削除
101         SqlUtil.executeSQLStatement(_dbconn, "delete from threadState"); // 古いデータを削除
102
103         // Chartの作業ファイルを設定
104         threadStateHtml = File.applicationStorageDirectory.resolvePath("threadState.html");
105         threadStateData = File.applicationStorageDirectory.resolvePath("threadState.xml");
106         threadTimeHtml = File.applicationStorageDirectory.resolvePath("threadTime.html");
107         threadTimeData = File.applicationStorageDirectory.resolvePath("threadTime.xml");
108     } catch(argerr:ArgumentError) {
109         trace("Can't connect...the connection name is already used by another SWF");
110     } catch(error:Error) {
111         trace(error.message);
112     }
113 }
114
115 /*
116  * アプリケーションの終了ハンドラ
117  */
118 private function onAppClosing(event:Event):void {
119
120     // プリファレンス(初期値)の書き込み
121     var prefList:ArrayCollection = new ArrayCollection();
122     prefList.addItem("nativeWindow.x"); // X座標
123     prefList.addItem("nativeWindow.y"); // Y座標
124     prefList.addItem("width"); // ウィンドウの幅
125     prefList.addItem("height"); // ウィンドウの高さ
126     PreferenceUtil.save(this, prefList, "preference.xml");
127
128     // LocalConnectionをクローズ
129     if (_dbconn != null)
130         _dbconn.close();
131 }
132
133 /*
134  * Windowのリサイズハンドラ
135  */
136 private function onWinResize(event:FlexNativeWindowBoundsEvent):void {
137
138     // スレッド名、スレッド遷移グラフの場所を元に戻す
139     threadName.y = 0;
140     threadTime.y = 0;
141
142     // もしログ収集を止めてたら、スレッド実行時間のグラフを再描画
143     if (!isLogging && threadList.length != 0)
144         createThreadTimeChart();
145 }
146
147 /* ######## LocalConnection関連のイベントハンドラ ######## */
148
149 /*
150  * 新規スレッドの取得ハンドラ
151  */
152 public function threadEntryHandler(name:String, newThread:Boolean = true):void {
153    
154     // ログ収集中でなければ終わる
155     if (!isLogging)
156         return;
157    
158     // スレッドリスト中にあるか?
159     if (threadList.contains(name)) {
160         trace("Thread", name, "already exists"); // 既に同名のスレッドが存在する
161     } else {
162         // スレッド名のLabelを生成
163         var t:Label = new Label();
164         t.x = LEFT_PADD;
165         t.y = threadList.length * 16;
166         t.text = name;
167         threadName.addChild(t);
168         threadNameLabel.addItem(t);
169        
170         // スレッド状態のImageを生成
171         var s:Image = new Image();
172         s.x = 8;
173         s.y = threadList.length * 16 + 1;
174         if (newThread)
175             s.source = "icons/NEW.png"; // 新規のスレッド
176         else
177             s.source = "icons/RUNNABLE.png"; //既存のスレッド
178        
179         threadName.addChild(s);
180         threadStatus.addItem(s);
181        
182         // スレッドリストに登録
183         threadList.addItem(name);
184     }   
185 }
186
187 /*
188  * スレッドの名称変更取得ハンドラ
189  */
190 public function threadNameHandler(name:String, newName:String):void {
191
192     // ログ収集中でなければ終わる
193     if (!isLogging)
194         return;
195
196     // スレッドリスト中にあるか?
197     if (!threadList.contains(name))
198         threadEntryHandler(name, false); // 無いので、既存のスレッドとして登録
199
200     // スレッドリストに登録されてるスレッド名を変更
201     var index:int = threadList.getItemIndex(name);
202     threadList.removeItemAt(index); // 古いスレッド名を削除
203     threadList.addItemAt(newName, index); // 新しいスレッド名を登録
204
205     // Labelリストから該当のLabelを取得して、スレッド名を更新する
206     var n:Label = Label(threadNameLabel.getItemAt(index - 1)); // threadListは"nop"も含むので、ひとつ引く
207     n.text = newName;
208 }
209
210 /*
211  * スレッドの状態取得ハンドラ
212  */
213 public function threadStateHandler(name:String, status:uint, time:int):void {
214
215     // スレッド状態画像のファイル名 注:TERMINATINGとTERMINATEDは同じ画像を使う
216     var StateImageFiles:Array = new Array("icons/NEW.png", "icons/RUNNABLE.png", "icons/WAITING.png",
217                                           "icons/TIMED_WAITING.png", "icons/TERMINATED.png", "icons/TERMINATED.png");
218
219     // ログ収集中でなければ終わる
220     if (!isLogging)
221         return;
222
223     // スレッドリスト中にあるか?
224     if (!threadList.contains(name))
225         threadEntryHandler(name, false); // 無いので、既存のスレッドとして登録
226
227     // 状態リストから該当のImageを取得して、画像を更新する
228     var index:int = threadList.getItemIndex(name);
229     var s:Image = Image(threadStatus.getItemAt(index - 1)); // threadListは"nop"も含むので、ひとつ引く
230     s.source = StateImageFiles[status];
231
232     // ローカルデータベースに情報を記録
233     SqlUtil.executeSQLStatement(_dbconn, "insert into threadState(name, state, time) values ('" + name + "', " + status + ", " + time + ")");
234 }
235
236 private var b_color:uint = 0x0000ff; // スレッド遷移グラフのデフォルト色
237
238 /*
239  * スレッドの実行時間取得ハンドラ
240  */
241 public function threadTimeHandler(name:String, startTime:int, endTime:int):void {
242
243     // ログ収集中でなければ終わる
244     if (!isLogging)
245         return;
246
247     // スレッドリスト中にあるか?
248     if (!threadList.contains(name))
249         threadEntryHandler(name, false); // 無いので、既存のスレッドとして登録
250
251     var pos_y:int = threadList.getItemIndex(name) * 16; // スレッド遷移グラフのY座標
252  
253     // スレッド遷移グラフの生成
254     var b:VBox = new VBox();
255     b.x = pos_x;
256     b.y = pos_y;
257     b.toolTip = String(endTime - startTime) + "ms";
258     b.width = (endTime - startTime) * hsScale.value;
259     b.height = 16;
260     b.setStyle("backgroundColor", b_color);
261     threadTime.addChild(b);
262     threadLog.addItem({bar:b, time:(endTime - startTime)}); // スレッド遷移グラフリストへ登録
263
264     pos_x += b.width; // 次回の描画X座標の計算
265
266     // もしフレーム同期ハンドラが呼ばれた直後だったら?
267     // 注:フレーム同期の直後は"nop"が来る
268     if (name == "nop") {
269         checkInterval(endTime, endTime - startTime); // フレーム同期間隔の確認
270
271         // フレーム毎に色を入れ替える
272         if (b_color == 0x0000ff)
273                 b_color = 0x8888ff;
274         else
275                 b_color = 0x0000ff;
276     }
277
278     // ローカルデータベースに情報を記録
279     SqlUtil.executeSQLStatement(_dbconn, "insert into threadTime(name, startTime, endTime, elapse) values ('" + name + "', " + startTime + ", " + endTime + ", " + (endTime - startTime) + ")");
280     tElapseTime.text = convertElapseTime(pos_x);
281 }
282
283 /* ######## コンポーネントのイベントハンドラ ######## */
284
285 /*
286  * Record/Stopボタンのクリックハンドラ
287  */
288 private function bRecordStop_ClickHandler(event:MouseEvent):void {
289
290     hsScale.enabled = isLogging; // 縮尺スケーラを有効/無効にする
291
292     // もしログ収集中だったら?
293     if (isLogging) {
294         // ログ収集を止める
295         bRecordStop.toolTip = "Record"; // ログ収集を止めるから次回は"Record"。ややこしい...
296         threadList.removeItemAt(0); // スレッドリストから"nop"を削除
297         // もしスレッドが1つでもあれば
298         if (threadList.length != 0) {
299             // スレッド選択コンボボックスの更新
300             cbThread.dataProvider = threadList;
301             cbThread.selectedItem = threadList.getItemAt(0);
302
303             // スレッド状態Chartの作成
304             createThreadStateChart(String(threadList.getItemAt(0)));
305
306             // スレッド実行時間のアップデート
307             updateThreadTimes(String(threadList.getItemAt(0)));
308
309             // スレッド実行時間Chartの作成
310             createThreadTimeChart();
311         }
312     } else {
313         bRecordStop.toolTip = "Stop"; // ログ収集を始めるから次回は"Stop"。やっぱりややこしい...
314     }
315
316     isLogging = !isLogging; // ログ収集中なら止める。収集してなかったら、始める。
317     bRecordStop.enabled = isLogging; // Recordボタンを無効/有効にする
318 }
319
320 /*
321  * Clearボタンのクリックハンドラ
322  */
323 private function bClear_ClickHandler(event:MouseEvent):void {
324
325     // 管理リストの削除
326     threadLog.removeAll();
327     threadList.removeAll();
328     threadNameLabel.removeAll();
329     threadStatus.removeAll();
330
331     // スレッド遷移グラフの削除
332     threadName.removeAllChildren();
333     threadTime.removeAllChildren();   
334     pos_x = 0; // 描画X座標を先頭に戻す
335
336     // 画面に表示されてるコンポーネント関連を初期化
337     bRecordStop.enabled = true;
338     cbThread.dataProvider = null;
339     tIssue.text = "";
340     tElapse.text = "";
341     tAveTime.text = "";
342     tMaxTime.text = "";
343     tMinTime.text = "";
344     htmlState.htmlText = "";
345     htmlTime.htmlText = "";
346     tElapseTime.text = "00:00:00.000";
347     tElapseMax.text = "Max 00.000";
348     tElapseMin.text = "Min 00.000";
349     tElapseAve.text = "Ave 00.000";
350     tFPS.text = "FPS: 000";
351     threadName.y = 0;
352     threadTime.y = 0;
353
354     // 内部変数の初期化
355     frameGet = false;
356     maxInterval = 0;
357     maxIntPos = 0;
358     minInterval = 10000;
359     minIntPos = 0;
360     lastNopTime = 0;
361     totalInterval = 0;
362     intervalCount = 0;
363
364     // ローカルデータベースの古いデータを削除
365     SqlUtil.executeSQLStatement(_dbconn, "delete from threadTime");
366     SqlUtil.executeSQLStatement(_dbconn, "delete from threadState");
367
368     // nopを生成
369     createNop();
370 }
371
372 /*
373  * スケールの変更ハンドラ
374  */
375 private function hsScale_ChangeHandler(event:SliderEvent):void {
376
377     // 描画X座標を先頭に戻す
378     pos_x = 0;
379
380     // スレッド遷移グラフの位置とサイズを更新
381     for each (var val:* in threadLog) {
382         var b:VBox = VBox(val.bar);
383         var time:int = int(val.time);
384         b.x = pos_x;
385         b.width = time * event.value; // 縮尺と時間からサイズを計算
386         pos_x += b.width;
387     }
388 }
389
390 /*
391  * スレッド選択コンボボックスのクローズハンドラ
392  */
393 private function cbThread_CloseHandler(event:Event):void {
394    
395     // スレッド状態Chartの作成
396     createThreadStateChart(String(ComboBox(event.target).selectedItem));
397
398     // スレッド実行時間の更新
399     updateThreadTimes(String(ComboBox(event.target).selectedItem));
400 }
401
402 /*
403  * インフォメーション表示
404  */
405 private function bInfo_ClickHandler(event:MouseEvent):void {
406     // Publisher IDをアラートで表示
407     Alert.show(NativeApplication.nativeApplication.publisherID, 'Publisher ID');
408 }
409
410 /*
411  * Interval Maxラベルのクリックハンドラ
412  */
413 private function tElapseMax_ClickHandler(event:MouseEvent):void {
414     // フレーム同期間隔が最大の場所にスクロール
415     threadTimeContainer.horizontalScrollPosition = maxIntPos * hsScale.value;
416 }
417
418 /*
419  * Interval Minラベルのクリックハンドラ
420  */
421 private function tElapseMin_ClickHandler(event:MouseEvent):void {
422     // フレーム同期間隔が最小の場所にスクロール
423     threadTimeContainer.horizontalScrollPosition = minIntPos * hsScale.value;
424 }
425
426 /*
427  * threadNameのドラッグ制御
428  */
429 private var m_x:Number;
430 private var m_y:Number;
431 private function threadName_MouseDownHandler(event:MouseEvent):void {
432
433     // 現座標の登録
434     m_x = event.stageX;
435     m_y = event.stageY;
436
437     // イベントハンドラの登録
438     threadName.addEventListener(MouseEvent.MOUSE_MOVE, threadName_MouseMoveHandler);
439     threadName.addEventListener(MouseEvent.MOUSE_UP, threadName_MouseUpHandler);
440 }
441
442 private var chata:Array = new Array(1, -1); // チャタリング防止用のバッファ
443 private var chata_cancel:int = 0; // チャタリング防止キャンセルのカウンタ
444 private function threadName_MouseMoveHandler(event:MouseEvent):void {
445
446     // もしスレッド名が表示領域に収まらないなら
447     if (threadName.height > threadName.parent.height) {
448         var delta_y:Number = event.stageY - m_y; // 移動量の計算
449         var pos_y:Number = threadName.y + delta_y; // Y座標を求める
450
451         // チャタリング防止のアルゴリズム:
452         // 過去2回のドラッグ方向(上もしくは下)と違ったらチャタリングと判断してキャンセル
453         // ただし、同じ方向に2回続けば、チャタリングじゃないと判断
454         if (chata[0] < 0 && chata[1] < 0) {
455             if (delta_y >= 0 && chata_cancel < 2) {
456                 pos_y = 1;
457                 chata_cancel++;
458             } else {
459                 chata[0] = chata[1];
460                 chata[1] = delta_y;
461                 chata_cancel = 0;
462             }
463         } else if (chata[0] >=0 && chata[1] >= 0) {
464             if (delta_y < 0 && chata_cancel < 2) {
465                 pos_y = 1;
466                 chata_cancel++;
467             } else {
468                 chata[0] = chata[1];
469                 chata[1] = delta_y;
470                 chata_cancel = 0;
471             }
472         } else {
473             chata[0] = chata[1];
474             chata[1] = delta_y;
475         }
476
477         // 移動可能か?
478         if ((pos_y <= 0) && (pos_y > (threadName.parent.height - threadName.height))) {
479             threadName.y = pos_y;
480             threadTime.y = pos_y;
481         }
482     }
483
484     // 現座標を更新
485     m_x = event.stageX;
486     m_y = event.stageY;
487 }
488
489 private function threadName_MouseUpHandler(event:MouseEvent):void {
490
491     // イベントハンドラを削除
492     threadName.removeEventListener(MouseEvent.MOUSE_MOVE, threadName_MouseMoveHandler);
493     threadName.removeEventListener(MouseEvent.MOUSE_UP, threadName_MouseUpHandler);
494
495     // チャタリング防止解除
496     chata[0] = 1;
497     chata[1] = -1;
498     chata_cancel = 0;
499 }
500
501 /* ######## ローカル関数 ####### */
502
503 /*
504  * スレッドの状態の割合グラフの生成
505  */
506 private var threadStateHtml:File = null; // 作業ファイル
507 private var threadStateData:File = null; // 作業ファイル
508 private function createThreadStateChart(name:String):void {
509
510     // それぞれのスレッド状態の時間を求める
511     var result:ArrayCollection = getThreadStateTime(name);
512
513     // スレッドの状態が1つ以上あればChartを生成
514     if (result.length != 0) {
515         var chartData:SingleChartData = new SingleChartData();
516         chartData.graphAttribute.decimalPrecision = "0";
517         chartData.graphAttribute.formatNumberScale = "0";
518         for each (var val:* in result) {
519             chartData.addSetElement(val);
520         }
521         chartData.createHtmlFile(threadStateHtml, "Doughnut2D", htmlState.width, htmlState.height, threadStateData.nativePath);
522         chartData.createDataFile(threadStateData);
523         htmlState.location = "file:///" + threadStateHtml.nativePath;
524     } else
525         htmlState.htmlText = ""; // 空のHTMLを表示
526 }
527
528 /*
529  * スレッドの状態時間の演算
530  */
531 private function getThreadStateTime(name:String):ArrayCollection {
532
533     // Chart用の情報
534     var stateName:Array = new Array("NEW", "RUNNABLE", "WAITING", "TIMED_WAITING", "TERMINATING", "TEMINATED"); // スレッドの状態名
535     var stateColor:Array = new Array("E1E1E1", "00FF00", "FF0000", "FFFF00", "656565", "656565"); // スレッドの状態色
536     var elapse:Array = new Array(0, 0, 0, 0, 0, 0); // スレッドの状態時間
537
538     // 該当スレッドの状態データを取得
539     var result:Array = SqlUtil.getData(_dbconn, "select name, state, time from threadState where name == '" + name + "'");
540
541     var currentState:int = 0;
542     var lastTime:int = 0;
543     var value:ArrayCollection = new ArrayCollection();
544
545     // もし状態データが存在すれば
546     if (result[1].data != null) {
547         for each (var val:* in result[1].data) {
548             elapse[currentState] += (val.time - lastTime); // スレッドの状態時間を計算する
549             currentState = val.state;
550             lastTime = val.time;
551         }
552         // スレッドの状態遷移が1つ以上あれば
553         if (result[1].data.length > 1) {
554             // スレッドの状態時間をChart用データに登録
555             for (var i:uint = 1; i < 6; i++)
556                 value.addItem({name: stateName[i], value: elapse[i], color: stateColor[i]});
557         } else {
558             // 無ければスレッドの状態時間は正しく求められないので、仕方ないからスレッドの実行時間を状態時間として求める
559             var result2:Array = SqlUtil.getData(_dbconn, "select sum(elapse) as value from threadTime where name =='" + name + "'");
560             if (result2[1].data != null) {
561                 value.addItem({name: stateName[0], value: 0, color: stateColor[0]}); // ダミーデータ
562                 value.addItem({name: stateName[currentState], value: result2[1].data[0].value, color: stateColor[currentState]});
563             }
564         }
565     }
566     return value;
567 }
568
569 /*
570  * スレッドの実行時間等の情報更新
571  */
572 private function updateThreadTimes(name:String):void {
573     // 該当スレッドの実行回数を取得
574     var result:Array = SqlUtil.getData(_dbconn, "select count(*) as issue from threadTime where name == '" + name + "'");
575
576     // もしデータがあれば
577     if (result[1].data != null) {
578         // スレッドの実行回数
579         tIssue.text = result[1].data[0].issue;
580
581         // スレッドの総実行時間を取得
582         result = SqlUtil.getData(_dbconn, "select sum(elapse) as value from threadTime where name == '" + name + "'");
583         tElapse.text = result[1].data[0].value;
584
585         // スレッドの平均実行時間を計算
586         tAveTime.text = "" + int(tElapse.text) / int(tIssue.text);
587
588         // スレッドの最長実行時間を取得
589         result = SqlUtil.getData(_dbconn, "select max(elapse) as value from threadTime where name == '" + name + "'");
590         tMaxTime.text = result[1].data[0].value;
591
592         // スレッドの最短実行時間を取得
593         result = SqlUtil.getData(_dbconn, "select min(elapse) as value from threadTime where name == '" + name + "'");
594         tMinTime.text = result[1].data[0].value;
595     } else {
596         // データ無い...
597         tIssue.text = "";
598         tElapse.text = "";
599         tAveTime.text = "";
600         tMaxTime.text = "";
601         tMinTime.text = "";
602     }
603 }
604
605 /*
606  * スレッドの実行時間のグラフ生成
607  */
608 private var threadTimeHtml:File = null;
609 private var threadTimeData:File = null;
610 private function createThreadTimeChart():void {
611
612     // スレッドの実行時間データを求める
613     var result:ArrayCollection = getThreadElapseTime();
614
615     // スレッドの実行時間Chartの生成
616     var chartData:SingleChartData = new SingleChartData();
617     chartData.graphAttribute.decimalPrecision = "0";
618     chartData.graphAttribute.formatNumberScale = "0";
619     for each (var val:* in result) {
620         chartData.addSetElement(val);
621     }
622     chartData.createHtmlFile(threadTimeHtml, "Bar2D", htmlTime.width, htmlTime.height, threadTimeData.nativePath);
623     chartData.createDataFile(threadTimeData);
624     htmlTime.location = "file:///" + threadTimeHtml.nativePath;
625 }
626
627 /*
628  * スレッドの実行時間の計算
629  */
630 private function getThreadElapseTime():ArrayCollection {
631
632     // それぞれのスレッドの実行時間の合計を得る
633     var result:Array = SqlUtil.getData(_dbconn, "select name, sum(elapse) as value from threadTime group by name order by value desc");
634
635     var value:ArrayCollection = new ArrayCollection(); // Chart用データ
636     var cnt:int = 0;
637     var etc_time:int = 0; // TOP 10以外のスレッドの実行時間の合計
638
639     for each (var val:* in result[1].data) {
640         // まだTOP 10が求まってなければ
641         if (cnt < 10) {
642             value.addItem({name: val.name, value: val.value}); // 実行時間をChartデータに登録
643         } else {
644             // TOP 10以外のスレッドの実行時間を足す
645             etc_time += val.value;
646         }
647         cnt++;
648     }
649
650     // スレッドが10個以上あれば
651     if (cnt >= 10)
652         value.addItem({name: "etc.", value: etc_time}); // TOP 10以外のスレッドの実行時間をChartデータに登録
653
654     return value;
655 }
656
657 /*
658  * フレーム同期間隔の確認/更新
659  */
660 private var frameGet:Boolean = false; // フレーム同期を既に受け取ったか
661 private var lastNopTime:int = 0; // 最後にnopが来た時間
662 private var maxInterval:int = 0; // フレーム間隔の最大値
663 private var maxIntPos:int = 0; // 最大フレーム間隔が発生した時間
664 private var minInterval:int = 10000; // フレーム間隔の最小値 デフォルト値:10秒
665 private var minIntPos:int = 0; // 最小フレーム間隔が発生した時間
666 private var totalInterval:int = 0; // 総フレーム間隔時間
667 private var intervalCount:int = 0; // フレーム同期回数
668 private function checkInterval(t:int, period:int):void {
669     var intervalTime:int = 0;
670    
671     // もしフレーム同期を既に取得済みなら
672     if (frameGet) {
673         intervalTime = t - lastNopTime; // 同期間隔を求める
674     } else {
675         intervalTime = period;
676         frameGet = true;
677     }
678     totalInterval += intervalTime;
679     intervalCount++;
680
681     // もし現在の最大値より大きかったら
682     if (intervalTime > maxInterval) {
683         maxInterval = intervalTime;
684         maxIntPos = pos_x - intervalTime;
685         tElapseMax.text = "Max " + convertElapseTime(maxInterval).substring(6);
686     }
687
688     // もし現在の最小値よりも小さかったら
689     if (intervalTime < minInterval) {
690         minInterval = intervalTime;
691         minIntPos = pos_x - intervalTime;
692         tElapseMin.text = "Min " + convertElapseTime(minInterval).substring(6);
693     }
694
695     var ave_time:int = totalInterval/intervalCount; // 平均フレーム間隔時間を求める
696     tElapseAve.text = "Ave " + convertElapseTime(ave_time).substring(6);
697     tFPS.text = "FPS: " + int(1000 / ave_time); // FPSを計算
698     lastNopTime = t; // 現在時間の更新
699 }
700
701 /*
702  * 時間(ms)を文字列 "HH:MM:SS.SSS" に変換
703  */
704 private function convertElapseTime(time:int):String {
705     var elapseTime:Date = new Date(time);
706     var value:String = "";
707     if (elapseTime.hoursUTC < 10)
708         value += "0";
709     value += (elapseTime.hoursUTC + ":");
710     if (elapseTime.minutesUTC < 10)
711         value += "0";
712     value += (elapseTime.minutesUTC + ":");
713     if (elapseTime.secondsUTC < 10)
714         value += "0";
715     value += (elapseTime.secondsUTC + ".");
716     if (elapseTime.millisecondsUTC < 100)
717         value += "0";
718     if (elapseTime.millisecondsUTC < 10)
719         value += "0";
720     value += (elapseTime.millisecondsUTC + "");
721     return value;   
722 }
723
724 /*
725  * nopを生成
726  */
727 private function createNop():void {
728     threadList.addItem("nop"); // スレッドリストに"nop"を登録
729     var t:Label = new Label();
730     t.x = LEFT_PADD; t.y = 0; t.text = "nop";
731     threadName.addChild(t);
732 }
733
734 /*
735  * Frame Per Second(FPS)情報の取得ハンドラ
736  */
737 public function frameInfoHandler(fps:uint):void {
738     framePerSecond = fps;
739     frameInterval = 1000/framePerSecond;
740 }
741
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。