3f2780c52988bf9e53468c9826a42c667696b1ee
[debian/gnuradio] / gcell / src / lib / runtime / qa_job_manager.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007,2008 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "qa_job_manager.h"
23 #include <cppunit/TestAssert.h>
24 #include "gc_job_manager.h"
25 #include <stdexcept>
26 #include <stdio.h>
27 #include <time.h>
28 #include <errno.h>
29
30 #include <malloc.h>
31
32 extern spe_program_handle_t gcell_qa;   // handle to embedded SPU executable w/ QA routines
33
34 #if 0
35 static void
36 gc_msleep(unsigned long millisecs)
37 {
38   int r;
39   struct timespec tv;
40   tv.tv_sec = millisecs / 1000;
41   tv.tv_nsec = (millisecs - (tv.tv_sec * 1000)) * 1000000;
42   
43   while (1){
44     r = nanosleep(&tv, &tv);
45     if (r == 0)
46       return;
47     if (r == -1 && errno == EINTR)
48       continue;
49     perror("nanosleep");
50     return;
51   }
52 }
53 #endif
54
55 void
56 qa_job_manager::leak_check(test_t t, const std::string &name)
57 {
58   struct mallinfo before, after;
59
60   before = mallinfo();
61   (this->*t)();
62   after = mallinfo();
63
64   size_t delta = after.uordblks - before.uordblks;
65   if (delta != 0){
66     std::cout << name << " leaked memory\n";
67     printf("  before.uordblks = %6d\n", before.uordblks);
68     printf("  after.uordblks  = %6d\n",  after.uordblks);
69     printf("  delta = %d\n", after.uordblks - before.uordblks);
70   }
71 }
72
73 void
74 qa_job_manager::t0()
75 {
76   //leak_check(&qa_job_manager::t1_body, "t1-0");
77 }
78
79 void
80 qa_job_manager::t1()
81 {
82   t1_body();            // leaks 800 bytes first time, could be one-time inits
83   leak_check(&qa_job_manager::t1_body, "t1");
84 }
85
86 void
87 qa_job_manager::t2()
88 {
89   leak_check(&qa_job_manager::t2_body, "t2");
90 }
91
92 void
93 qa_job_manager::t3()
94 {
95   t3_body();            // leaks first time only, could be cppunit
96   leak_check(&qa_job_manager::t3_body, "t3");
97 }
98
99 void
100 qa_job_manager::t4()
101 {
102   leak_check(&qa_job_manager::t4_body, "t4");
103 }
104
105 void
106 qa_job_manager::t5()
107 {
108   leak_check(&qa_job_manager::t5_body, "t5");
109 }
110
111 void
112 qa_job_manager::t6()
113 {
114   leak_check(&qa_job_manager::t6_body, "t6");
115 }
116
117 void
118 qa_job_manager::t7()
119 {
120   leak_check(&qa_job_manager::t7_body, "t7");
121 }
122
123 void
124 qa_job_manager::t8()
125 {
126   leak_check(&qa_job_manager::t8_body, "t8");
127 }
128
129 void
130 qa_job_manager::t9()
131 {
132   leak_check(&qa_job_manager::t9_body, "t9");
133 }
134
135 void
136 qa_job_manager::t10()
137 {
138   leak_check(&qa_job_manager::t10_body, "t10");
139 }
140
141 void
142 qa_job_manager::t11()
143 {
144   leak_check(&qa_job_manager::t11_body, "t11");
145 }
146
147 void
148 qa_job_manager::t12()
149 {
150   leak_check(&qa_job_manager::t12_body, "t12");
151 }
152
153 void
154 qa_job_manager::t13()
155 {
156   leak_check(&qa_job_manager::t13_body, "t13");
157 }
158
159 void
160 qa_job_manager::t14()
161 {
162   leak_check(&qa_job_manager::t14_body, "t14");
163 }
164
165 void
166 qa_job_manager::t15()
167 {
168   leak_check(&qa_job_manager::t15_body, "t15");
169 }
170
171 // ----------------------------------------------------------------
172
173 void
174 qa_job_manager::t1_body()
175 {
176   gc_job_manager *mgr;
177   gc_jm_options opts;
178   opts.program_handle = &gcell_qa;
179   mgr = gc_make_job_manager(&opts);
180   delete mgr;
181 }
182
183 void
184 qa_job_manager::t2_body()
185 {
186   gc_job_manager *mgr = 0;
187   gc_jm_options opts;
188   opts.program_handle = &gcell_qa;
189   opts.nspes = 100;
190   opts.gang_schedule = false;
191   mgr = gc_make_job_manager(&opts);
192   delete mgr;
193 }
194
195 void
196 qa_job_manager::t3_body()
197 {
198   // This leaks memory the first time it's invoked, but I'm not sure
199   // if it's us or the underlying exception handling mechanism, or
200   // cppunit.  cppunit is the prime suspect.
201
202 #if 0
203   gc_job_manager *mgr = 0;
204   gc_jm_options opts;
205   opts.program_handle = &gcell_qa;
206   opts.nspes = 100;
207   opts.gang_schedule = true;
208   CPPUNIT_ASSERT_THROW(mgr = gc_make_job_manager(&opts), std::out_of_range);
209   delete mgr;
210 #endif
211 }
212
213 static void
214 init_jd(gc_job_desc *jd, gc_proc_id_t proc_id)
215 {
216   jd->proc_id = proc_id;
217   jd->input.nargs = 0;
218   jd->output.nargs = 0;
219   jd->eaa.nargs = 0;
220 }
221
222 void
223 qa_job_manager::t4_body()
224 {
225   gc_job_manager *mgr;
226   gc_jm_options opts;
227   opts.program_handle = &gcell_qa;
228   opts.nspes = 1;
229   mgr = gc_make_job_manager(&opts);
230   //mgr->set_debug(-1);
231   static const int NJOBS = 32;
232   gc_job_desc *jds[NJOBS];
233   bool done[NJOBS];
234
235   gc_proc_id_t gcp_no_such = mgr->lookup_proc("--no-such-proc-name--");
236   CPPUNIT_ASSERT_EQUAL(GCP_UNKNOWN_PROC, gcp_no_such);
237
238   gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
239   CPPUNIT_ASSERT(gcp_qa_nop != GCP_UNKNOWN_PROC);
240
241   for (int i = 0; i < NJOBS; i++){
242     jds[i] = mgr->alloc_job_desc();
243     init_jd(jds[i], gcp_qa_nop);
244   }
245
246   for (int i = 0; i < NJOBS; i++){
247     if (!mgr->submit_job(jds[i])){
248       printf("%d: submit_job(jds[%d]) failed, status = %d\n",
249              __LINE__, i, jds[i]->status);
250     }
251   }
252
253   int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
254   CPPUNIT_ASSERT_EQUAL(NJOBS, n);
255
256   for (int i = 0; i < NJOBS; i++){
257     mgr->free_job_desc(jds[i]);
258   }
259
260   delete mgr;
261 }
262
263 void
264 qa_job_manager::t5_body()
265 {
266   gc_job_manager *mgr;
267   gc_jm_options opts;
268   opts.program_handle = &gcell_qa;
269   opts.nspes = 0;       // use them all
270   mgr = gc_make_job_manager(&opts);
271   //mgr->set_debug(-1);
272   static const int NJOBS = 32;
273   gc_job_desc *jds[NJOBS];
274   bool done[NJOBS];
275
276   gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
277
278   for (int i = 0; i < NJOBS; i++){
279     jds[i] = mgr->alloc_job_desc();
280     init_jd(jds[i], gcp_qa_nop);
281   }
282
283   for (int i = 0; i < NJOBS; i++){
284     if (!mgr->submit_job(jds[i])){
285       printf("%d: submit_job(jds[%d]) failed, status = %d\n",
286              __LINE__, i, jds[i]->status);
287     }
288   }
289
290   int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
291   CPPUNIT_ASSERT_EQUAL(NJOBS, n);
292
293   for (int i = 0; i < NJOBS; i++){
294     mgr->free_job_desc(jds[i]);
295   }
296
297   delete mgr;
298 }
299
300 void
301 qa_job_manager::t6_body()
302 {
303   gc_job_manager *mgr;
304   gc_jm_options opts;
305   opts.program_handle = &gcell_qa;
306   opts.nspes = 1;       
307   mgr = gc_make_job_manager(&opts);
308   gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
309   gc_job_desc *jd = mgr->alloc_job_desc();
310
311   
312   // test for success with gcp_qa_nop procedure
313   init_jd(jd, gcp_qa_nop);
314   if (!mgr->submit_job(jd)){
315     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
316   }
317   else {
318     mgr->wait_job(jd);
319     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
320   }
321
322   // test for JS_UNKNOWN_PROC with bogus procedure
323   init_jd(jd, -2);
324   if (!mgr->submit_job(jd)){
325     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
326   }
327   else {
328     mgr->wait_job(jd);
329     CPPUNIT_ASSERT_EQUAL(JS_UNKNOWN_PROC, jd->status);
330   }
331
332   mgr->free_job_desc(jd);
333   delete mgr;
334 }
335
336 static int
337 sum_shorts(short *p, int nshorts)
338 {
339   int total = 0;
340   for (int i = 0; i < nshorts; i++)
341     total += p[i];
342
343   return total;
344 }
345
346 static void
347 test_sum_shorts(gc_job_manager *mgr, short *buf, int nshorts)
348 {
349   gc_job_desc *jd = mgr->alloc_job_desc();
350   gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
351
352   init_jd(jd, gcp_qa_sum_shorts);
353   jd->eaa.nargs = 1;
354   jd->eaa.arg[0].ea_addr = ptr_to_ea(buf);
355   jd->eaa.arg[0].direction = GCJD_DMA_GET;
356   jd->eaa.arg[0].get_size = nshorts * sizeof(short);
357   
358
359   if (!mgr->submit_job(jd)){
360     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
361   }
362   else {
363     mgr->wait_job(jd);
364     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
365     int expected = sum_shorts(buf, nshorts);
366     int actual = jd->output.arg[0].s32;
367     CPPUNIT_ASSERT_EQUAL(expected, actual);
368   }
369
370   mgr->free_job_desc(jd);
371 }
372
373 static const int NS = 32768;
374 static short short_buf[NS] _AL128;      // for known alignment
375
376 //
377 // test all "get" alignments and sizes
378 //
379 void
380 qa_job_manager::t7_body()
381 {
382   gc_job_manager *mgr;
383   gc_jm_options opts;
384   opts.program_handle = &gcell_qa;
385   opts.nspes = 1;
386   mgr = gc_make_job_manager(&opts);
387
388   int ea_args_maxsize = mgr->ea_args_maxsize();
389
390   for (int i = 0; i < NS; i++)  // init buffer with known qty
391     short_buf[i] = 0x1234 + i;
392   
393   for (int offset = 0; offset <= 128; offset++){
394     for (int len = 0; len <= 128; len++){
395       test_sum_shorts(mgr, &short_buf[offset], len);
396     }
397   }
398
399   // confirm maximum length
400   for (int offset = 0; offset <= 64; offset++){
401     test_sum_shorts(mgr, &short_buf[offset], ea_args_maxsize/sizeof(short));
402   }
403
404   delete mgr;
405 }
406
407 //
408 // test "get" args too long
409 //
410 void
411 qa_job_manager::t8_body()
412 {
413   gc_job_manager *mgr;
414   gc_jm_options opts;
415   opts.program_handle = &gcell_qa;
416   opts.nspes = 1;
417   mgr = gc_make_job_manager(&opts);
418   gc_job_desc *jd = mgr->alloc_job_desc();
419   gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
420
421   init_jd(jd, gcp_qa_sum_shorts);
422   jd->eaa.nargs = 1;
423   jd->eaa.arg[0].ea_addr = 0;
424   jd->eaa.arg[0].direction = GCJD_DMA_GET;
425   jd->eaa.arg[0].get_size = 1 << 20;
426
427   if (!mgr->submit_job(jd)){
428     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
429   }
430   else {
431     mgr->wait_job(jd);
432     CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
433   }
434
435   mgr->free_job_desc(jd);
436   delete mgr;
437 }
438
439 //
440 // test MAX_ARGS_EA "get" case
441 //
442 void
443 qa_job_manager::t9_body()
444 {
445   static const int N = 127;
446   static const int M = 201;
447   gc_job_manager *mgr;
448   gc_jm_options opts;
449   opts.program_handle = &gcell_qa;
450   opts.nspes = 1;
451   mgr = gc_make_job_manager(&opts);
452   gc_job_desc *jd = mgr->alloc_job_desc();
453   gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
454
455   init_jd(jd, gcp_qa_sum_shorts);
456   jd->eaa.nargs = MAX_ARGS_EA;
457   for (int i = 0; i < MAX_ARGS_EA; i++){
458     jd->eaa.arg[i].direction = GCJD_DMA_GET;
459     jd->eaa.arg[i].ea_addr = ptr_to_ea(&short_buf[i * M]);
460     jd->eaa.arg[i].get_size = N * sizeof(short);
461   }
462
463   if (!mgr->submit_job(jd)){
464     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
465   }
466   else {
467     mgr->wait_job(jd);
468     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
469     for (int i = 0; i < MAX_ARGS_EA; i++){
470       int expected = sum_shorts(&short_buf[i * M], N);
471       int actual = jd->output.arg[i].s32;
472       CPPUNIT_ASSERT_EQUAL(expected, actual);
473     }
474   }
475
476   mgr->free_job_desc(jd);
477   delete mgr;
478 }
479
480 static bool
481 confirm_const(const unsigned char *buf, size_t len, unsigned char v)
482 {
483   bool ok = true;
484
485   for (size_t i = 0; i < len; i++){
486     if (buf[i] != v){
487       ok = false;
488       printf("confirm_const: buf[%6d] = 0x%02x, expected = 0x%02x\n",
489              i, buf[i], v);
490     }
491   }
492
493   return ok;
494 }
495
496 static bool
497 confirm_seq(const unsigned char *buf, size_t len, unsigned char v)
498 {
499   bool ok = true;
500
501   for (size_t i = 0; i < len; i++, v++){
502     if (buf[i] != v){
503       ok = false;
504       printf("confirm_seq: buf[%6d] = 0x%02x, expected = 0x%02x\n",
505              i, buf[i], v);
506     }
507   }
508
509   return ok;
510 }
511
512 static void
513 test_put_seq(gc_job_manager *mgr, int offset, int len, int starting_val)
514 {
515   gc_job_desc *jd = mgr->alloc_job_desc();
516   gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
517
518   unsigned char *buf = (unsigned char *) short_buf;
519   size_t buf_len = sizeof(short_buf);
520   memset(buf, 0xff, buf_len);
521
522   // two cache lines into the buffer, so we can check before and after
523   int fixed_offset = 256;
524
525   init_jd(jd, gcp_qa_put_seq);
526   jd->input.nargs = 1;
527   jd->input.arg[0].s32 = starting_val;
528   jd->eaa.nargs = 1;
529   jd->eaa.arg[0].ea_addr = ptr_to_ea(buf + fixed_offset + offset);
530   jd->eaa.arg[0].direction = GCJD_DMA_PUT;
531   jd->eaa.arg[0].put_size = len;
532
533   if (!mgr->submit_job(jd)){
534     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
535   }
536   else {
537     mgr->wait_job(jd);
538     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
539     
540     // check before
541     CPPUNIT_ASSERT(confirm_const(&buf[0], fixed_offset + offset, 0xff)); 
542
543     // check sequence
544     CPPUNIT_ASSERT(confirm_seq(&buf[fixed_offset + offset], len, starting_val));
545
546     // check after
547     CPPUNIT_ASSERT(confirm_const(&buf[fixed_offset + offset + len],
548                                  buf_len - fixed_offset - offset - len, 0xff));
549   }
550   mgr->free_job_desc(jd);
551 }
552
553 //
554 // Test all "put" alignments and sizes
555 //
556 void
557 qa_job_manager::t10_body()
558 {
559   gc_job_manager *mgr;
560   gc_jm_options opts;
561   opts.program_handle = &gcell_qa;
562   opts.nspes = 1;
563   mgr = gc_make_job_manager(&opts);
564
565   int starting_val = 13;
566
567   for (int offset = 0; offset <= 128; offset++){
568     for (int len = 0; len <= 128; len++){
569       test_put_seq(mgr, offset, len, starting_val++);
570     }
571   }
572
573   int ea_args_maxsize = mgr->ea_args_maxsize();
574
575   // confirm maximum length
576   for (int offset = 0; offset <= 64; offset++){
577     test_put_seq(mgr, offset, ea_args_maxsize, starting_val++);
578   }
579
580   delete mgr;
581 }
582
583 //
584 // test "put" args too long
585 //
586 void
587 qa_job_manager::t11_body()
588 {
589   gc_job_manager *mgr;
590   gc_jm_options opts;
591   opts.program_handle = &gcell_qa;
592   opts.nspes = 1;
593   mgr = gc_make_job_manager(&opts);
594   gc_job_desc *jd = mgr->alloc_job_desc();
595   gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
596
597   init_jd(jd, gcp_qa_put_seq);
598   jd->input.nargs = 1;
599   jd->input.arg[0].s32 = 0;
600   jd->eaa.nargs = 1;
601   jd->eaa.arg[0].ea_addr = 0;
602   jd->eaa.arg[0].direction = GCJD_DMA_PUT;
603   jd->eaa.arg[0].put_size = 1 << 20;
604
605   if (!mgr->submit_job(jd)){
606     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
607   }
608   else {
609     mgr->wait_job(jd);
610     CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
611   }
612
613   mgr->free_job_desc(jd);
614   delete mgr;
615 }
616
617 //
618 // test MAX_ARGS_EA "put" case
619 //
620 void
621 qa_job_manager::t12_body()
622 {
623   static const int N = 127;
624   static const int M = 201;
625   gc_job_manager *mgr;
626   gc_jm_options opts;
627   opts.program_handle = &gcell_qa;
628   opts.nspes = 1;
629   mgr = gc_make_job_manager(&opts);
630   gc_job_desc *jd = mgr->alloc_job_desc();
631   gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
632
633   unsigned char *buf = (unsigned char *) short_buf;
634   size_t buf_len = sizeof(short_buf);
635   memset(buf, 0xff, buf_len);
636
637   // two cache lines into the buffer, so we can check before and after
638   int fixed_offset = 256;
639
640   int starting_val = 13;
641
642   init_jd(jd, gcp_qa_put_seq);
643   jd->input.nargs = 1;
644   jd->input.arg[0].s32 = starting_val;
645   jd->eaa.nargs = MAX_ARGS_EA;
646   for (int i = 0; i < MAX_ARGS_EA; i++){
647     jd->eaa.arg[i].direction = GCJD_DMA_PUT;
648     jd->eaa.arg[i].ea_addr = ptr_to_ea(&buf[i * M + fixed_offset]);
649     jd->eaa.arg[i].put_size = N;
650   }
651
652   if (!mgr->submit_job(jd)){
653     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
654   }
655   else {
656     mgr->wait_job(jd);
657     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
658     for (int i = 0; i < MAX_ARGS_EA; i++){
659       CPPUNIT_ASSERT(confirm_seq(&buf[i * M + fixed_offset], N, starting_val));
660       starting_val += N;
661     }
662   }
663
664   mgr->free_job_desc(jd);
665   delete mgr;
666 }
667
668 //
669 // test qa_copy primitive
670 //
671 void
672 qa_job_manager::t13_body()
673 {
674   gc_job_manager *mgr;
675   gc_jm_options opts;
676   opts.program_handle = &gcell_qa;
677   opts.nspes = 1;
678   mgr = gc_make_job_manager(&opts);
679
680   memset(short_buf, 0, sizeof(short_buf));
681   for (int i = 0; i < NS/2; i++)        // init buffer with known qty
682     short_buf[i] = 0x1234 + i;
683
684   int nshorts = NS/2;
685
686   gc_job_desc *jd = mgr->alloc_job_desc();
687   gc_proc_id_t gcp_qa_copy = mgr->lookup_proc("qa_copy");
688
689 #if 0
690   printf("gcq_qa_copy = %d\n", gcp_qa_copy);
691   std::vector<std::string> procs = mgr->proc_names();
692   for (unsigned int i = 0; i < procs.size(); ++i)
693     std::cout << procs[i] << std::endl;
694 #endif
695
696   init_jd(jd, gcp_qa_copy);
697   jd->eaa.nargs = 2;
698   jd->eaa.arg[0].ea_addr = ptr_to_ea(&short_buf[nshorts]);
699   jd->eaa.arg[0].direction = GCJD_DMA_PUT;
700   jd->eaa.arg[0].put_size = nshorts * sizeof(short);
701   
702   jd->eaa.arg[1].ea_addr = ptr_to_ea(&short_buf[0]);
703   jd->eaa.arg[1].direction = GCJD_DMA_GET;
704   jd->eaa.arg[1].get_size = nshorts * sizeof(short);
705   
706
707   if (!mgr->submit_job(jd)){
708     printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
709   }
710   else {
711     mgr->wait_job(jd);
712     CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
713     CPPUNIT_ASSERT_EQUAL(0, jd->output.arg[0].s32);
714
715     bool ok = true;
716     for (int i = 0; i < nshorts; i++){
717       if (short_buf[i] != short_buf[i + nshorts])
718         ok = false;
719     }
720     CPPUNIT_ASSERT(ok);
721   }
722   mgr->free_job_desc(jd);
723
724   delete mgr;
725 }
726
727 /*
728  * Parallel submission of NJOBS "put" jobs will test double buffered puts.
729  */
730 void
731 qa_job_manager::t14_body()
732 {
733   //return;
734
735   //static const int NJOBS = 64;
736   static const int NJOBS = 128;
737   static const int LEN_PER_JOB = 1021;
738   unsigned char    buf[NJOBS * LEN_PER_JOB];
739   gc_job_desc_t   *jd[NJOBS];
740   bool             done[NJOBS];
741
742   static const int STARTING_VAL = 13;
743
744   memset(buf, 0xff, LEN_PER_JOB * NJOBS);
745
746   gc_job_manager *mgr;
747   gc_jm_options opts;
748   opts.program_handle = &gcell_qa;
749   opts.nspes = 1;
750   mgr = gc_make_job_manager(&opts);
751
752
753   gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
754
755   // do all the initialization up front
756
757   for (int i = 0, val = STARTING_VAL; i < NJOBS; i++, val += 3){
758     jd[i] = mgr->alloc_job_desc();
759     init_jd(jd[i], gcp_qa_put_seq);
760     jd[i]->input.nargs = 1;
761     jd[i]->input.arg[0].s32 = val;
762     jd[i]->eaa.nargs = 1;
763     jd[i]->eaa.arg[0].ea_addr = ptr_to_ea(&buf[i * LEN_PER_JOB]);
764     jd[i]->eaa.arg[0].direction = GCJD_DMA_PUT;
765     jd[i]->eaa.arg[0].put_size = LEN_PER_JOB;
766   }
767
768   // submit them all
769
770   for (int i = 0; i < NJOBS; i++){
771     if (!mgr->submit_job(jd[i])){
772       printf("%d: submit_job(jd[%2d]) failed, status = %d\n", __LINE__, i, jd[i]->status);
773     }
774   }
775
776   // wait for them all
777
778   int n = mgr->wait_jobs(NJOBS, jd, done, GC_WAIT_ALL);
779   CPPUNIT_ASSERT_EQUAL(NJOBS, n);
780
781   // check results
782
783   for (int i = 0, val = STARTING_VAL; i < NJOBS; i++, val += 3){
784     CPPUNIT_ASSERT_EQUAL(JS_OK, jd[i]->status);
785     CPPUNIT_ASSERT(confirm_seq(&buf[i * LEN_PER_JOB], LEN_PER_JOB, val));
786   }
787   
788   // cleanup
789   for (int i = 0; i < NJOBS; i++)
790     mgr->free_job_desc(jd[i]);
791
792   delete mgr;
793 }
794
795 void
796 qa_job_manager::t15_body()
797 {
798 }