comparison TaskManager/ChangeLog @ 0:04e28d8d3c6f

first commit
author Daiki KINJYO <e085722@ie.u-ryukyu.ac.jp>
date Mon, 08 Nov 2010 01:23:25 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:04e28d8d3c6f
1 2010-8-7 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
2
3 get_segmentのinlineは、その場に static に置いて、default のものを置いておく。
4 size のcheckはしない。
5
6 MemList は廃止。QueueInfo に。
7
8 Data 領域は、2^n 管理で、move/compaction を行なう。(が、今は書かない)
9
10 とりあえず、SPUのobject管理だが...
11
12 2010-8-6 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
13
14 Bulk, Simple, basic は一つにするべきだよな。many_task は、sort と言う名前に変えるべき。
15
16 2010-7-31 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
17
18 なんと、simple task を SchedTaskManager 経由で作ると、
19 PPE task しか作れなくなっていたらしい。それな遅いよ。
20 SchedTaskManagerのtask managerがFifoManagerだったのが
21 原因。CellTaskManager を使う時には、FifoManagerは消せる?
22
23 その代わり、dead lock が起きる。待ち先のtaskが消滅する場合が
24 あるらしい。
25
26 やっぱり、既に終了した task に対して wait for してしまうのが
27 まずいらしい。自分で HTask をfree してやれば良いわけだが..
28
29 2010-7-30 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
30
31 TASK_LIST_MAIL でない方が高速なみたい
32 sort (many_task) が、とっても遅くなっている
33
34 2010-7-24 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
35
36 やっぱり、load module のlinkの解決はやらないといけないので、
37 無理に、SchedTaskのAPI全部を virtual にする必要はないらしい。
38 spu-gcc spe/ChainCal.o -Wl,-R,spe-main -o tmp.o
39 と言う形で、link してやれば良い。(ただし、必要なものが参照されている場合)
40
41 2010-7-16 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
42
43 SimpleTask のsizeを16の倍数に。そうしないと、Taskのaligmentが16に
44 ならないので、gcc -O9 で破綻する。
45
46 2010-7-14 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
47
48 SchedTaskArray::exec の run の値が最適化で、おかしくなるのは、gcc のbugらしい。
49 SimpleTask の finish mail が返るのが早すぎる。write を呼ぶのが正しい。
50 cur_index++ してしまうと、task1/task2 のcur_indexが同じになってしまう。
51
52 2010-5-25 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
53
54 PPE側のpost_funcやtaskを実行している時にもSPEからのメールは読んでしまう
55 のが望ましい。読んで、とりあえずfifoに入れておく。その場で処理しても良いが、
56 check_task_list_finishとかが再帰的に呼びされるのがやっかい。
57
58 Task 実行ループは Scheduler にpoling routineを登録するのが良さそう。
59 post_func は、SchedTask 経由で poling すれば良い。
60
61 2010-5-22 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
62
63 CpuThread を作るなら、create_task は、manager にメールで教えないとだめ。
64 CpuManager みたいなものを用意しないとダメか。
65
66 HTask から、waitfor/create_task とかは、TaskManager を呼んでいる。
67 そのたびに CAS (Check and set) するのはばかげているよな〜
68 TaskManager にメールで送る方が良いのではないか。
69
70 wait_for する Task が既に終了していると、存在しないTaskあるいは、
71 別な Task を wait_for する場合がある。いわゆるゾンビだけど、これは
72 どうしよう? 生きているかどうかを識別するように id を付けるか?
73
74 どうも、TaskManager.{h,cc} は要らないっぽい。TMmain に渡されるのも
75 SchedTask である方が自然。
76
77 TaskListInfo は循環リストなので、SPU/PPU scheduler に渡す前に、
78 getLast()->next = 0 する必要がある。freeAll() する前に、直さないと
79 だめ。getList() みたいなものを用意しても良いが...
80
81 Scheduler のconnector(DMA) / Memory 関連は Scheduler.{h,cc} から
82 追い出すべき。connector/memory とかを SchedTask に持たせれば良い。
83 そうすると、API追加でScheduelr.{h,cc} / TaskManagerImple とかを修正する
84 必要がなくなる。
85
86 2010-5-11 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
87
88 speTaskList_bg は追放するべきだと思われる。(done)
89
90 PPE task はTaskList をすべて実行するまで戻って来ない。
91 なので、spe のmail checkが疎かになっている。
92 PPE task の実行途中で SPEのmail checkを行なうべき。
93
94 Fifo/Cell TaskManagerImpl は統一できるのではないか? (done)
95
96 SchedTask は今は各Taskのselfを返しているがTaskListにするべき
97 spe からのメールはTaskListが空になった時で良い。早めに、
98
99 PPE Taskを早めに起動する義理はある? あるかも知れない。Quick Reply Property。
100
101 TaskList もDataSegement化するべきだと思われる。(done)
102
103 Scheduler::task_list もDataSegment化して、メインメモリ上に置く。
104
105 2010-4-28 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
106
107 SchedTaskBase のみにインスタンス変数を書かせて、
108 SchedTask*.h には method のみを書かせる。
109 そうすると、デバッグが楽だし、object のallocateも楽。(done)
110
111 HTask(list) -> TaskList(array) -> SchedTask
112
113 というcopyだが、SchedTask で最初から作る方が良いのかも。
114 それを DataSegment で共有する。
115
116 SimpleTask のMailを、
117 if (mail_is_not_full) send_mail() ;
118 else if (queue is not full) enqueuue() ;
119 else wait_mail();
120 ってな感じに出来ないの?
121
122 Multi thread にすると、PPEのmail loop が暴走する可能性がある。
123 このあたりなんか方法があるはずだが...
124
125 2010-4-24 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
126
127 write T3 T2 T1 TL TA0 TA1
128 exec T2 T1 TL TA0 TA1 TA2
129 read T1 TL TA TA1 TA2 T2
130 next T1 TL TA TA1 TA2* T2  
131
132 *のところで終了mailが出てTaskArrayのデータがfreeされてしまうので、よくない
133 そうならないように、一段TAN(SchedTaskArrayNop)を挟む。
134
135 write T3 T2 T1 TL TA0 TA1 TA2 TAN%
136 exec T2 T1 TL TA0 TA1 TA2 TAN T2
137 read T1 TL TA TA1 TA2 TAN T2 T3
138 next T1 TL TA TA1 TA2 TAN T2 T3 
139
140 %のところで終了mailを送る。T2のreadのところで、TaskArrayのデータはreadbuff上にあるので
141 破壊されてしまう。なので、savedTask->task->self の値はTANにコピーして持っていく必要がある
142
143 2009-12-19 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
144
145 そうか、TaskList->next は、SPE 側で自分で呼び出しているわけね。
146 と言うことは、schdule(list) が終るまでは、mail check に戻って
147 こない... それだと、ちょっとまずいね。
148
149 となると、TaskList のfree(clear)のtimingは? schdule から抜けた
150 時と言うことになるわけだけど。
151
152 waitQueue は、実は不要。しかし、終了条件、dead lock detection には
153 必要らしい。
154
155 2009-12-16 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
156
157 CellTaskManagerのTaskList_bg は変だよ。TaskList 自体が
158 queue なんだから、トップ二つを特別扱いしているだけでしょう。
159
160 TaskList をread()しているのと同時にnext()されてしまうので、
161 next()の中で、TaskList の中身に触るのは良くない。SchedTask
162 は微妙に大丈夫らしい。TLのdma waitは、write になっていた。
163
164 TaskArray/TaskArray1 は、TAの中身をnext()で判断しているので、
165 これはただしくない。TaskListLoad を間にはさむ手もあるが...
166
167 write T3 T2 T1 TL TA0 ! TL の dma wait
168 exec T2 T1 TL! TA0 TA1
169 read T1 TL* TA TA1 TA2 * TL の dma start
170 next T1 TL% TA TA1 TA2 % TAの作成判断
171
172 TaskListLoad をはさむ、安全だけど遅い方法
173
174 write T3 T2 T1 TLL TL
175 exec T2 T1 TLL! TL TA0
176 read T1 TLL*TL TA0 TA1
177 next T1 TLL TL% TA0 TA1
178
179 なんだけど、pointer の下位ビットで送ると、前者で実行できる。
180 next で、TaskList のloadを始めてしまうという手もあるな...
181
182 write T3 T2 T1 TL TA0 ! TL の dma wait
183 exec T2 T1 TL TA0 TA1
184 read T1 TL! TA TA1 TA2 * TL の dma start
185 next T1* TL% TA TA1 TA2
186
187 こっっちかな...
188
189 2009-12-15 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
190
191 SimpleTask の実装が出来たので、TaskArray からは、
192 PPU側に詳細な情報を返せる。と言うことは、SPU側から
193 PPU Task を投入出来る。実装すればだけど。
194
195 Task 側から書き出し情報を設定するAPIが必要。
196 マニュアルも書くか。
197
198 Down cast をすべてなくしたい。Sched*.cc からは取れました。
199
200 まだ、いらないものが結構あるらしい...
201
202 2009-12-14 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
203
204 ようやっと動きました。SIMPLE_TASK でないのとの互換性
205 を維持するべきか? 頑張れば出来ると思うけど...
206
207 方法は二つ。TaskList に無理矢理 Task を詰め込むか、
208 今までのHTaskを、TaskArray に読み変えるか。前者は変更が
209 多い。後者は、wait_for が微妙。
210
211 前者で実装しました。そのうち落すかも。エラーチェックと、
212 エラー処理関数が必要。コメントを書かないと。
213
214 2009-12-12 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
215
216 SchedTask::next で、TaskArray を認識して、そこで、
217 SchedTaskArrayLoad を作る。次のSchedTask を用意して、
218 SchedTaskArrayLoad にsavedSchedTaskとして引き渡す。
219
220 SchedTaskArrayLoad::read は、TaskArray をload する。
221 SchedTaskArrayLoad::next は、SchedTaskArray を返す。
222 この時に、saveedSchedTask を引き継ぐ。
223 write/exec は何もしない。(これで、pipe line を空ける)
224
225 SchedTaskArray::read は、List DMA をload する。
226 SchedTaskArrayLoad::next は、TaskArray 上のTaskを返す。
227 exec/write は、List DMA 対応で動作する。
228 もうない場合には、SchedTaskArrayLoad から伝えられた
229 saveされた SchedTask を返す。mail も送る。
230
231 2009-12-7 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
232
233 pipeline stageは、loop local だから、instance 変数である必
234 要はない。途中で中断することはない。これを一時変数にして、
235 再帰的にpipeline stage を呼び出せば良いらしい。
236
237 pipeline stage のtask1に引数で new SchedTaskList を渡すと、
238 run()でtask1 = new SchedNop() するよりループ二回ぐらい高速
239 になるらしい。が、おそらく、ほとんど影響はない。
240
241 pipelineで既に走っている次のTaskのreadを停める必要があるら
242 しい。前もってNopを入れて置く方法もあるが、TaskListの境界が
243 問題になる。停めないとパイプラインバッファを新たに取る必要
244 があり連鎖的にはまる。
245
246 writeしている奴もいるしな。スケジューラは一段しかネストしな
247 いから新しくバッファ取るか? いや、やっぱり許されないか。い
248 や、取るか。うーん、悩ましい。どうせ、Task list は確保しな
249 いとだめだから… 再帰しないで、もとのスケジューラで動かした
250
251
252 そのためには、既に Pipeline に入っているTaskが邪魔か。2つTask
253 を投入して、間に TaskList read が入ってもなんとかなるように
254 工夫するのが良いっぽい
255
256 なんか、Renew Task の道を歩んでいる気もするが...
257
258 2009-12-6 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
259
260 やっぱり、Graphical なprofileが欲しいかな。どのDMA/Taskに時間がかかっている
261 かが見えるようなものが。profile で、メインメモリにlogを書き出すようなもの
262 が必要。deubg 用のデータ書き出しツールがいるな。
263
264 log header
265 command(16) cpu-id(16) event(32) time(64)
266 struct debug_log {
267 uint16 command;
268 uint16 cpu-id;
269 uint32 event;
270 uint32 time;
271 }
272 ぐらい? get_segment 使うべきか。連続領域に使える get_segement があると
273 良いわけね。write とも言うが。
274
275 sort で、memcpy しているのは変。read/write buffer をflipしてやると
276 良い。両方とも握っているんだから問題ない。ただし、read/write buffer
277 の大きさは等しい必要がある。SchedTask->flip_read_write_buffer(); か?
278 sort ちゃんとは動いているんだよ。
279
280 word_count_test の稼働率が10%なのはひどい。word_count の方だと偏りが
281 あって、一部が50%になるが10%ぐらい。DMA待ちではなくて、メール待ちに
282 なっている。PPUネックになっているっぽい。
283
284 TaskArray は、SchedTask を拡張して処理する。next で、次のTaskを
285 用意する感じか。inData/outData の処理も。
286
287 2009-12-5 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
288
289 なんかなぁ。一つの機能を付け加えようとすると、
290
291 TaskManager/Cell/CellTaskManagerImpl.cc
292 TaskManager/Cell/CellTaskManagerImpl.h TaskManager/Cell/spe/CellDmaManager.cc
293 TaskManager/Cell/spe/CellDmaManager.h TaskManager/Cell/spe/ShowTime.cc TaskManager/Cell/spe/ShowTime.h
294 TaskManager/Cell/spe/SpeTaskManagerImpl.cc TaskManager/Cell/spe/SpeTaskManagerImpl.h
295 TaskManager/Cell/spe/main.cc TaskManager/Fifo/FifoTaskManagerImpl.cc
296 TaskManager/Fifo/FifoTaskManagerImpl.h TaskManager/Makefile.cell TaskManager/kernel/ppe/TaskManager.h
297 TaskManager/kernel/ppe/TaskManagerImpl.h TaskManager/kernel/schedule/DmaManager.h
298 TaskManager/kernel/schedule/SchedTask.cc TaskManager/kernel/schedule/SchedTask.h
299 TaskManager/kernel/schedule/Scheduler.h TaskManager/kernel/sys_task/SysTasks.h
300 example/word_count_test/main.cc
301
302 こんなにファイルをいじらないと出来ない。それって、全然、ダメじゃん。
303
304 なんでかなぁ。
305 SchedTask -> Scheduler -> Connector
306 TaskManagerImpl -> {CellTaskManager,FifoTaskManager/SpeTaskManager}
307 を全部、いじる羽目になる。
308 SchedTask から system call するより、Task を定義して、
309 それを呼び出すって方がましかも。
310
311
312 2009-11-23 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
313 list.bound は廃止。list element から計算可能。
314
315 2009-11-20 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
316
317 mail_sendQueue の実装がだめ。こういう実装をすると、queue の
318 正しさを関数の中に閉じ込められない。なんか、無限リストにな
319 っているらしい。参照が、渡り歩いているどこかの場所でダメに
320 なっているらしい。
321
322 実際、mail_sendQueue は、free list に置き換わってしまう。
323 これまで、これがおかしくならなかった理由は不明。
324
325 connector に外から手を入れないで、ちゃんとfunction callするべし。
326
327 わかりました。
328 if (list) {
329 ...
330 mainScheduler->send_mailList(in_mail_list);
331 }
332 out_mail_list = mainScheduler->recv_mailList();
333
334 としてしまったが、recv_mailList() でなく、send_mailList で、
335 mail_sendQueue をクリアしていたので、
336 } else {
337 mainScheduler->send_mailList(in_mail_list);
338 }
339 とする必要があったらしい。if (list) を入れたせいで、こうなった。
340 でも、当然、recv_mailList() で clear するべき。atomicity の意味でも。
341 なので、send_mailList() での clear は必要ない。
342
343
344 2009-11-19 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
345
346 finish_task を全員が待つ設定で、finish_task を終了判定に
347 使っている。それだと、すべてのtaskが、finish_task のwait queue
348 を*必ず*触りにいってしまう。
349
350 finish_task への待ちを取り除くと、CellTaskManagerImpl::run()
351 が、
352 do {
353 ppeMail = ppeManager->schedule(ppeTaskList);
354 cont:
355 ppeTaskList = mail_check(ppeMail);
356 } while (ppeTaskList);
357 とかやっているので、ここで抜けてしまう。
358
359 要するに、SPUの状態を見て、running がなくなるのを調べるべき
360 なんだが、SpeTheads は「一つしかない」らしい。spe_running
361 で、走っているものがあるかどうか見るか?
362
363 Cell だと、MainScheduler と FifoScheduler の二種類の
364 スケジューラがあるのか。
365
366 MainScheduler --- task list -----> FifoScheduler
367 MainScheduler <-- finish task ---- FifoScheduler
368
369 というわけね。
370
371 2009-11-15 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
372
373 List DMAって、32bit address を使っているらしい。それは、ちょっと
374 ひどいなぁ。
375
376 2009-11-14 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
377
378 やっぱり、TaskList の存在が許せない。あったとしても不定長でしょう。
379 無駄なコピーが多すぎる。
380
381 2009-11-14 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
382
383 Scheduler / TaskManger / TaskManagerImpl の区別が不明
384 HTask は、TaskManagerImpl を持ってる。
385
386 Scheduler は SchedTask から直接見えないはずだが、SchedTask は、
387 Scheduler は知っているが、TaskManager は知らない。これがかなりの
388 混乱を生んでいる。
389
390 SPU上では、TaskManager が存在しないのが原因らしいが、allcoate とかは、
391 TaskManager が行うはず。なので、SPU上にもTaskManagerがある方が自然。
392
393 SchedTask が自分自身で scheduling してしまっているので、Scheduler
394 には、ほとんど仕事がない。なので、大半の処理を scheduler -> manager
395 経由で行うことになる。
396
397 2009-11-14 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
398
399 要するに、SPE task 側から addOutData できればよい。
400 でも、別に、PPE側から計算してもよいはずだけどね。
401 そうすれば、renew task は取り外せる。
402
403 SchedDefineTask1(DrawSpanEnd,draw_span_end);
404 で、名前を指定させておいて、さらに、
405 SchedExternTask(DrawSpanEnd);
406 SchedRegisterTask(TASK_DRAW_SPAN_END, DrawSpanEnd);
407 で、新しく名前を要求するのって、なんとかならんの? 読みづらいんだよ。
408 DrawSpanEnd を、そのまま使ってもよさそうだけど?
409
410 せっかく、renew task を外したのに、HD crash で失ってしまいました。
411
412 add_param が順序を持っているのは見づらい。数字で指定する方が合理的。
413
414 2009-10-11 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
415
416 単純な、rbuf, wbuf + write return size の task のAPI
417 List DMA の API
418 投入 cpu 別の spawn method
419 Redering 時の内部からの DMA への直接アクセスへの禁止等など
420
421 set_post で登録する関数も、task のrun関数と同じ型にした方が便利そう。
422
423 SPU側でも配列(TaskList)ではなく、TaskQueue で管理すれば、
424 renew task は簡単に実装できる。
425
426 SchedTask の renew かそうでないかの区別は全部なくす。ex_init とかは、
427 なくなるはず。その代わり TaskQueue で管理する。
428
429 TaskList に inListData/outListData が入っているのは、やはりおかしい。
430 もっとコンパクトであるべき。
431
432 TaskList は、こまめに終了をPPE側へ知らせるのではなく、TaskListの
433 書き換えで知らせる方が良い。
434
435 SPUからPPUへ、create task 出来た方が良い。それはTaskList の書き出し
436 で行なう。
437
438 2009-10-11 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
439
440 ようやっと直せました。inListData/outListData は別に転送しないで、
441 一緒に転送してしまった方が良い。どうせ、いつも転送しているのだから。
442
443 word_count が fifo の方が高速なのは、どうにかしてください。
444
445 Renew Task の addInData は、メインメモリからDMAするので正しいらしい。
446 直し方を間違えた。
447
448 Task をmemcpyして、TaskList に入れているが、List DMA に直すべき。
449 Simple Task を常に起動して、List DMA task は、その中で、Renew Task
450 として起動するのが良いのでは? そうすれば、Task Load 自体を Task に
451 出来る。
452
453 Renew Task の実行順序が filo になっている。このあたり変なので、
454 修正するべきでしょう。Renew用の TaskList を持てば良いんじゃないか?
455 task->self の ad-hoc な使い方が泣ける。ひどすぎます。
456
457 2009-10-06 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
458
459 Task 内の create_task は、SchedTask に対してで、
460 PPE 上では、Manager に対してだよね。だから、出来る
461 ことがかなり異なる。これは、まずいだろ?
462
463 特に、PPE task に明示的に manager を渡すってのは、
464 とっても変。
465
466 Renew Task の特別扱いが、いろいろ歪めているんだが、
467 view.cc で使っているので落せない。
468
469 2009-10-05 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
470
471 TaskQueue のfree list の管理はシステムで一つであるべき。
472 TaskQueue は double linked list が当然らしい。
473
474 2009-10-02 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
475
476 DrawSpan で、~DrawSpan() で、allocate したデータを DMA_WAIT
477 して、free しているが、これは、抽象化違反。Task で明示的に
478 DMAするのは禁止。Task 内で、add_outData 出来れば良い。
479
480 renew が正しいような気がするが...
481
482 Task 内で大域変数は使えない。なので、smanager からallocateする
483 必要がある。Task の解放のタイミングではなくて、パイプラインの
484 タイミングでDMA waitとfreeを行なう必要がある。DrawSpan の場合は、
485 add_outData で良いが、内部で allocate/free は行なう必要がある。
486 put_segement がパイプライン動作するべきなのか?
487
488 固定のDMA tagが邪魔。
489
490 DrawSpan は全般的にダメだな〜
491
492 でも、その変更は大きいので、とりあえず動くようにしたい。
493
494 memset 0 は、7.7.3 SL1 Data Cache Range Set to Zero コマンド
495 つかうべき。SPE側でやっても良い。でも、本来は全面埋まるのが
496 普通なのでどうでも良いけど。
497
498 2009-08-06 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
499
500 で、MemList/MemHash が TaskManager 側に移ったので、
501 これで、code の management を書くことが出来る。
502 そうすれば、SPEのメモリの限界をほんと気にする必要がなくなるはず。
503
504 その前に、get_segment の例題を直さないと。
505
506 DrawSpanRnew/reboot は使ってないらしい。
507
508 Tree は、配列にしないでlinkをSPE側からたどるようになっている。
509 それは良いのだが、Task 側で dma_wait するような実装は望ましくない。
510 この部分も書き直す必要がある。list 構造の SPE上の Iterator を
511 実装すれば良い。
512
513 memory 関係のコードが scheduler の下にあるのは面白くない。
514
515 Scheduler で実装(__scheduler)に移譲している部分は、headerに
516 移した方が良い。
517
518 2009-08-06 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
519
520 うーん、get_segemnt で、dma_wait のtagをなんとかする
521 必要があるらしい。get_tag() でなんとかなるけど、
522 他のtag との関係があるかな。
523
524 完全に見えなくするべきでしょうけど... 今はいい。
525
526 2009-08-01 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
527
528 MemList は動いたので、今度は TileHash を TaskManager 側に移動する
529 必要がある。
530
531 その後、コードのLRUを書けば、Cerium は一通り出来上がり。
532
533 TaskManager と Scheduler の関係が一貫してない。複雑すぎる。
534
535
536 2009-07-24 Kaito TAGANO <tkaito@cr.ie.u-ryukyu.ac.jp>
537
538 長さ別の freeList と単一の HashTable で管理する
539 TileList を廃止
540 class MemorySegment {
541 MemorySegment *next;
542 MemorySegment *prev;
543 uint64 size;
544 uint64 address;
545 uint64 dummy;
546 // uint32 data[0];
547 }
548
549 class MemList {
550 MemorySegment* first;
551 MemorySegment* last;
552
553 MemList* createMemList(uint32 size, uint32 count);
554 void addFirst(MemorySegment* e);
555 void addLast(MemorySegment* e);
556 MemorySegment* getFirst();
557 MemorySegment* getLast();
558 boolean remove(MemorySegment* e);
559 void moveToFirst(MemorySegment* e); // or use();
560 }
561
562 サイズ毎に freelist と activelist を持って、これを malloc free
563 として使う。
564 これのテストルーチンを書き終わったら、Tapestry をこれで書き直す
565 LRU は使うたびに以下を呼び出す
566
567 void use(MemorySegment* e, MemList* active) {
568 active.remove(e);
569 active.addFirst(e);
570 }
571
572
573 2009-07-15 Yusuke KOBAYASHI <koba@cr.ie.u-ryukyu.ac.jp>
574
575 PPU からMainMemory にResource を Access する API
576 長さ別の freeList と単一の HashTable で管理する
577
578 読みだしAPI。set_rgb に相当。
579 uint32 segment_id = smanager->get_segment(memaddr addr, *MemList m)
580 id は hash値に相当。
581 addr で指定された PPU の Address が Hash にあるかどうか調べる。
582 無ければ dma_load する。そして指定された id を返す。
583
584 確保 API。set_rgb に相当。読み出さないで、hash entry だけ確保する。put しかしない部分用
585 uint32 segment_id = smanager->get_null_segment(memaddr addr, *MemList m)
586 id は hash値に相当。
587
588 書き出しAPI、読みだしていること前提。
589 smanager->put_segment(wait_id);
590
591 MemorySegment* smanager->wait_segment(uint32 segment_id)
592 id で指定された PPU の segment の copy の Address を返す。
593 必要があれば dma_wait を行う。書き出しも待ち合わせる。
594
595 2009-06-8 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
596
597 SchedTask/SchedTaskImpl の分離はあんまり意味がなかった。
598 SchedTaskBase が既にあるし。
599 とりあえず、__list とかは、private にしただけ。
600 ScheTaskImple を作っても、継承してprivateにすると、
601 warning は出るが、 User Task space の名前空間は結局汚れてしまう。
602
603 delegate するべきだと思うが、SchedTaskBase でないと、
604 動かないらしい。それだと、indirect が増えるので、ちょっといや。
605
606 2009-06-4 Shinji KONO <kono@ie.u-ryukyu.ac.jp>
607
608 set_symbol は、もういらないよね?
609
610 list dma 中心の実装にして、もっと細かく read/exec/write
611 した方が良いかも。
612
613 post で、PPE task を渡せると良い。address は parameterとして送る
614
615 2009-02-13 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
616
617 * kernel/ppe/Random.cc (reset): fix
618 urandom -> random とどれも読めなかったら
619 gettimeofday() での時間から seed を求めるように
620
621 2009-02-12 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
622
623 * add: kernel/ppe/Random.cc
624 乱数生成クラス。
625 ゲームだとユーザ使うでしょうきっと。
626 一応 /dev/random から seed 取る様にしてます
627
628 2009-02-04 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
629
630 * kernel/ppe/TaskManager.cc (TaskManager::allocate): rename
631 malloc -> allocate
632
633 * kernel/main.cc (main): fix
634 cerium_main を呼ぶのではなく、TMmain という名前にしました。
635 ちょっと SDLmain をパクった感じで。
636 まあ TaskManager の main で cerium_* って名前は微妙に変だからね。
637
638 * kernel/ppe/TaskManager.cc (TaskManager::set_TMend): add
639 cerium_main があるんだから、cerium_end があってもいいじゃない。
640 もっと言うと、TaskManager に main を隠すって流れなんだけど
641 終了を検知できないのはちとやりづらいかなと。
642 たとえば測定とか。Task の post_func とかでもやれないことはないけどね。
643 というわけで、ユーザが、プログラム終了時に呼ばれる関数を設定できるように。
644
645 2009-01-20 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
646
647 * Cell/spe/SchedTask.cc (SchedTask::get_cpuid): add
648 printf デバッグ時に、どの CPU かって知りたい時があるので。
649
650 PPE = 0
651 SPE = 0〜spu_num-1;
652
653 PPE は 0 以外に分かりやすい数字がいいんだけどなー。SPE と被るし。
654 -1 とかはエラーっぽいから好かない。まあいいんだけど。
655
656 User Task では以下の様に使用します
657
658 int cpuid = smanager->get_cpuid();
659
660
661 * Cell/SpeThreads.cc (SpeThreads::spe_thread_run): fix
662 SPE_EXIT が出る時は正常終了だけど、これだと
663 エラーでたようなメッセージに見えてしまう(俺がそう見えてしまった)ので
664 ここは表示しなくてもいいかな。
665
666 * kernel/ppe/MailManager.cc (MailManager::destroy): fix
667 無限ループになってた。この for() 間違ってるかな。
668 なんか TaskQueueInfo.cc とかでも、結局 while() に直してるし。
669
670 * kernel/ppe/TaskManager.cc (TaskManager::~TaskManager): add
671 kernel/main.ccで
672
673 delete manager;
674
675 としているのに、TaskManagerImpl::~TaskManagerImpl が呼び出されず
676 どうしてかなと思ったら、そもそも ~TaskManager が無かった。あほか
677
678 2009-01-05 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
679
680 * all : fix
681 Scheduler::curIndex_taskList を削除し、
682 SchedTask に持たせる様に変更。(SchedTask::__cur_index)
683 それに伴い、SchedTask::__init__() も cur_index を入れる様に変更
684
685 2008-12-24 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
686
687 * kernel/schedule/SchedTask.cc (SchedTask::ex_init_renew)
688 (SchedTask::ex_init_normal): add
689 (SchedTask::__init__): fix
690
691 init でも ex_init を使える様に。
692 あと、コンストラクタで渡していた引数を __init__() に渡す様にした。
693 コンストラクタの引数あると、継承する時にいちいち親クラスのも書かないと
694 いけなかった。これ省略できないんだよな。めんどくさい。
695
696 例.
697 class Hoge : public SchedTask {
698 Hoge(int i) : Task(i) {}
699 };
700
701 なので、今までは Scheduler.h に SchedConstructor ってマクロを書いて
702 クラス名入れるだけで上の様な形になるようにしていた。
703 でも、例えば
704
705 SchedTask -> Hoge -> Fuge っていうように Fuge ってタスクを
706 作りたいとき、上のままだと SchedTask に引数渡してしまうのでだめ。
707 もうめんどくさいってことで、コンストラクタ全てデフォルトにして、
708 __init__() の引数に渡す様にしました。
709
710 (SchedTask::__set_renewFlag): add
711
712 ここで、PPEで生成されたか(normal)、SPE で生成されたか(renew) の
713 判定を行い、ex_xxx の設定もする
714
715 (SchedTask::get_inputSize, SchedTask::get_outputSize): add
716
717 アドレスだけじゃなく、そのサイズも取れた方がいいだろう
718
719
720 2008-12-23 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
721
722 * Cell/spe/SchedTask.cc (SchedTask::get_outputAddr)
723 (SchedTask::get_inputAddr): add
724
725 in/out のデータだけじゃなく、そのアドレスも取れた方がいいだろう
726
727 2008-12-22 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
728
729 * Cell/spe/SchedTask.cc (SchedTask::__init__, SchedTask::read)
730 (SchedTask::exec, SchedTask::write): fix
731 (SchedTask::ex_read_normal, SchedTask::ex_read_renew)
732 (SchedTask::ex_exec_normal, SchedTask::ex_exec_renew)
733 (SchedTask::ex_write_normal, SchedTask::ex_write_renew): add
734
735 SPE 内で生成されたタスクは、PPE で生成されたものと違い
736
737 - add->inData
738 : PPE から DMA or SPE 内のものをそのまま使う
739 - PPE にタスクが終了したことを知らせる
740 : 生成されたタスクを待つ必要があるなら、その時点では送らない
741
742 とか、まあいろいろ処理が違うわけです。
743 そして、タスク内生成タスクの判断をする
744
745 __flag_renewTask ? 0 = PPE で生成 : 1 = SPE で生成
746
747 という変数がある。これでいくつか処理を分けてるんだけど、
748 今までは
749
750 if (__flag_renewTask) {
751 } else {
752 }
753
754 ってやってた。これではいかんという事で、
755 __init__() 内で、関数ポインタに、
756
757 ex_xxxx_normal: PPE で生成されたタスクに対する処理
758 ex_xxxx_renew: SPE で生成されたタスクに対する処理
759
760 と入れて、if 文無しでやってみた。
761 今は ex_write_xxx しか書いてないが、これからread/exec でも
762 出てくると思うので、作っておいた
763
764
765 2008-12-19 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
766
767 * Cell/spe/CellDmaManager.cc (CellDmaManager::dma_wait)
768 (CellDmaManager::mail_write, CellDmaManager::mail_read): fix
769 writech、readch の関数を、wrap (って言い方でおk?)された関数に変更。
770 最適化掛かってるっぽいし、長いよりはわかりやすいし。そのための wrap。
771
772 例:
773 - before
774 spu_readch(SPU_RdInMspu_readch(SPU_RdInMbox);
775 - after
776 spu_read_in_mbox(void);
777
778 2008-11-05 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
779
780 * add: Task 内での API
781 Task 外での API は、今まで通り manager->create_task とかですが
782 タスク内でも、「オブジェクト->関数」の呼び出しがいいんじゃないか
783 って話になったので、付け加えました。今のところ、SchedTask.h の
784 内部クラスとして
785
786 STaskManager
787
788 ってのを加えて、ユーザはそのインスタンスである
789
790 smanager
791
792 からAPIにアクセスします。
793 今までは __scheduler->dma_load とかいろいろやってたんですが
794 これからは全て smanager にしました。
795 というわけで、ここに使える API 一覧。いずれゲーム班 wikiの方にも。
796
797 - get_input, get_output, get_param
798 - create_task, wait_task
799 - global_alloc, global_get, global_free
800 - mainMem_alloc, mainMem_wait, mainMem_get
801 - dma_load, dma_store, dma_wait
802 - allocate
803
804 使い方は追々描きますが、
805 今のところ上に変更しなくてもそのままの記述で動くはずです。
806 いずれは全て移行してもらうことになりますがきっと。
807
808
809 * kernel/schedule/SchedTask.cc:
810 いろいろ関数が増えてますが、ラッパーです。
811
812 2008-11-01 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
813
814 * add: kernel/main.cc
815 main loop をユーザに書かせるのはめんどくさいので、
816 ライブラリ側で main() を書く事にしました。
817 ユーザ側では main() の代わりに cerium_main() を
818 書かせるようにしています。引数は main() のをそのまま渡す感じで。
819
820 Cerium 標準のオプションとして、-cpu は付けました。
821 ゲームフレームワークってことで、-width とか -height は
822 標準でつけてもいいかなって話なので、これは後日実装。
823 標準オプションで受け取った値にアクセスする方法も考えないと。
824 manager->cpu とか manager->width とかは安易か?
825
826 * add: Cell/PpeScheduler.cc
827 MainScheduler をそのまま使うと、
828 PPE のタスクで mainMem_alloc で確保した領域がアライメント
829 取れていないため、SPE で使うと余裕でバスエラー。
830
831 Scheduler->allocate で poxis_memalign で使えるように。
832
833 * move: kernel/schedule/FifoDmaManager.cc, MainScheduler.cc
834 kernel というよりは Fifo バージョン用なので Fifo/ に移動。
835
836
837 2008-10-21 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
838
839 * kernel/ppe/TaskManagerImpl.cc (TaskManagerImpl::systask_init): fix
840 下に述べてる SysTask_Finish を regist する部分
841
842 (TaskManagerImpl::spawn_task):
843
844 SysTask_Finish に対して、タスクが spawn されるたびに
845 wait_for を掛けて、待つようにしている。
846
847 * add: kernel/systask/
848 久々の更新乙
849
850 プログラム動かすとき、タスクが SPE だけで、
851 PPE で待ってるタスクが無いとそのままプログラムが素通りするってことで
852 今まではユーザに、全てのタスクを待たせるタスクってのを書かせてた。
853 まあもちろんめんどくさいので、いい加減追加した。
854
855 system task っつーことで、spawn された全てのタスクを待つ
856 SysTask_Finish を作った。これでいちいち task_finish とか作らなくておk
857
858 2008-08-10 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
859
860 * thinking: add_update() ?
861 現在、タスクは input/output があるわけですよ。
862 で、例えば
863
864 - 入力データ : PolygoPpack
865 - 出力データ : SpanPack
866
867 ってなわけですが、別のタスクで
868
869 - 入力データ : SceneGraphPack (更新前)
870 - 出力データ : SceneGraphPack (更新後)
871
872 ってのがある。つまり Update なわけだ。
873 今のところ、同じアドレスを add_inData, add_outData に設定して
874 タスク内で memcpy(wbuf, rbuf, sizeof(SceneGraphPack) とかしてる。
875 まあそれはそれでいいのかわるいのか。
876
877 in/out だけじゃなくて update も必要?
878
879 2008-08-08 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
880
881 * add: ../include/TaskManager/base.h
882 通常の new/delete では、RTTI とか 例外処理とかで
883 -fno-exceptions や -fno-rtti をコンパイルオプションにしても
884 効かなかったんだけど、operator new/delete をオーバーライドして
885 中身を普通の malloc/free にすると、上の処理が無くなるので
886 オプションが効くようになる。結果コードサイズも減ると。
887 SPE の場合、70〜80KBは減りました。使わない手は無い。
888 つーことで、一応動いてる。。。といいたけど動いてないorz
889 最適化 (-O2 とか -O9) をかけると止まる。SPE 上でね。
890 FIFO バージョンだと問題ない。SPEだとだめだ。
891 今わかってる、止まる場所は Scheduler::run() 内の
892
893 task3->write();
894
895 だ。task1~3までのnewは(多分)できているんだけど
896 そこを呼び出すと SPE 自体が終了してしまう。謎だ
897
898 一応、俺作の new/delete は base.h に定義してあって、
899 通常の API との切り替えは、base.h にある
900 BASE_NEW_DELETE を切り替えるだけでおk。
901 全てのファイルではなく、現在は SPE で使いそうなところだけやってます。
902 いずれは全部やったほうがいいかな〜
903
904 ライブラリ側の最適化はアウトだけど、ユーザ側では問題ないです。
905 なので、今は
906
907 ライブラリ側(libspemanager.a)は最適化無し(-O0)
908 ユーザ側(SchedTaskを継承したやつね)は最適化しても無問題 (-O9)
909
910 でっす。ここらへん完璧なれば、だいぶ楽になる。
911 つーかもう C++ やめ(ry
912
913
914 2008-08-07 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
915
916 * change: mainMem_set -> mainMem_wait
917 allocate を待つんだから、なんとなく wait かな。
918 あと、ユーザも使えるので、wait の方がわかりやすいと思ったり。
919
920 2008-08-05 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
921
922 * add: mainMem_alloc, mainMem_set, mainMem_get
923 SPE から メインメモリの領域に対して allocate できないと
924 SceneGraphの生成やら、結構クリティカルな処理を
925 全部 PPE でやらないといけなくなるってことで実装しました。
926
927 流れとして
928
929 1 タスク中に、mainMem(id,size) を実行する事で、
930 メインメモリに対して allocate のコマンドを発行。
931
932 1.1 Scheduler から PPE に対して
933 - commmand (MY_SPE_COMMAND_MALLOC)
934 - id (PPEから戻ってくるコマンドに必要)
935 - size
936 を mailbox で送る
937
938 1.2 確保した領域はそのタスク内では取得できない(NULL が来ます)
939 正確には、返事の mail をここでは read してないから
940
941 2. PPE では、受信した mail が MY_SPE_COMMAND_MALLOC だったら
942 次に来る mail が id と size であるとして read を行い、
943 size を元に allocate する。allocate が完了したら
944 - id
945 - allocate された領域のアドレス
946 を SPE に mail で送る
947
948 3. SPE Scheduler では、SchedTaskList::read で、
949 一つ前の TaskList 中で実行された mainMem_alloc の数だけ
950 PPE からのメールを待つ。mainMem_set() の処理です。
951
952 4. create_task されたタスク内で mainMem_get(id) とすると
953 allocate したメインメモリ領域のアドレスが得られる。
954
955 こんな感じ。結構ださい実装なので、もうちょいスマートにいきたいよね。
956 例題は Game_project/student/master/gongo/MainMemMalloc にあります。
957 README にもおんなじこと書いてます。
958
959 * memo: The number of available entries of Inbound/Outbound Mailbox
960 Outbound (SPE -> PPE) のmailboxデータキュー保持数は
961
962 /* SPE プログラム中 */
963 #include <spu_mfcio.h>
964 spu_stat_out_mbox(void);
965
966 で調べる事が出来る。
967
968 --- 記述例 ---
969 printf("Available capacity of SPU Outbound Mailbox\n");
970 printf(" %d\n", spu_stat_out_mbox());
971
972 --- 実行結果 --
973 Available capacity of SPU Outbound Mailbox
974 1
975
976 Inbound (PPE -> SPE) の mailbox データキュー保持数は
977
978 /* PPE プログラム中 */
979 #include <libspe2.h>
980 spe_in_mbox_status(spe_context_ptr_t);
981
982 で調べられます。
983
984 --- 記述例 ---
985 printf("the number of available entries = %d\n",
986 spe_in_mbox_status(spe_ctx));
987
988 --- 実行結果 ---
989 the number of available entries = 4
990
991 Outbound が少ないなー。
992 In/Out 共に、キューが MAX の場合、減るまで wait 掛かるんだよな。
993 それがどこまで影響あるかは実際にやらないと、ってことか。
994
995 * fix: ファイル名の変更 (*.cpp -> *.cc)
996 前々から先生に直せ言われてたので。
997
998 cvs のファイル名を変える方法は簡単に二つ(てかこれだけ?)
999
1000 1. cvs rm hoge.cpp; cvs add hoge.cc
1001 2. リポジトリを直接変更 mv hoge.cpp,v hoge.cc,v
1002
1003 めんどくさかったので 2 でやりました。
1004 Attic (削除されたファイルがあるリポジトリディレクトリ?)にも
1005 同じ処理を行えば、tag で update かけてもちゃんと反映されました。
1006
1007 2008-07-22 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1008
1009 * tag: open-campus-2008
1010 次やる事は、Cell/spe 以下のコードサイズを減らすために
1011 new/delete を消して malloc/free で統一する事。
1012 placement_new ってのを使えば、コンストラクタは呼べて
1013 new ほどサイズ圧迫しないからこれにしようかな。
1014 逆の placement_delete ってのは自分で小細工しないと行けないらしい。
1015 まあ、これが旨く行けば 80KB ほど減るから。やるべきだろう。
1016
1017 * Cell/spe/Scheduler.cpp (Scheduler::dma_load): アホなミスその2
1018 自分で __scheduler->dma_store をやってもデータが送れない。
1019 そんな馬鹿な。つーことでいろいろ調べてもわからない。
1020 アドレスやサイズが違うのかと調べても違う。
1021 こうなったらっつーことでライブラリに printf 加えてみたら表示されない
1022 あれ、おかしいな。たしかに Connector::dma_store に加えたはz・・
1023
1024 Scheduler::dma_store(void *buf, uint32 addr, uint32 size, uint32 mask)
1025 {
1026 <<<
1027 connector->dma_load(buf, addr, size, mask);
1028 ========
1029 connector->dma_store(buf, addr, size, mask);
1030 >>>
1031 }
1032
1033 なぜ store から load を呼んでるのか不思議だった。
1034 Scheduler::dma_load をコピペして dma_store にした後、
1035 中の connector->dma_load を変えなかったってオチだな。
1036 下のミスと合わせて5,6時間費やしたよHAHAHA
1037
1038 * Cell/spe/SchedTask.cpp (SchedTask::exec): アホなミスその1
1039 Test/test_render で、
1040 SpanPack のデータが時々壊れてる感じがする。
1041 送る前までは正常だから生成に問題は無いはず。
1042 つーことでいろいろ調べたがわからず。
1043 printf デバッグすると動く不思議
1044 なんだ、printf で遅くなったらできるってことは
1045 DMA が完了する前に SchedTask::run にきてんのか?
1046 いやいや、そんなばかな。だってちゃんと wait し・・・
1047
1048 <<<
1049 ============
1050 __scheduler->dma_wait(DMA_READ);
1051 >>>
1052
1053 はいはい wait し忘れ wait し忘れ
1054
1055 2008-07-16 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1056
1057 * memo: if 文消した成果2 & memcpy するかしないかか
1058 Renew Task では、inListData,outListData は新たに allocate して
1059 使っているので、SchedTask にそって実行する場合、
1060
1061 __scheduler->dma_load(__inListData, (uint32)__task->inData,
1062 sizeof(ListData), DMA_READ_IN_LIST);
1063 __scheduler->dma_load(__outListData, (uint32)__task->outData,
1064 sizeof(ListData), DMA_READ_OUT_LIST);
1065
1066 の代わりに
1067
1068 memcpy(__inListData, __task->inData, sizeof(ListData));
1069 memcpy(__outListData, __task->outData, sizeof(ListData));
1070 free(__task->inData);
1071 free(__task->outData);
1072
1073 もしくは
1074
1075 __inListData = __task->inData;
1076 __outListData = __task->outData;
1077 (__task->inData と __task->outData は Destructor で free する)
1078
1079 とやっています。
1080 memcpy が重いのはわかるんですが、下の方法では
1081 Destructor で if 文使って free() しているわけです(このタスクが Renew か否か)。
1082 ですので、どっちが早いか試してみた。
1083
1084 /**
1085 * memcpy() して、すぐ free() する version
1086 */
1087 void
1088 test_cpy(int flag, int *src)
1089 {
1090 if (flag) {
1091 memcpy(data, src, sizeof(int)*length);
1092 free(src);
1093 }
1094 }
1095
1096 /**
1097 * 参照で扱って、最後に free() する version
1098 */
1099 void
1100 test_nocpy(int flag, int *src)
1101 {
1102 if (flag) {
1103 data = src;
1104 }
1105
1106 // この部分を SchedTask::~SchedTask() と
1107 // 思ってください
1108 if (flag) {
1109 free(data);
1110 }
1111 }
1112
1113
1114 これらの関数を10000回ループしました。
1115 src の allocate は関数の外でやっており、その部分は実行時間に含まれてません
1116 flag は 1 or 0 の繰り返しです。
1117
1118 - 実行結果 (1)
1119 :no copy
1120 SPE time by SPU Decrementer: 0.035500
1121 :copy
1122 SPE time by SPU Decrementer: 0.057500
1123
1124 memcpy しないほうが速いらしいです。
1125 ためしに、flag を ずっと 1 にしてみました。
1126
1127 - 実行結果 (2)
1128 :no copy
1129 SPE time by SPU Decrementer: 0.055250
1130 :copy
1131 SPE time by SPU Decrementer: 0.053389
1132
1133 今度は copy するほうが早いという不思議。
1134 でもまあ、ずっと 1 ってことはないと思いますし、
1135 むしろ flag == 1 になるほうが少ないと思うので、
1136 no_copy version でやったほうがいいかな。
1137
1138 おまけで、実行結果 (1) の環境で、test_nocpy を変えてみた
1139
1140 void
1141 test_nocpy(int flag, int *src)
1142 {
1143 if (flag) {
1144 data = src;
1145 }
1146
1147 free((void*)(flag*(int)data));
1148 }
1149
1150 キャストしまくりですが、単純に free(flag*data) だと
1151 「invalid operands of types 'int' and 'int*' to binary 'operator*'」って
1152 出るので、キャストで逃げました。
1153 で、実行結果なんですが
1154
1155 - 実行結果 (3)
1156 :no copy
1157 SPE time by SPU Decrementer: 0.040375
1158 :copy
1159 SPE time by SPU Decrementer: 0.059500
1160
1161 遅くなってーら。キャストが悪いのか。乗算が重いのか。
1162 branch が無い? spe の if 文と対決しても遅いのかー。
1163 例題が間違ってる可能性もあるが・・・ if 文は使っていくかなー
1164
1165
1166 2008-07-10 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1167
1168 * fix: TaskGroup->group
1169 今まで slist っていう、ライブラリの単方向リスト構造体?を
1170 使ってたんだけど、まあいろいろあって、TaskQueue を使うようにしました。
1171 最初からこれにするつもりではあったけどね。
1172 RenewTask や static_alloc とかの実装を優先したので
1173 ライブラリを使いました。といっても、書いてみると
1174 それほと記述量無いので最初から行っても良かったかなーと思ったり。
1175
1176 そんなわけで動いてます。つーか、やめてよかったよ slist。
1177 slist を使ったやつと使ってない奴のファイルサイズがやばい
1178
1179 -rwxr-xr-x 1 gongo gongo 120672 2008-07-10 14:29 spe-main*
1180 -rwxr-xr-x 1 gongo gongo 180368 2008-07-10 13:40 spe-main.bak*
1181
1182 .bak が slist を使ってる、上のやつが使ってないversionです。
1183 まさか 60k も違ってくるとは思わなかった。
1184 SPE LS の容量が 256k と考えると、かなりの痛手だったよ。アブねえ。
1185 インラインとか最適化掛けまくってて、コード量が増えてるからかなー。
1186
1187 「SPU C/C++ 言語拡張」とかで、C++ のライブラリがSPUでも使えるよ〜
1188 って書いてたから入れてみたんだけど。罠だったか。
1189 おそらく SPU に移植した側の人も「サイズが増えるのを覚悟で使え」って
1190 ことだったんだろう。なかったら文句言う人も居そうだし。
1191
1192 2008-07-09 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1193
1194 * fix: TaskGroup での task の扱い
1195 下にもかいているけど (直したいところ (1))
1196 TaskGroup->group が持つ要素は int で持ってて、
1197 それらは、同じく TaskGroup が持つ cur_id をインクリメントしていって、
1198 それを要素としていました。つまり、TaskGroup->group は、厳密にいえば
1199 「どの Task があるか」ではなく、「いくつのタスクがあるか」を
1200 あらわしているだけでした。slist を使う意味もなかったわけです。
1201
1202 そこで、SchedTask が持つ、RenewTaskList の解放のタイミングを
1203 RenewTaskList の一番最後のタスクが delete されるときにしました。
1204 これによって、アドレスが被ることがなくなったので
1205 TaskGroup->group の要素を TaskPtr にできました。
1206 この方が、TaskGroup の意味的にもしっくりくるのでよかばってん。
1207
1208 * memo: if 文消した成果
1209
1210 #ifdef FREE_TEST
1211 free((ListDataPtr)(__flag_renewTask*(int)(__inListData)));
1212 free((ListDataPtr)(__flag_renewTask*(int)(__outListData)));
1213 free((TaskListPtr)(__flag_renewTask*(int)(__list)));
1214 #else
1215 if (__flag_renewTask) {
1216 free(__inListData);
1217 free(__outListData);
1218 free(__list);
1219 }
1220 #endif
1221
1222 こんな感じで、いくつかか if 文を消してみた。
1223 そして、PPE側の main.cc で gettimeofday で計測してみた (各10回)
1224
1225
1226 - if 文消した場合
1227 time: 1.222000
1228 time: 1.230000
1229 time: 1.241000
1230 time: 1.230000
1231 time: 1.223000
1232 time: 1.257000
1233 time: 1.219000
1234 time: 1.228000
1235 time: 1.220000
1236 time: 1.229000
1237 avarage: 1.2299
1238
1239 - if 文消してない場合
1240 time: 1.225000
1241 time: 1.215000
1242 time: 1.229000
1243 time: 1.218000
1244 time: 1.223000
1245 time: 1.214000
1246 time: 1.225000
1247 time: 1.215000
1248 time: 1.224000
1249 time: 1.219000
1250 avarage: 1.2207
1251
1252 あまり変わらな(ryむしr(ry
1253 使い方がまずいのか、もっとと回数を増やせば変わってくるのかね。。。
1254 PPE でなく、 SPE のほうで計測すべきなのかなーとか思ったり思わなかったり。
1255
1256
1257 2008-07-08 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1258
1259 * add: Renew Task の wait
1260 Renew Task は今まで「生成されたやつ全部待つ」だったのを
1261
1262 void SchedTask::wait_task(TaskPtr task);
1263
1264 ってのを作って、任意のタスクに wait 掛けれるようにしました。
1265 名前が思いつかなかったお。。。
1266 動作確認済み・・・だと思います。例題・・・誰か例題を!(俺が
1267
1268
1269 * fix: SchedTask の変数名
1270 ユーザが継承して使う SchedTask クラスなんですが、
1271 今まで変数は list, task などを使ってました。
1272 が、これは一般に使われやすい変数名です。
1273 その証拠に、俺も例題書いている時に task って名前が被ってました。
1274
1275 run(r, w)
1276 {
1277 ...
1278
1279 //TaskPtr task; <= 宣言してないのにエラーにならない
1280 task = create_task(TASK_EXEC);
1281 }
1282
1283 ってコードを書いてたせいで、Scheduler が使用する task を
1284 上書きしたせいでバグってました。ってことがありました。
1285 上のように、宣言してないのに普通に通ってるのを気づきませんでした。
1286 今のところ変数名は __task とか __list にしてあります。
1287 private にしてもいいんだけどさ。
1288
1289
1290 2008-07-07 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1291
1292 * fix: if 文を無くしてみた
1293 下の方に 「if () が多い」って書きましたが、いろいろ小細工を。
1294 SchedTask をやってみました。例えば
1295
1296 if (cmd != 0) {
1297 delete taskGroup;
1298 scheduler->mail_write(cmd);
1299 }
1300
1301 ってのがありました。cmd ってのは taskGroup->status で
1302 もし cmd が 0 でなければ、taskGroup はすでに空っぽで
1303 待つべきタスクはすべて終了したので、taskGroup を delete し、
1304 mailbox で cmd を PPE に送ります(cmd にはすでに送るべきコマンドがある)
1305 でまあ、これくらいなら
1306
1307 delete (int*)((cmd != 0)*(int)(taskGroup));
1308 scheduler->mail_write(cmd);
1309
1310 ぐらいに直せました。
1311 delete や free では NULL を渡しても何もしない(?)って動作なので
1312 これでも問題ない。つまり、cmd == 0 なら、taskGroup を
1313 解放する必要は無いので NULL が delete に渡されるわけです
1314 int* でキャストしてるのは、そのまま 0 を渡すと、
1315 「int型を delete するのはできない」的なエラーがでるからです。
1316 。。。だったら int* じゃなくて TaskGroupPtr じゃね?とか思った今。
1317
1318 あと、PPE 側で 「mail == 0 なら NOP」 的な処理を入れました。
1319 これによって、cmd が 0 かその他で if を書く必要がなくなりました。
1320 問題があるとすれば、 SPE -> PPE の mailbox の queue の長さ。
1321 NOP コマンドを送って、queue の制限に引っかかって
1322 mail_write が止まるんじゃないかなーとか少し心配です。
1323 ここらへんは optimize の時間に考える事かな。
1324 どうせ PPE では mail しか読んでないし、
1325 そこまで queue が埋まる事は無いと思いたい。
1326
1327
1328
1329 あとはこんな感じかな
1330
1331 #if 1 // fix
1332 free((void*)(flag_renewTask*(int)(list)));
1333 #else
1334 if (flag_renewTask) {
1335 free(list);
1336 }
1337 #endif
1338
1339 動いてるのは確認したし、gdb で x/20i とかしたら
1340 branch 命令が減ってるのは確認した。
1341 まあ -O9 とかで最適化掛けるとどっちも同じになるけどな。
1342
1343
1344 * add (API): static_alloc, static_get, static_free
1345 SchedTask 自身だけが持つ領域ではなく、
1346 SPE 上に複数のタスクが共有したい領域を作る
1347 これは task::run() 内で使用する。
1348
1349 - void* static_alloc(int id, int size);
1350 @param [id] 領域ID。現在は 0〜31 まで使用可能 (Scheduler.h で定義)
1351 @param [size] 領域のサイズ
1352 @return allocate した領域のポインタ。下の static_get の返り値と同じ
1353
1354 - void* static_get(int id);
1355 @param [id] static_alloc で作った領域 ID。
1356 @return 領域のポインタ
1357
1358 - void static_free(int id);
1359 @param [id] 解放したい領域の ID
1360
1361 こんな感じかなー。
1362 static_free はさすがにユーザに任せるだろう。
1363 static_free し忘れると SPE には致命的なので、ここはよく伝える必要有
1364
1365 例題は
1366 cvs: firefly:Game_project/student/master/gongo/Static
1367
1368 まあ Renew と大体同じですけどね。
1369 int 型配列 data を共有にして、各タスクでインクリメントしてる
1370
1371 * TODO: TaskGroup の扱い
1372 通常の Task では、task->self には
1373 自分が終了した時に PPE に送るコマンド(自分自身)になりますが、
1374 タスク中に生成されたタスク(もう何度も書くのめんどいんで Renew で)では
1375 task->self は、task を待っている TaskGroup を表します。
1376
1377 self という名前で意味が違うのでこういうことはやめたいんだが。。。
1378 といいながらやめないのが(ry
1379
1380 * memo:
1381 下の 直したいところ (1) ってやつがよくわからんので、
1382 現在の状況だけ
1383
1384 scheduler->add_groupTask() をするたびに
1385
1386 group.insert_front(cur_id++);
1387
1388 されます。
1389 そして、scheduler->remove_groupTask() されると
1390
1391 group.remove(--cur_id);
1392
1393 されます。要するに、どのタスクでも
1394 cur_id だけが insert/remove されます。
1395 「どのタスクがあるか」ではなく「どれだけのタスクがあるか」ですね。
1396 実際にはしっかりと TaskPtr で管理したかったんですが、
1397 下にも書いたアドレスが被る云々の問題でそれもできず。
1398 やり方はあると思うんですが。
1399
1400 うーん、うまく説明できないな。
1401
1402 * tag: v20080707
1403 タスク内タスク生成を作りました。
1404
1405 [TODO]
1406 SPE 上で領域を共有する API の
1407
1408 - static_alloc
1409 - static_get
1410 - static_free
1411
1412 を速攻で実装しよう。。
1413
1414 * add: タスク内タスク生成
1415 一応できたんですが、直したい。。。
1416 仕様としては
1417
1418 - 現在のタスク(T1) の中でタスクを生成したとする (Tc = T2, T3, ...)
1419 - 本来、T1 が終了次第、T1 が終わった事を PPE に伝えるが、
1420 ここでは、Tc が全て終わってから、T1 の終了を PPE に伝える
1421 - Tc 内で再びタスクが生成されても(Tcc)、Tcc が終わってから T1 を(ry
1422
1423 現在は、生成したタスクすべてに対して wait_for をかけてる感じ。
1424 しかし、例えば Frame Buffer に書き込む時は待つ必要ない(はず)なので
1425 タスク毎に wait_for を選べるようにした方がいいだろう。
1426
1427 __ 例題
1428 cvs firefly:Game_project/student/master/gongo/Renew
1429
1430 にあります。
1431 もうちょいちゃんとした例題が欲しいところです。
1432
1433
1434 __ 直したいところ (1)
1435
1436 現在、Tc を管理する構造体として、TaskGroup を使ってます
1437
1438 class TaskGroup {
1439 unsigned int command; // T1 が PPE に送るコマンド
1440 __gnu_cxx::slist<int> group; // Tc がある Linked List
1441
1442 // function は省略
1443 };
1444
1445 slist じゃなくて、TaskQueue みたいに自分で作っても良かったんだけど。
1446 group.empty() == true になったら、command を PPE に送るって感じです。
1447
1448 で、slist が持つデータが TaskPtr じゃなくて int の理由。
1449 まあいろいろあるんだけど(何)、アドレスが重複してしまうことです。
1450 最初は、create_task で得られた TaskPtr をキーとして使うつもりだったけど
1451 その TaskPtr は TaskList から取った物で (&list->takss[index] みたいな)
1452 なんでそれじゃだめなのか。buff_taskList[2] (Scheduler.cpp 参照) を
1453 使うと、交互に使用するのでアドレスは被る。
1454 新たに allocate すれば問題は無いが (t1とする)、SPE の LS の問題で
1455 使わなくなった TaskList は free していかないといけない。
1456 で、free -> 再び allocate したとき (t2とする)、t1 と t2 の
1457 アドレスが被ることがあった。当然 TaskPtr も被ると。
1458 だから、アドレスではなく、TaskGorup が持つ
1459 unsigned int cur_id を使う事にしました。
1460
1461 なんかここまで自分で書いてて、
1462 なんで出来ないのかまだわからんくなってきた。
1463
1464 ので試しに戻してみたら * で * き * ま * し * た *
1465 わけわからん。まあ勘違いだったのか、いろいろ別のところを直してるうちに
1466 知らず知らずミスってたところも治ってたのか。まあいいか。
1467
1468 と思っていろいろ試したらまた動かなくなった。。もうだめぽ
1469 とりあえず、また unsigned int に戻しました。
1470 今のところ、0 <= cur_id <= 0xffff (65535) の範囲のキーを使うように。
1471
1472
1473 __ 直したいところ (2)
1474 if 文が多い。
1475 今は、「通常の Task」「タスク内で生成されたタスク」で挙動が違います。
1476 例えば
1477
1478 - SPE で allocate されたデータを使うので、通常 DMA を使うところは
1479 アドレス参照や memcpy を使う
1480 - TaskGroup を、上記の Tc や Tcc へ引き継がせるところ
1481
1482 なので、flag_renewTask とかいう変数で、ほぼ if 文 で書いてます。
1483 SPE でこの書き方はかなりまずい気がします。良い書き方はないものか。。。
1484 「通常の(ry」「タスク内(ry」で新たにインスタンスを作るってのも
1485 考えはしましたが (SchedTask = 通常、SchedRenewTask = タスク内(ry とか)
1486 これだと ユーザー側も この二つを選んでやることになります。
1487 「このタスクは SchedRenewTask 、このタスクは通常」とかやるのは
1488 かなりめんどくさいと思う。だからライブラリ側で分けるべきか。。。
1489 多重継承とかってこんなとき役に立つん?
1490
1491
1492 2008-07-03 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1493
1494 * TODO:
1495 - add_param で渡せるパラメータの数を増やす。15もあればいいんじゃね?
1496 - 今の実装では、
1497
1498 1. PPE でタスク(T1)が生成される
1499 2. SPE で T1 が実行される
1500 3. T1 が終わった事を PPE に mailbox で送る
1501 送る情報は T1 自身。(PPE で生成された時のアドレス)
1502
1503 なわけです。しかし、もし T1 から新たにタスクが生成された時はどうするか
1504 仮に T1 から T2, T3, T4 が作られたとする。
1505 このとき、
1506
1507 1. T1 が終わった時点で、T1 から終了コマンドを送る
1508 2. T1 だけでなく、T1 内で作られた T2, T3, T4 が終わってから
1509 終了コマンドを送る
1510
1511 の二つが考えられる。
1512 PPE 側では T1 しか認識していないため、この判定は SPE 内でやることになる
1513 必要な処理かと言われると微妙だが、欲しくなるのは間違いない。
1514 つーことで今これを実装中です。
1515
1516
1517 * tag: v20080703
1518 - タスクに 32 bits パラメータを渡す add_param を実装(現在は3個まで)
1519 - SPE 内部でタスク生成ができるようになった
1520
1521 * add (API): SPE内部での create_task
1522 今まで、SPE ではタスクを生成する事は出来ず、
1523 PPE から送られてくるタスクを実行するだけでした。
1524 それだと不便だってことで SPE 内部でもできるようにしました。
1525 方法はPPEでやるのと同じく
1526
1527 task = create_task(TASK_EXEC);
1528 task->add_inData(buff, sizeof(Buff));
1529 task->add_param(data);
1530
1531 みたいな感じでいいです。
1532 spawn() や wait_for() は実装していません。
1533 SPE 内部で生成するタスク同士で依存関係作るのが
1534 結構めんどくさいからです。spawn() も、しなくても勝手に実行します。
1535 PPE とそろえる意味で作ってもいいんだけどね。
1536 そのためには SPE にも TaskManager が必要になってくるなー。
1537
1538
1539 2008-06-24 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1540
1541 * add (API): add_param, get_param
1542 DMA で送れないけど、必要になってくる 4 バイトの情報があるとして
1543 それは今までは
1544
1545 add_inData(param, 0);
1546
1547 とかして、「サイズ == 0 なら 32 bit のデータ」としていたけど
1548 それは余りにも変なので(関数の意味的にもおかしい)ので、
1549
1550 add_param(parameter);
1551
1552 ってのを追加しました。タスク側では
1553
1554 get_param(index);
1555
1556 とかします。index は、add_param を呼び出した順番で決まります
1557
1558 add_param(x);
1559 add_param(y);
1560 add_param(z);
1561
1562 とあるとき、タスク側では
1563
1564 int x = get_param(0);
1565 int z = get_param(2);
1566
1567 とします。
1568 今のところ parameter は 3つしか送れないことになってますが
1569 後ほど、上限をあげます。15くらいあれば余裕だと思うんだがどうだい?
1570 今は、SPE でのタスクの生成のルーチンを書くために、最低限な部分だけ
1571 ってことで 3 つにしてます。それが出来次第、これもやります。
1572
1573
1574 2008-06-12 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1575
1576 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::set_runTaskList):
1577 アホなミス(ry
1578
1579 「list が持つ TASK_MAX_SIZE を超えると、次の list へ next を」っていう
1580 前回直したところがまたミスっててだな。
1581 簡単に言うと
1582
1583 TaskPtr task = &list[list->length++];
1584 [task の初期化]
1585
1586 if (list->length > TASK_MAX_SIZE) {
1587 [newList 生成]
1588 newList = append(newList, topList[speid]);
1589 topList[speid] = newList;
1590 }
1591
1592 ってやってたわけ。これだと、toplist[speid] に
1593 length = 0 の list が来る可能性があると。
1594 で、spe に TaskList を送る条件は
1595
1596 1. taskList[speid]->length >= 1
1597 2. speid が次の TaskList を待っている状態
1598
1599 で、1 の条件に触れてしまい、TaskList が送られなくなって
1600 プログラムが終了しないと。アホですね〜
1601 上の if 文を &list[list->length++]; の前に持って行くだけでおk。
1602
1603 2008-06-10 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1604
1605 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::set_runTaskList):
1606 アホなミスしてました。
1607 list が持つ TASK_MAX_SIZE を超えると、次の list へ
1608 next を繋げるはずなんだけど、speTaskList_bg[speid] とか読む時に
1609 ちゃんと繋げられてなかったというかなんというか。
1610 簡単に言うと、タスク多くなると落ち(ry
1611
1612 * add (API): set_post
1613
1614 create_task(id, 0);
1615
1616 とかわざわざ 0 付けるのもアレなので、もうそれように
1617
1618 task->set_post(func)
1619
1620 を追加しました。func は void (*func)(void) です。
1621 せっかくだから、引数に void* とか付けてもいいんじゃないかと。
1622
1623
1624 * fix (API): ListDMA API
1625 タスク側で、ListDMA で指定したデータの取り方
1626
1627 run(rbuf, wbuf) として
1628
1629 // index は add_inData や add_outData で指定した(順番-1)
1630 get_input(rbuf, index);
1631 get_input(wbuf, index);
1632
1633 返り値は void* なので、malloc っぽくキャストしてください。
1634 あと、4バイト以下のデータを送りたい場合、main で
1635
1636 add_inData(data, 0)
1637
1638 と、アドレスは送りたいデータを則値で、サイズは 0 で指定するとおk。
1639 get_input で int なりなんなりでキャストすればいいじゃない!
1640 例題は
1641
1642 Game_project/student/master/gongo/arr_cal
1643
1644 で複数データ扱ってたり4バイト送ってたりしてます。
1645
1646
1647 * tag: v20080610
1648 前回との違いは
1649
1650 - ListDMA の導入
1651 - 凡ミスfix
1652
1653 とかかな。何気にここには ListDMA の API 書いてなかったな。
1654
1655 - task->add_inData(addr, size); // input
1656 - task->add_outData(addr, size); // output
1657
1658 これで Input/Output のデータ領域を指定可能。複数できます。
1659 詳しくはいずれドキュメントに書く予定だが、
1660
1661 - addr は 16 バイトアライメントに取れてないと行けない
1662 - size は 16 バイト倍数
1663
1664 ってのが最低条件。
1665 16 バイト未満のデータを送りたいとき(整数を2,3個とか)は考え中。
1666 addr に直接渡すって手法はできるとわかってるので、それでもいいかな。
1667 まあいろいろ問題はありますが、少しはできたんじゃないかな。
1668
1669 次からは SPE 内でのタスク生成(再起動?)を書く予定
1670
1671 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::set_runTaskList):
1672 if (speid > machineNum) {
1673 speid %= MAX_USE_SPE_NUM;
1674 }
1675
1676 から
1677
1678 if (speid >= machineNum) {
1679 speid %= machineNum;
1680 }
1681
1682 に。なんという凡ミス
1683
1684 * Cell/spe/CellDmaManager.cpp (CellDmaManager::dma_loadList): fix
1685 ListData が持つ ListElement は
1686
1687 class ListElement {
1688 public:
1689 int size;
1690 unsigned int addr;
1691 };
1692
1693 というデータ構造なわけだが、これは、spu_mfcio.h が持っていて
1694 且つ List DMA で使用される
1695
1696 typedef struct mfc_list_element {
1697 uint64_t notify : 1; /** Stall-and-notify bit */
1698 uint64_t reserved : 16;
1699 uint64_t size : 15; /** Transfer size */
1700 uint64_t eal : 32; /** Lower word of effective address */
1701 } mfc_list_element_t;
1702
1703 と同じである。notify と reserved は 0 となる (ストールは今は
1704 考えていない)ので、結局は uint が 2 つの 8 バイト のデータ構造であれば
1705 そのまま mfc_getl とか mfc_putl に遅れるわけである。
1706 今までは mfc_list_element_t 構造体に for 文でいちいち代入してたが
1707 まあそれはなくなったっつーことで。dma_storeList もね。
1708
1709
1710 2008-05-30 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1711
1712 * change (API): TaskManager Memory Allocate
1713 manager->cerium_malloc(&buff, DEFAULT_ALIGNMENT, sizeof(Data))
1714
1715 から
1716
1717 buff = (Data*)manager->malloc(sizeof(Data));
1718
1719 に変更しました。
1720 alignment の指定は全て TaskManager に埋め込んであります。
1721 記述は TaskManager.h に書いてあります。
1722
1723 void* TaskManager::malloc(int size) {
1724 return m_impl->allocate(DEFAULT_ALIGNMENT, size);
1725 }
1726
1727 2008-05-29 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1728
1729 * thinking: List DMA (4)
1730 Cell 版でも動いたのを確認。今、Cell 版で List DMA が動く条件は
1731
1732 1. List の各要素の転送サイズが 16 バイト倍数でなければならない
1733 2. List の各要素の転送するデータのアドレスのアライメントを保証(16or128
1734
1735 2に関しては Cell の仕様なんでまあいいんだけど、
1736 1は、ドキュメント見る分には
1737
1738 - Cell Broadband Engine アーキテクチャ version 1.01 より
1739 - 7.5.3 get list
1740 > リスト・サイズ・パラメータは、このDMAコマンドの場合は
1741 > 8バイトの倍数でなければならず、また、リスト・アドレス・パラメータは、
1742 > ローカルストレージの8バイト境界にアラインされなければなりません。
1743
1744 って書いてるんだよな。int が 10 個の配列(40バイト) を送っても
1745 見事に弾かれたんだよな。おのれバスエラーめ!
1746 とりあえず、上の条件を満たせば行けました。
1747 送るデータのアロケートは
1748
1749 TaskManager::cerium_allocate(void **buff, int align, int size);
1750
1751 ってのを作りました。使い方は別項目で。だいたい posix_memalign 準拠。
1752
1753 動くのはいいんだけど、これだとユーザに全部任せる事になります。
1754 特に、配列をアロケートした後、その途中の部分をリストに入れたい時。
1755 その配列の要素のサイズが16倍数じゃないとそこでエラーがでると。
1756 それをユーザに全部任せるのは、まあいけないこともないけどさ。。。
1757
1758
1759 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::mail_check): fix
1760 CellTaskManager は FifoTaskManager のオブジェクトを
1761 ppeManager という変数で持っていて、作業を別々に行っているわけで。
1762 だけど両方のオブジェクトがもつ waitTaskQueue は同じじゃないと
1763 ならないので、最初は TaskQueuePtr * とかで渡して
1764 共有してたわけだけど、よくよく考えると、
1765
1766 - waitTaskQueue に task が append される時
1767 CellTaskManager->append_waitTask()
1768
1769 - waitTaskQueue から task が remove されるとき(依存満たした時とか)
1770 FifoTaskManagerImpl->mail_check() 及び
1771 CellTaskManagerImpl->mail_check() です。
1772
1773 つまり、waitTaskQueue が共有されるのは mail_check だけなので、
1774 CellTaskManagerImpl の mail_check で
1775
1776 ppeManager->mail_check(mail_list, &waitTaskQueue)
1777
1778 として、ここで waitTaskQueue を参照渡ししてます。
1779 ppeManager->mail_check で waitTaskQueue の整理が終わって
1780 戻ってくる事には waitTaskQueue が更新されていると。
1781
1782 なんか文章がおかしいですね。気になる人は俺に直でお願いします。
1783 要するに、ppe と spe のそれぞれの TaskManagerImpl で
1784 waitTaskQueue の共有が上手くいったというわけです。
1785
1786
1787 2008-05-24 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1788
1789 * thinking: List DMA (3)
1790 現在実装中。Fifo 版では動いている模様。
1791 問題は Cell だよなー。考えないと行けない事がいくつか
1792
1793 - Input/Output データはアライメントされている?
1794 アライメントされていなくても、こっちでアドレスずらして
1795 DMAしてずらして run() に渡して〜とかもできるんだけど
1796 かなりめんどくさい。それに、In ならともかく、
1797 Out は変な領域に書き込みそうなので無理そう。
1798 これはもうユーザが、送るデータはすべて
1799 Cerium_malloc 的なものを通したものだけ、っていう
1800 制約にした方がいいかもしれない。てかそうなんだっけ。
1801
1802 - 配列中のデータの指定
1803 上の項目と少し関連があるんだが、例えば
1804
1805 int data[100]; // アライメントは取れてるとする
1806
1807 ってのがあって、そのなかの data[0]〜data[49]、
1808 data[50] 〜 最後まで送りたいとする。
1809 最初のやつは &data[0] のアドレスは 16 bytes アライメントだけど、
1810 &data[50] では、sizeof(int)*50 = おそらく 200 ずれて
1811 16 bytes アライメントではなくなると。これだと DMA できない。
1812 ユーザがそこまで考えて、例えば data[32] から送る、とかでもいいけど。
1813 ライブラリ側で、少しは融通効くようにすべきかな。
1814 やるなら、アドレスずらして取って来て、ユーザが見るデータは
1815 そのずらした分戻してから見せるって感じ。変な説明だが。
1816
1817 うーん。今はとりあえず全てアライメント大丈夫な方向でやってみるか。
1818
1819
1820 2008-05-23 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1821
1822 * Cell/SpeThreads.cpp (SpeThreads::init): スレッドの生成
1823 今まで作られてたスレッドは
1824
1825 - spe_context_run を実行するだけのスレッド (spe_thread_run)
1826 - 上のスレッドを呼び出し、終了を待つスレッド (frontend_thread_run)
1827
1828 2番目に何の意味があるのかということだが、
1829 SPE 毎にスレッドを立ち上げておいて、
1830 それぞれのSPEからのメールは、その担当するスレッドが見る、
1831 って構想で作っていました。だけど、今は mailbox の扱いは
1832 Cell/CellTaskManagerImpl::mail_check で行っているため
1833 わざわざ2番目のスレッドを作る必要がなくなりました。
1834 つーことで、frontend_thread_run ではなく、
1835 最初から spe_thread_run を起動すればおkとなりました。
1836
1837 * Cell/SpeThreads.cpp (SpeThreads::get_mail): if 文排除
1838 今までは
1839
1840 if (spe_out_mbox_read(spe_ctx[speid], &ret, 1) < 0) {
1841 return ret;
1842 else
1843 return -1;
1844
1845 とやっていた。これは
1846
1847 - データを読めたらそれ(ret)を返す
1848 - データが無かったら -1 を返す
1849
1850 ってことだったんだが、よくよく考えると、spe_out_mbox_read() は
1851 データがなかった場合 ret の値を変えないので、最初に
1852
1853 unsigned int ret = (unsigned int)-1;
1854
1855 としておけば、最終的に if 文無しの
1856
1857 spe_out_mbox_read(spe_ctx[speid], &ret, 1);
1858 return ret;
1859
1860 だけで済むわけだ。
1861
1862 2008-05-22 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1863
1864 * thinking: List DMA (2)
1865 MFC List DMA read の場合は(少なくともPPEでcreate_taskする時は)
1866 read size が決まっているので無問題。
1867 しかし、MFC List DMA write の場合。同じタスクでも
1868 違うサイズを出力するということはありえるので問題。
1869 今までも、write の場合は task->run() の返す値が write size として
1870 使う事にしていた。List DMA write の場合は、おそらく
1871
1872 - task->run() 内で write 用の List DMA 構造体を作って Scheduler に
1873 渡して、task->write() でやってもらう
1874
1875 って感じ? でも(上の手法に限らず)、write のサイズが決まってないと
1876 write 用バッファを生成しておく事ができないので
1877 書き込めない or あらかじめ多めに取っておくってことが必要になる。
1878 後者は SPE には痛手(昔は強制16KB確保とかやってたな)なので微妙。
1879 前者は論外だろう。
1880
1881 うーん、どうすっかな。Single DMA write の頃からこれは問題であって。
1882 最悪、ユーザが「write のサイズが変動しないようなタスクにする」とか?
1883
1884 * thinking: List DMA
1885
1886 構想としては以下のような考え。
1887
1888 class Task {
1889 int cmd;
1890 DataListDMA *rlist;
1891 DataListDMA *wlist;
1892 };
1893
1894 class DataListDMA {
1895 int length; // リストの数
1896 unsigned int addr[128]; // アドレス
1897 int size[128]; // そのアドレスから取得するデータのサイズ
1898 };
1899
1900 128 という数字は、一つのタスクが持てるリストの合計サイズを
1901 1KB (= 1024B) にしようってことで 4*128+4*128 = 1024 としました。
1902 ListDMA を使う流れとしては
1903
1904 1. Scheduler から cmd にそった Task を生成する
1905 2. Task のコンストラクタ(もしくは Task を生成する implement 内 )で
1906 task->rlist, task->wlist を DMA read しておく (ここは通常のDMA)
1907 3. task->read() で MFC List DMA で List を読む
1908
1909 DataListDMA->length に関しては、Task の中に入れるのも有りかと思う。
1910 その場合は、2 の DMA read で、わざわざ 1KB 全部読む必要は無くなる。
1911
1912
1913 * tag: v20080522
1914 - PPE 側のタスクも SPE と同じく、クラスオブジェクトとして登録
1915 - PPE、SPE 側の TaskManagerImpl を整理。見やすくなったと思われ
1916
1917 こんなところかなー。
1918 テストプログラムは
1919
1920 Game_project/student/master/gongo/hello
1921
1922 にあります。DMA の例題まだだったぜHAHAHA
1923 ここからは List DMA の処理を入れて行きたいと思います。
1924
1925 現在の simple_render のバージョンは
1926 PPE のタスクが関数ベースだった頃のなのでそのままでは動きません。
1927 List DMA ができるか、気晴らしに描き直すと思います。
1928
1929 * Task 定義について
1930 PPE も C++ のクラスオブジェクトとしてタスクを定義するようにしました。
1931 ちゃんとした API を考えたら改めて書きます。
1932
1933 * メールチェックから次のタスクリスト生成までの流れの変更
1934 今までの FifoTaskManagerImpl の mail_check では
1935
1936 1. mail_check
1937 1.1 check_task_finish
1938 1.1.1 notify_wait_taskQueue
1939 1.1.1.1 append_activeTask (依存満たしたタスクを)
1940 1.2 get_runTaskList
1941
1942 と、全て mail_check の中で終わってたんですが、これを
1943
1944 1. mail_check
1945 1.1 check_task_finish
1946 1.1.1 notify_task_finish
1947 2. wakeup_waitTask (つまり append_activeTask)
1948 3. get_runTaskList
1949
1950 というように分割しました。
1951 おかげで CellTaskManagerImpl の mail_check もすっきり。
1952
1953 2008-05-13 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1954
1955 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::set_task):
1956 // set_task って名前やめね?
1957
1958 どの SPE に振るかって判定を少し変更。
1959 cur_anySpeid の宣言場所のコメントにもあるけど、
1960 これはインクリメントじゃなくて乱数の方が
1961 より SPE_ANY っぽいのか。むしろ「仕事してない方に割り振る」ってのが
1962 SPE_ANY の役目な気がするな。ウーム。。。
1963
1964 2008-05-05 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1965
1966 * Cell/CellTaskManagerImpl.cpp (CellTaskManagerImpl::mail_check):
1967 PPE には実行するタスクが一つも無い時の動作がおかしかった。
1968 要するに、
1969
1970 PPE で実行するタスクは全て SPE で実行中のタスク待ち
1971
1972 って時。。。よけいわからなくなったな。
1973 まあなんだ、今まで 必ずタスクが PPE and SPE にあったんだけど
1974 PPE or SPE ってか、どっちか片方でしか動いてない状況だと
1975 終了判定というか、それがおかしかったっぽい。
1976
1977 Hello World でのタスクは
1978
1979 1. "Hello World!!" と表示するタスク (2.) を発行するタスク
1980 2. 表示するタスク
1981 3. 2 が全て終わったら実行される、最後のタスク(番兵的な
1982
1983 この時、(2) が SPE だけで実行されてると、
1984 (2) の終了を待つ (3) の判定?というか、それがおかしい
1985
1986
1987 もう眠くてわけわからん。
1988 一応動いたんだけど、やはり描き直します。
1989 気持ち悪いほどやっつけな書き方してるので。これはきもい。。。
1990
1991 2008-03-09 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
1992
1993 * memo: pthread_cond_wait
1994 この ChangeLog に書くものでもないが、まあメモ。
1995
1996 セマフォの P 動作は、基本的に
1997
1998 ---------------------
1999 pthread_mutex_lock(&sem->mutex);
2000
2001 while(sem->value == 0) { // 資源が無い
2002 // 条件付き変数に自分を登録して、ロックを解放して、他の
2003 // プロセスが資源を解放してくれるのを待つ
2004 pthread_cond_wait(&sem->cond,&sem->mutex);
2005 }
2006 // 自分の分の資源があったので、それを確保する */
2007 sem->value--;
2008 // ロックを解放する
2009 pthread_mutex_unlock(&sem->mutex);
2010 ----------------------
2011
2012 こんな感じ。でコメントにもあるように、
2013 pthread_cond_wait では、wait の前に unlock する。
2014 これがよくわかってなくて、「while の外で lock してるのに
2015 「なんで他のプロセスが lock できるんだろう。」と。
2016 man 見ろよと思った。てか先生のページのコメントに書いてるよ!
2017
2018
2019 2008-03-08 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2020
2021 * memo: mailbox read の blocking/non-blocking
2022 spe_out_mbox_read は non-blocking API なので、
2023 これをぐるぐる回すと busy-wait になるので、
2024 今の所 ppe 側の Scheduler がトップに戻る?時にメール確認する。
2025 で、spe_out_intr_mbox_read は blocking API 。
2026 spe_out_mbox_read との記述の違いは、予め
2027 spe_event_handler_register で SPE_EVENT_OUT_INTR_MBOX を
2028 登録しておく。spe 側では、
2029
2030 spu_writech(SPU_WrOutMbox, data)
2031
2032 じゃなくて
2033
2034 spu_writech(SPU_WrOutIntrMbox, data)
2035
2036 を使う必要がある。
2037 両者の mailbox read の速度を調べてみたけど、そんなに違いは感じない。
2038 まあベンチマークの取り方がへぼいせいかもしれないけど。
2039 ってことで、こっちの intr の方がいいんじゃないかと思う。
2040 これと セマフォを組み合わせて mail の処理は簡単になると思う。
2041 セマフォの処理が重いって話もあるが、どうなんだろうね。
2042
2043 * Test/simple_render/task/create_span.cpp (half_triangle): fix
2044 画面外の span を描画しようとして落ちるので、それの修正。
2045 polygon->span の時点で外してるけど、span を外すより
2046 Polygon の時点で修正するべきかな?
2047
2048 * kernel/ppe/TaskManagerImpl.cpp (TaskManagerImpl::set_task): fix
2049 返す TaskList が、mainTaskList の最後尾になってた。
2050 ってことで、TaskList のトップである bufferManager->mainTaskList を。
2051
2052 * kernel/ppe/BufferManager.cpp (BufferManager::clear_taskList): fix
2053 mainTaskList->length はクリアしてるのに、
2054 mainTaskList->next をクリアし忘れてた。
2055 だから空の TaskList が送られてたのか・・・ちくしょう!
2056
2057 2008-03-07 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2058
2059 * bug-fix (Test/simple_render): y座標の移動方向
2060 (1) で、書き込む時に
2061
2062 y = height - y
2063
2064 としていた。千秋に聞いてみると、
2065
2066 「ポリゴンの y を増やす(+)と、画面上に進むようにした」
2067
2068 だそうです。なるほどねー。ってことで(2)でもやったら上に進んだよ。
2069
2070 しかし、ゲーム的には上が + の方がわかりやすいかもしれんが、
2071 プログラミング的には、framebuffer ベースでやるので、
2072 下にいくと y++ ってほうが作りやすいかなーと思いつつ。どっちがいいかね
2073
2074 * bug (Test/simple_render): y座標の移動方向
2075 Viewer::run_draw で、従来の、SpanPack をそのまま描画する方法(1)と、
2076 SPE に渡すように、8分割したものとして描画する方法(2)で、
2077 それぞれの y に +0.5 とかしたら、移動する方向が違う。
2078 (1)では上、(2)では下へ行く。
2079 送られてくる span には違いが見られず、
2080 x 方向や 回転は問題ないので、おそらく draw 時の y の計算のバグだろう。
2081
2082 1: polygon.cpp Polygon::draw(SPANPACK);
2083 2: task/span_pack_draw.cpp run();
2084
2085 * Test/simple_render/spe/SpuDraw.cpp: ↓の続きの解決
2086 render_y &= ~7
2087
2088 これでおkでした。先生ありがとうございます。
2089 今はマクロとして
2090
2091 #define YTOP(y) (y & ~7)
2092
2093 ってやってますわ。
2094
2095 2008-03-05 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2096
2097 * memo: MFC List DMA の element の最大値
2098 「Cell Broadband Engine Architecture Version 1.02」 より
2099
2100 P.55
2101 The maximum number of elements is 2048.
2102 Each element describes a transfer of up to 16 KB.
2103
2104 ってことらしいです。一度の転送での制限は普通のDMAと変わらず16KB。
2105 mfc_list_element_t は 2048 個まで設定できるってことか。
2106 テクスチャのロードで、分割しないなら MFC List DMA を使うことになるが、
2107 2048 個もあれば充分?
2108
2109
2110 * Test/simple_render/spe/SpuDraw.cpp: ↓の続き
2111 と思ったけど、やっぱりずれるなあ。うーむ。
2112 とりあえず今は
2113
2114 if (render_y < 0) {
2115 int tmpy = render_y%8;
2116 render_y -= tmpy + (tmpy != 0)*8;
2117 } else {
2118 render_y -= (render_y%8);
2119 }
2120 render_y += 1080/2;
2121
2122 で落ち着くことに。うーむ。
2123 もっと良い計算を考えるよりは span の生成時で
2124 いろいろやるほうがいいのかなー
2125
2126 2008-03-04 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2127
2128 * Test/simple_render/spe/SpuDraw.cpp: ↓の続き
2129 よくよく考えてだな。。。マイナスが気になるなら
2130
2131 if (render_y < 0) {
2132 int tmpy = render_y%8;
2133 render_y -= tmpy + (tmpy != 0)*8;
2134 } else {
2135 render_y -= (render_y%8);
2136 }
2137 render_y += 1080/2;
2138
2139 じゃなくて
2140
2141 render_y += 1080/2;
2142 render_y -= (render_y%8);
2143
2144 これでよくね?ってか元々そのための 1080/2 だった気が。。。
2145
2146 * Test/simple_render/spe/SpuDraw.cpp: render_y の計算の修正
2147 sp->span[0].y (SpanPack に格納されてる最初の Span の y 座標) から
2148 この SpanPack が描画する範囲の一番上の y 座標を調べる。
2149
2150 どういうことかっていうと、例えば SpanPack に入ってる Span が持つ
2151 y 座標が 1 ~ 8 の時
2152
2153 1 -----
2154 --
2155 --------
2156 ----
2157 ---------
2158 8 --
2159
2160 '-' は描画していると思ってください。
2161 この場合は、y = 1 がこの SpanPack の一番上、基準となる 座標ってこと。
2162 framebuffer に書き込むとき、y = 1 から順々に書いて行きます。
2163
2164 で、sp->span[0].y ってのが、その基準となる y である保証が無いので、
2165 sp->span[i].y 、つまりどの y からでも、基準となる y を求める
2166 必要がある。その計算をミスってました。
2167
2168 1 //////////
2169 <- なぜか書き込まれていない
2170 //////////
2171 //////////
2172
2173 みたいに、歯抜けした部分があったので、いろいろ調べてみたら
2174 この render_y がずれてるってことが判明しました。
2175 今までは
2176
2177 render_y = sp->span[0].y;
2178 render_y += 1080/2;
2179 render_y = (render_y/8)*8;
2180
2181 ってことしてたんだけど、これだと sp->span[0].y が マイナスのとき
2182 ずれることが判明。なので
2183
2184 if (render_y < 0) {
2185 int tmpy = render_y%8;
2186 render_y -= tmpy + (tmpy != 0)*8;
2187 } else {
2188 render_y -= (render_y%8);
2189 }
2190 render_y += 1080/2;
2191
2192 こうするとできました。。。が、直したい。
2193 もう少し奇麗に描けると思うんだけどなー。if 文ぐらいは外したい
2194
2195 2008-03-03 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2196
2197 * memo: 最適化の結果
2198 ppe/spe ともに最適化なしの場合
2199 263.444 FPS
2200
2201 ppe だけ -O9 で最適化
2202 317.425 FPS
2203
2204 spe だけ -O9 で最適化
2205 812.539 FPS
2206
2207 ppe/spe ともに -O9 で最適化
2208 1610.58 FPS (吹いた
2209
2210
2211 最初、ダブル最適化の画像を見た時の
2212 あまりの早さにびびった。
2213 逆に「こ、これはバグか!?」と思った
2214
2215
2216 2008-02-28 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2217
2218 * kernel/ppe/BufferManager.cpp: remove_taskQueue_all()
2219 taskQueue の create と free が釣り合って無くて、
2220 queue が足りなくなる -> extend_pool -> 足りなく(ry
2221 ってのを繰り返してメモリ的なセグメンテーションフォルとが出て
2222 なんでかなと思ったら、task->wait_me を消去してなかった。
2223 task->wait_i は notify(ry で削除されるんだけど、
2224 task->wait_me は、notify(ry に渡した後ほったらかしだった。
2225 ってことで、wait_me を全消しする関数を作りましたとさ。
2226 気持ち速度が増した気がする。気ね。
2227
2228
2229 2008-02-17 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2230
2231 * Todo: 悩んでる所
2232
2233
2234 * fix: kernel/ppe/HTask.cpp
2235 今まで、manager->create_task で生成したタスクは
2236
2237 - dependency の設定
2238 manager->set_task_depend(master, slave) // slave は master を待つ
2239
2240 - 実行キューへの追加
2241 manager->spawn_task(master);
2242 manager->spawn_task(slave);
2243
2244 と、manager を介してやっていました。
2245 まあそれでもいいんだけど、特に dependency の所は
2246 どっちがどっちを待つのかってのは、API見るだけじゃわからない。
2247 そこで、Task (HTask のこと) に、上二つに対応するような
2248
2249 void set_depend(HTaskPtr) と void spawn(void) を追加しました。
2250
2251 - Usage
2252 slave->set_depend(master); // slave は master を待つ
2253 slave->spawn(); // slave をキューへ追加
2254
2255 結局は、それぞれの関数の中では、上の set_task_depend とかを
2256 呼んでるんだけど、ユーザ側からするとこの方がわかりやすいと思います。
2257
2258 2008-02-16 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2259
2260 * tag: beta3
2261 ダブルバッファリングを追加し、まあなんとか動いてるんじゃない?って
2262 ところまでですが、所詮 Fifo バージョンなので、
2263 そろそろ Cell を書き上げて、並列にちゃんと動いてるか確かめないとね
2264
2265 * add: kernel/ppe/DmaBuffer.cpp
2266 ダブルバッファリング用に作ったんだけど、
2267 せっかくなので、DMA は、このオブジェクト(が持つ二つの領域)でしか
2268 行えないようにする。ってのでどうでしょう。って話を先生としました。
2269 並列処理だし、ダブルバッファリングがデフォでいいでしょう。
2270 というか、したくなければ swap_buffer とかしなければおk。
2271
2272 -Usage
2273 DmaBuffer *buffer = manager->allocate(sizeof(SceneGraphPack));
2274
2275 今までと違い、create_task の in_addr と out_addr には
2276 DmaBuffer をいれてください。ユーザが自分で malloc/new したやつは
2277 エラーを出すようにしてる(seg faultだけどね!)
2278 汚いソースだが、実際に使ってる様子は Test/simple_render の
2279 viewer.cpp で使ってます。sgp_buff と pp_buff ってやつね。
2280
2281 もうすこしユーザに優しいAPIを作りたい・・・
2282
2283 2008-02-11 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2284
2285 * add: Test/simple_render
2286 chiaki の DataPack を使った Cube の表示プログラム。
2287 簡単に DataPack を TaskManager の scheduler (SpeManager) に渡して
2288 処理してコピーして、を繰り返してるだけなんだけど
2289 まあ動いてる気がするのでいいんじゃないでしょうか。
2290
2291
2292 2008-02-10 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2293
2294 * tag: beta1
2295 この状況だと、できることよりもできないことを書くべき?違うか。
2296
2297 - task (親) 中で task (子) を生成することはできない
2298 正確には「生成はできる」だけど、その 子task が
2299 親task に依存している別の task を無視して動くので
2300 ちゃんとした結果にならないと。
2301 8日の Todo にも書いてあるけど、今の実装では
2302 task が task を生成することを想定してない感じなので。
2303 完全に spe 用にのみ狙いを絞った実装であって
2304 OS って言えない実装であるからして、書き直すの?
2305 全ての関数を task しようとするとこうなる訳で、
2306 ある部分だけやるってのはまあできるんだろうけど、うーん。
2307
2308 - chiaki の simple_render が動かない
2309 (追記) 解決しました
2310 単に read/write buffer のサイズが足りないだけだった。アホスwww
2311 まあ辱めの為の下は残しておこう
2312
2313 まだ cvs に commit してないけど、chiaki が書いた、
2314 DataPack 対応の simple_render に TasKManager を組み込んでみた。
2315 といっても、OSっぽく書いたんじゃなく、今は
2316 update_sgp と create_pp だけを task 化してみた。
2317 でまあ動いてるような気はするけど、ものすっごい malloc 系の warning が。
2318 時々長く動くよねみたいな感じになってしまっている。
2319 TaskManager が悪いのか、simple_render が悪いのか。
2320 この TaskManager、ある部分での malloc 系の問題に敏感だなあ。
2321 まあそうでなかったらバグの探しようも無いし、良いっちゃー良いんだが。
2322
2323
2324 2008-02-08 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2325
2326 * add: kernel/ppe/SymTable.cpp
2327 今まで func[] = {add, sum, ...}
2328 とかやってかっこわるい言われまくってたので
2329 話し合いの通り Symbol Table みたいなものを作ることに
2330
2331 // 疑似コードね
2332 struct sym_table {
2333 char *sym; // シンボル
2334 void *address; // シンボルが示すアドレス
2335 } sym_table[] = {{"Sum", &Sum} , {"Draw", &draw}};
2336
2337 int fd = get_fd("Sum");
2338 void *addr = get_address(fd);
2339
2340 table には "Sum" と "Draw" っていう二つのシンボルが登録されている。
2341 例えば、ユーザ(カーネル?)が "Sum" ってシンボルにアクセスしたい場合、
2342 まずは get_fd で "Sum" に対する、file descripter を返す。
2343 ユーザは、その fd に従って get_address を取得することが出来る。
2344 TaskManager 的な使い方をするなら
2345
2346 // 俺は今、Draw 関数を使うタスクを生成したい
2347 int fd = manager->open("Draw");
2348 manager->create_task(fd, size, in, out, func);
2349 manager->open では get_fd と同じ使い方です。
2350
2351 まだ改良の余地ありそうですが、今は動いてるってことで。
2352
2353
2354 - 補足
2355 なぜ file descripter と表すか
2356
2357 OS の昨日として、 fopen とかと同じ使い方もできるじゃない!
2358
2359
2360 * Todo: task が task を生成する際の処理
2361 今まで、 task が行う作業は、演算のみを行うような
2362 単純な実装に決め打ちされているわけです。
2363 しかし、OS なんかだと、タスク中から別のタスクを生成するとか
2364 ありありだと思われる。てか今のテストプログラムでなった。
2365
2366 Test/Sum にあるプログラムで使われるタスク
2367
2368 - init2 // 貧相な名前ですまない
2369 演算する数値とかバッファの初期化
2370
2371 - sum1
2372 ある範囲の整数 (i から i+16 とか) の総和
2373
2374 - sum2
2375 sum1 で求められた、複数の範囲の総和を一つにまとめる
2376 (ex. 複数の sum1 が 1->16, 17->32, 33->48 の総和を計算し、
2377 sum2 で 上の3つの総和を計算する
2378 要は 1->48 の総和を分割するっていうプログラムね
2379
2380 - finish
2381 sum2 で求まった値を表示
2382
2383 この Sum というプログラム、というか OS と言おう。SumOS ね。
2384 SumOS は最初に TaskManager (所謂 kernel) を起動し、
2385 init を起動する。init では、予め決められたタスクである
2386 init2 と finish の二つのタスクを create して登録する。
2387 init2 と finish には依存関係がある (init2 が終わったら finish)
2388 init2 の中で、sum1 と sum2 というタスクが作られる。
2389 sum1 と sum2 にも依存関係はある (sum1 が終わったら sum2)
2390
2391 今の実装だと、タスクが終了して初めて次のタスクへ行く。
2392 まあ当たり前なんだけど、例えばそのタスクの中で
2393 新たにタスクが作られた場合、そのタスクが終了するまでは
2394 実行されなくなってしまう。
2395 でまあ、今は、manager->create_task される度に
2396 manager->run とかして、無理やり起動してる訳さ。
2397 何が無理矢理かっていうと、scheduler の役目をしている
2398 SpeManager (これも名前変えないと) を2度呼び出してる訳。
2399 つまり、タスク中でタスクを作る度に、SpeManager オブジェクトを
2400 new してるわけさ。いいのか?いや、動いてるけどね?
2401
2402 ちなみに、Cell version だと spe が勝手に取っていってくれるから
2403 大丈夫かなと思いつつ、もし spe を1つしか使わない設定だったら微妙。
2404
2405 要するに、タスク中でタスクが作られる場合の処理を考えないとね。
2406
2407 2008-02-07 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2408
2409 * memo: プログラミングの姿勢
2410 scheduler とか、task の管理をする部分は
2411 kernel programing のつもりで、
2412 example とか、task に割り当てる処理を決めたりする部分は
2413 user programing のつもりで。
2414
2415 それぞれ違った視点で見る必要がある
2416
2417 * memo: OS というもの
2418 OS 起動の流れ
2419
2420 - PC の電源を入れる
2421 - BIOS が立ち上がる (OpenFirmWare, EFI, BIOS)
2422 - 起動デバイスをチェック (優先度とか種類とか)
2423 - 起動デバイスから Boot loader を起動
2424 + BIOS によって、認識できるファイルシステムが違う(だっけ?)
2425 + ファイルシステムのどこに Boot Loader があるか知っている
2426 + grub, grub2, lilo, kboot などがある
2427 - Boot Loader が kernel を起動
2428 + ネットワークブートの場合、TCP/IP や
2429 ネットワークデバイス(イーサとか?)のドライバを持ってる必要がある
2430 - kernel は、最初に scheduler を起動する
2431 - scheduler の初期化 (init を呼ぶ?)
2432 - init では、事前?に設定されているスクリプトとかを呼ぶ
2433 + linux とかだと /etc/rc にあるやつを init が呼ぶ
2434 - login form が起動
2435
2436 補足 こっからユーザ
2437 - login する
2438 - shell を呼ぶ
2439 + login shell かどうか確かめる
2440 - ユーザに設定されてる起動スクリプト?を実行
2441 - 晴れてログイン
2442
2443 2008-02-06 Wataru MIYAGUNI <gongo@cr.ie.u-ryukyu.ac.jp>
2444
2445 * kernel/spe/*.cpp: new と placement new
2446 現在、spe kernel のタスクは、切り替わる毎に
2447 new/delete を繰り返しています。今はこれでいいんだけど、
2448 速度的にも、いずれは直さないといけないと思うわけで。
2449 で、予め allocate された領域を利用した placement new を使えば
2450 new よりもそれなりに早くなるっぽい。
2451 例題として、与えられた回数分 new/delete を繰り返すプログラムと、
2452 同じ回数分、placement new したときの速度の比較
2453
2454 for (int i = 0; i < num; i++) {
2455
2456 < task = new Task;
2457 < task->init(i);
2458 < task->printID();
2459 < delete task;
2460 ---
2461 > task = new(buff) Task; // buff = malloc(BUFF_SIZE);
2462 > task->init(id);
2463 > task->printID(id);
2464 }
2465
2466 placement new では、delete の必要は無い。
2467 その中で新たに allocate してるなら必要かもしれないが。
2468 速度比較は以下。no_new が placement new で、ln_new が new/delete 。
2469
2470 % ./a.out 10 // 10 回
2471 no_new: time: 0.012135(msec)
2472 ln_new: time: 0.003572(msec)
2473
2474 % ./a.out 100
2475 no_new: time: 0.022453(msec)
2476 ln_new: time: 0.018989(msec)
2477
2478 % ./a.out 1000
2479 no_new: time: 0.115277(msec)
2480 ln_new: time: 0.136335(msec)
2481
2482 % ./a.out 10000
2483 no_new: time: 1.056156(msec)
2484 ln_new: time: 1.322709(msec)
2485
2486 % ./a.out 100000
2487 no_new: time: 10.622221(msec)
2488 ln_new: time: 13.362414(msec)
2489
2490 % ./a.out 1000000
2491 no_new: time: 109.436496(msec)
2492 ln_new: time: 136.956872(msec)
2493
2494 10、100 回だと負けてるが、まあ無視しよう(ぇ
2495 回数が多くなるにつれて、ほんの少しだが no_new が勝ってる。
2496 どうなんだろうね。ちなみに printID を無くすと
2497
2498 % ./a.out 1000000
2499 no_new: time: 0.008512(msec)
2500 ln_new: time: 27.100296(msec)
2501
2502 I/O に左右され過ぎ。まあそんなもんだろうけどさ。