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