3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
22 #include "qa_job_manager.h"
23 #include <cppunit/TestAssert.h>
24 #include "gc_job_manager.h"
32 // handle to embedded SPU executable w/ QA routines
33 extern spe_program_handle_t gcell_runtime_qa;
37 gc_msleep(unsigned long millisecs)
41 tv.tv_sec = millisecs / 1000;
42 tv.tv_nsec = (millisecs - (tv.tv_sec * 1000)) * 1000000;
45 r = nanosleep(&tv, &tv);
48 if (r == -1 && errno == EINTR)
57 qa_job_manager::leak_check(test_t t, const std::string &name)
59 struct mallinfo before, after;
65 size_t delta = after.uordblks - before.uordblks;
67 std::cout << name << " leaked memory\n";
68 printf(" before.uordblks = %6d\n", before.uordblks);
69 printf(" after.uordblks = %6d\n", after.uordblks);
70 printf(" delta = %d\n", after.uordblks - before.uordblks);
77 //leak_check(&qa_job_manager::t1_body, "t1-0");
83 t1_body(); // leaks 800 bytes first time, could be one-time inits
84 leak_check(&qa_job_manager::t1_body, "t1");
90 leak_check(&qa_job_manager::t2_body, "t2");
96 t3_body(); // leaks first time only, could be cppunit
97 leak_check(&qa_job_manager::t3_body, "t3");
103 leak_check(&qa_job_manager::t4_body, "t4");
109 leak_check(&qa_job_manager::t5_body, "t5");
115 leak_check(&qa_job_manager::t6_body, "t6");
121 leak_check(&qa_job_manager::t7_body, "t7");
127 leak_check(&qa_job_manager::t8_body, "t8");
133 leak_check(&qa_job_manager::t9_body, "t9");
137 qa_job_manager::t10()
139 leak_check(&qa_job_manager::t10_body, "t10");
143 qa_job_manager::t11()
145 leak_check(&qa_job_manager::t11_body, "t11");
149 qa_job_manager::t12()
151 leak_check(&qa_job_manager::t12_body, "t12");
155 qa_job_manager::t13()
157 leak_check(&qa_job_manager::t13_body, "t13");
161 qa_job_manager::t14()
163 leak_check(&qa_job_manager::t14_body, "t14");
167 qa_job_manager::t15()
169 leak_check(&qa_job_manager::t15_body, "t15");
172 // ----------------------------------------------------------------
175 qa_job_manager::t1_body()
177 gc_job_manager_sptr mgr;
179 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
180 mgr = gc_make_job_manager(&opts);
184 qa_job_manager::t2_body()
186 gc_job_manager_sptr mgr;
188 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
190 opts.gang_schedule = false;
191 mgr = gc_make_job_manager(&opts);
195 qa_job_manager::t3_body()
197 // This leaks memory the first time it's invoked, but I'm not sure
198 // if it's us or the underlying exception handling mechanism, or
199 // cppunit. cppunit is the prime suspect.
202 gc_job_manager_sptr mgr;
204 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
206 opts.gang_schedule = true;
207 CPPUNIT_ASSERT_THROW(mgr = gc_make_job_manager(&opts), std::out_of_range);
212 init_jd(gc_job_desc *jd, gc_proc_id_t proc_id)
214 jd->proc_id = proc_id;
216 jd->output.nargs = 0;
221 qa_job_manager::t4_body()
223 gc_job_manager_sptr mgr;
225 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
227 mgr = gc_make_job_manager(&opts);
228 //mgr->set_debug(-1);
229 static const int NJOBS = 32;
230 gc_job_desc *jds[NJOBS];
233 gc_proc_id_t gcp_no_such;
234 CPPUNIT_ASSERT_THROW(gcp_no_such = mgr->lookup_proc("--no-such-proc-name--"), gc_unknown_proc);
236 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
237 CPPUNIT_ASSERT(gcp_qa_nop != GCP_UNKNOWN_PROC);
239 for (int i = 0; i < NJOBS; i++){
240 jds[i] = mgr->alloc_job_desc();
241 init_jd(jds[i], gcp_qa_nop);
244 for (int i = 0; i < NJOBS; i++){
245 if (!mgr->submit_job(jds[i])){
246 printf("%d: submit_job(jds[%d]) failed, status = %d\n",
247 __LINE__, i, jds[i]->status);
251 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
252 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
254 for (int i = 0; i < NJOBS; i++){
255 mgr->free_job_desc(jds[i]);
260 qa_job_manager::t5_body()
262 gc_job_manager_sptr mgr;
264 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
265 opts.nspes = 0; // use them all
266 mgr = gc_make_job_manager(&opts);
267 //mgr->set_debug(-1);
268 static const int NJOBS = 32;
269 gc_job_desc *jds[NJOBS];
272 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
274 for (int i = 0; i < NJOBS; i++){
275 jds[i] = mgr->alloc_job_desc();
276 init_jd(jds[i], gcp_qa_nop);
279 for (int i = 0; i < NJOBS; i++){
280 if (!mgr->submit_job(jds[i])){
281 printf("%d: submit_job(jds[%d]) failed, status = %d\n",
282 __LINE__, i, jds[i]->status);
286 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
287 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
289 for (int i = 0; i < NJOBS; i++){
290 mgr->free_job_desc(jds[i]);
295 qa_job_manager::t6_body()
297 gc_job_manager_sptr mgr;
299 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
301 mgr = gc_make_job_manager(&opts);
302 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
303 gc_job_desc *jd = mgr->alloc_job_desc();
306 // test for success with gcp_qa_nop procedure
307 init_jd(jd, gcp_qa_nop);
308 if (!mgr->submit_job(jd)){
309 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
313 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
316 // test for JS_UNKNOWN_PROC with bogus procedure
318 if (!mgr->submit_job(jd)){
319 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
323 CPPUNIT_ASSERT_EQUAL(JS_UNKNOWN_PROC, jd->status);
326 mgr->free_job_desc(jd);
330 sum_shorts(short *p, int nshorts)
333 for (int i = 0; i < nshorts; i++)
340 test_sum_shorts(gc_job_manager_sptr mgr, short *buf, int nshorts)
342 gc_job_desc *jd = mgr->alloc_job_desc();
343 gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
345 init_jd(jd, gcp_qa_sum_shorts);
347 jd->eaa.arg[0].ea_addr = ptr_to_ea(buf);
348 jd->eaa.arg[0].direction = GCJD_DMA_GET;
349 jd->eaa.arg[0].get_size = nshorts * sizeof(short);
352 if (!mgr->submit_job(jd)){
353 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
357 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
358 int expected = sum_shorts(buf, nshorts);
359 int actual = jd->output.arg[0].s32;
360 CPPUNIT_ASSERT_EQUAL(expected, actual);
363 mgr->free_job_desc(jd);
366 static const int NS = 32768;
367 static short short_buf[NS] _AL128; // for known alignment
370 // test all "get" alignments and sizes
373 qa_job_manager::t7_body()
375 gc_job_manager_sptr mgr;
377 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
379 mgr = gc_make_job_manager(&opts);
381 int ea_args_maxsize = mgr->ea_args_maxsize();
383 for (int i = 0; i < NS; i++) // init buffer with known qty
384 short_buf[i] = 0x1234 + i;
386 for (int offset = 0; offset <= 128; offset++){
387 for (int len = 0; len <= 128; len++){
388 test_sum_shorts(mgr, &short_buf[offset], len);
392 // confirm maximum length
393 for (int offset = 0; offset <= 64; offset++){
394 test_sum_shorts(mgr, &short_buf[offset], ea_args_maxsize/sizeof(short));
399 // test "get" args too long
402 qa_job_manager::t8_body()
404 gc_job_manager_sptr mgr;
406 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
408 mgr = gc_make_job_manager(&opts);
409 gc_job_desc *jd = mgr->alloc_job_desc();
410 gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
412 init_jd(jd, gcp_qa_sum_shorts);
414 jd->eaa.arg[0].ea_addr = 0;
415 jd->eaa.arg[0].direction = GCJD_DMA_GET;
416 jd->eaa.arg[0].get_size = 1 << 20;
418 if (!mgr->submit_job(jd)){
419 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
423 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
426 mgr->free_job_desc(jd);
430 // test MAX_ARGS_EA "get" case
433 qa_job_manager::t9_body()
435 static const int N = 127;
436 static const int M = 201;
437 gc_job_manager_sptr mgr;
439 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
441 mgr = gc_make_job_manager(&opts);
442 gc_job_desc *jd = mgr->alloc_job_desc();
443 gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
445 init_jd(jd, gcp_qa_sum_shorts);
446 jd->eaa.nargs = MAX_ARGS_EA;
447 for (int i = 0; i < MAX_ARGS_EA; i++){
448 jd->eaa.arg[i].direction = GCJD_DMA_GET;
449 jd->eaa.arg[i].ea_addr = ptr_to_ea(&short_buf[i * M]);
450 jd->eaa.arg[i].get_size = N * sizeof(short);
453 if (!mgr->submit_job(jd)){
454 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
458 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
459 for (int i = 0; i < MAX_ARGS_EA; i++){
460 int expected = sum_shorts(&short_buf[i * M], N);
461 int actual = jd->output.arg[i].s32;
462 CPPUNIT_ASSERT_EQUAL(expected, actual);
466 mgr->free_job_desc(jd);
470 confirm_const(const unsigned char *buf, size_t len, unsigned char v)
474 for (size_t i = 0; i < len; i++){
477 printf("confirm_const: buf[%6d] = 0x%02x, expected = 0x%02x\n",
486 confirm_seq(const unsigned char *buf, size_t len, unsigned char v)
490 for (size_t i = 0; i < len; i++, v++){
493 printf("confirm_seq: buf[%6d] = 0x%02x, expected = 0x%02x\n",
502 test_put_seq(gc_job_manager_sptr mgr, int offset, int len, int starting_val)
504 gc_job_desc *jd = mgr->alloc_job_desc();
505 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
507 unsigned char *buf = (unsigned char *) short_buf;
508 size_t buf_len = sizeof(short_buf);
509 memset(buf, 0xff, buf_len);
511 // two cache lines into the buffer, so we can check before and after
512 int fixed_offset = 256;
514 init_jd(jd, gcp_qa_put_seq);
516 jd->input.arg[0].s32 = starting_val;
518 jd->eaa.arg[0].ea_addr = ptr_to_ea(buf + fixed_offset + offset);
519 jd->eaa.arg[0].direction = GCJD_DMA_PUT;
520 jd->eaa.arg[0].put_size = len;
522 if (!mgr->submit_job(jd)){
523 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
527 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
530 CPPUNIT_ASSERT(confirm_const(&buf[0], fixed_offset + offset, 0xff));
533 CPPUNIT_ASSERT(confirm_seq(&buf[fixed_offset + offset], len, starting_val));
536 CPPUNIT_ASSERT(confirm_const(&buf[fixed_offset + offset + len],
537 buf_len - fixed_offset - offset - len, 0xff));
539 mgr->free_job_desc(jd);
543 // Test all "put" alignments and sizes
546 qa_job_manager::t10_body()
548 gc_job_manager_sptr mgr;
550 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
552 mgr = gc_make_job_manager(&opts);
554 int starting_val = 13;
556 for (int offset = 0; offset <= 128; offset++){
557 for (int len = 0; len <= 128; len++){
558 test_put_seq(mgr, offset, len, starting_val++);
562 int ea_args_maxsize = mgr->ea_args_maxsize();
564 // confirm maximum length
565 for (int offset = 0; offset <= 64; offset++){
566 test_put_seq(mgr, offset, ea_args_maxsize, starting_val++);
571 // test "put" args too long
574 qa_job_manager::t11_body()
576 gc_job_manager_sptr mgr;
578 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
580 mgr = gc_make_job_manager(&opts);
581 gc_job_desc *jd = mgr->alloc_job_desc();
582 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
584 init_jd(jd, gcp_qa_put_seq);
586 jd->input.arg[0].s32 = 0;
588 jd->eaa.arg[0].ea_addr = 0;
589 jd->eaa.arg[0].direction = GCJD_DMA_PUT;
590 jd->eaa.arg[0].put_size = 1 << 20;
592 if (!mgr->submit_job(jd)){
593 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
597 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
600 mgr->free_job_desc(jd);
604 // test MAX_ARGS_EA "put" case
607 qa_job_manager::t12_body()
609 static const int N = 127;
610 static const int M = 201;
611 gc_job_manager_sptr mgr;
613 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
615 mgr = gc_make_job_manager(&opts);
616 gc_job_desc *jd = mgr->alloc_job_desc();
617 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
619 unsigned char *buf = (unsigned char *) short_buf;
620 size_t buf_len = sizeof(short_buf);
621 memset(buf, 0xff, buf_len);
623 // two cache lines into the buffer, so we can check before and after
624 int fixed_offset = 256;
626 int starting_val = 13;
628 init_jd(jd, gcp_qa_put_seq);
630 jd->input.arg[0].s32 = starting_val;
631 jd->eaa.nargs = MAX_ARGS_EA;
632 for (int i = 0; i < MAX_ARGS_EA; i++){
633 jd->eaa.arg[i].direction = GCJD_DMA_PUT;
634 jd->eaa.arg[i].ea_addr = ptr_to_ea(&buf[i * M + fixed_offset]);
635 jd->eaa.arg[i].put_size = N;
638 if (!mgr->submit_job(jd)){
639 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
643 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
644 for (int i = 0; i < MAX_ARGS_EA; i++){
645 CPPUNIT_ASSERT(confirm_seq(&buf[i * M + fixed_offset], N, starting_val));
650 mgr->free_job_desc(jd);
654 // test qa_copy primitive
657 qa_job_manager::t13_body()
659 gc_job_manager_sptr mgr;
661 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
663 mgr = gc_make_job_manager(&opts);
665 memset(short_buf, 0, sizeof(short_buf));
666 for (int i = 0; i < NS/2; i++) // init buffer with known qty
667 short_buf[i] = 0x1234 + i;
671 gc_job_desc *jd = mgr->alloc_job_desc();
672 gc_proc_id_t gcp_qa_copy = mgr->lookup_proc("qa_copy");
675 printf("gcq_qa_copy = %d\n", gcp_qa_copy);
676 std::vector<std::string> procs = mgr->proc_names();
677 for (unsigned int i = 0; i < procs.size(); ++i)
678 std::cout << procs[i] << std::endl;
681 init_jd(jd, gcp_qa_copy);
683 jd->eaa.arg[0].ea_addr = ptr_to_ea(&short_buf[nshorts]);
684 jd->eaa.arg[0].direction = GCJD_DMA_PUT;
685 jd->eaa.arg[0].put_size = nshorts * sizeof(short);
687 jd->eaa.arg[1].ea_addr = ptr_to_ea(&short_buf[0]);
688 jd->eaa.arg[1].direction = GCJD_DMA_GET;
689 jd->eaa.arg[1].get_size = nshorts * sizeof(short);
692 if (!mgr->submit_job(jd)){
693 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
697 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
698 CPPUNIT_ASSERT_EQUAL(0, jd->output.arg[0].s32);
701 for (int i = 0; i < nshorts; i++){
702 if (short_buf[i] != short_buf[i + nshorts])
707 mgr->free_job_desc(jd);
711 * Parallel submission of NJOBS "put" jobs will test double buffered puts.
714 qa_job_manager::t14_body()
718 //static const int NJOBS = 64;
719 static const int NJOBS = 128;
720 static const int LEN_PER_JOB = 1021;
721 unsigned char buf[NJOBS * LEN_PER_JOB];
722 gc_job_desc_t *jd[NJOBS];
725 static const int STARTING_VAL = 13;
727 memset(buf, 0xff, LEN_PER_JOB * NJOBS);
729 gc_job_manager_sptr mgr;
731 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
733 mgr = gc_make_job_manager(&opts);
736 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
738 // do all the initialization up front
740 for (int i = 0, val = STARTING_VAL; i < NJOBS; i++, val += 3){
741 jd[i] = mgr->alloc_job_desc();
742 init_jd(jd[i], gcp_qa_put_seq);
743 jd[i]->input.nargs = 1;
744 jd[i]->input.arg[0].s32 = val;
745 jd[i]->eaa.nargs = 1;
746 jd[i]->eaa.arg[0].ea_addr = ptr_to_ea(&buf[i * LEN_PER_JOB]);
747 jd[i]->eaa.arg[0].direction = GCJD_DMA_PUT;
748 jd[i]->eaa.arg[0].put_size = LEN_PER_JOB;
753 for (int i = 0; i < NJOBS; i++){
754 if (!mgr->submit_job(jd[i])){
755 printf("%d: submit_job(jd[%2d]) failed, status = %d\n", __LINE__, i, jd[i]->status);
761 int n = mgr->wait_jobs(NJOBS, jd, done, GC_WAIT_ALL);
762 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
766 for (int i = 0, val = STARTING_VAL; i < NJOBS; i++, val += 3){
767 CPPUNIT_ASSERT_EQUAL(JS_OK, jd[i]->status);
768 CPPUNIT_ASSERT(confirm_seq(&buf[i * LEN_PER_JOB], LEN_PER_JOB, val));
772 for (int i = 0; i < NJOBS; i++)
773 mgr->free_job_desc(jd[i]);
777 qa_job_manager::t15_body()
780 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa);
782 gc_job_manager_sptr mgr = gc_make_job_manager(&opts);
784 gc_job_manager::set_singleton(mgr);
786 CPPUNIT_ASSERT(gc_job_manager::singleton());
788 CPPUNIT_ASSERT_THROW(gc_job_manager::singleton(), boost::bad_weak_ptr);