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 <gcell/gc_job_manager.h>
33 // handle to embedded SPU executable w/ QA routines
34 extern spe_program_handle_t gcell_runtime_qa_spx;
38 gc_msleep(unsigned long millisecs)
42 tv.tv_sec = millisecs / 1000;
43 tv.tv_nsec = (millisecs - (tv.tv_sec * 1000)) * 1000000;
46 r = nanosleep(&tv, &tv);
49 if (r == -1 && errno == EINTR)
58 qa_job_manager::leak_check(test_t t, const std::string &name)
60 struct mallinfo before, after;
66 size_t delta = after.uordblks - before.uordblks;
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);
78 //leak_check(&qa_job_manager::t1_body, "t1-0");
84 t1_body(); // leaks 800 bytes first time, could be one-time inits
85 leak_check(&qa_job_manager::t1_body, "t1");
91 leak_check(&qa_job_manager::t2_body, "t2");
97 t3_body(); // leaks first time only, could be cppunit
98 leak_check(&qa_job_manager::t3_body, "t3");
104 leak_check(&qa_job_manager::t4_body, "t4");
110 leak_check(&qa_job_manager::t5_body, "t5");
116 leak_check(&qa_job_manager::t6_body, "t6");
122 leak_check(&qa_job_manager::t7_body, "t7");
128 leak_check(&qa_job_manager::t8_body, "t8");
134 leak_check(&qa_job_manager::t9_body, "t9");
138 qa_job_manager::t10()
140 leak_check(&qa_job_manager::t10_body, "t10");
144 qa_job_manager::t11()
146 leak_check(&qa_job_manager::t11_body, "t11");
150 qa_job_manager::t12()
152 leak_check(&qa_job_manager::t12_body, "t12");
156 qa_job_manager::t13()
158 leak_check(&qa_job_manager::t13_body, "t13");
162 qa_job_manager::t14()
164 leak_check(&qa_job_manager::t14_body, "t14");
168 qa_job_manager::t15()
170 leak_check(&qa_job_manager::t15_body, "t15");
173 // ----------------------------------------------------------------
176 qa_job_manager::t1_body()
178 gc_job_manager_sptr mgr;
180 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
181 mgr = gc_make_job_manager(&opts);
185 qa_job_manager::t2_body()
187 gc_job_manager_sptr mgr;
189 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
191 opts.gang_schedule = false;
192 mgr = gc_make_job_manager(&opts);
196 qa_job_manager::t3_body()
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.
203 gc_job_manager_sptr mgr;
205 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
207 opts.gang_schedule = true;
208 CPPUNIT_ASSERT_THROW(mgr = gc_make_job_manager(&opts), std::out_of_range);
213 init_jd(gc_job_desc *jd, gc_proc_id_t proc_id)
215 jd->proc_id = proc_id;
217 jd->output.nargs = 0;
222 qa_job_manager::t4_body()
224 gc_job_manager_sptr mgr;
226 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
228 mgr = gc_make_job_manager(&opts);
229 //mgr->set_debug(-1);
230 static const int NJOBS = 32;
231 gc_job_desc *jds[NJOBS];
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);
237 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
238 CPPUNIT_ASSERT(gcp_qa_nop != GCP_UNKNOWN_PROC);
240 for (int i = 0; i < NJOBS; i++){
241 jds[i] = mgr->alloc_job_desc();
242 init_jd(jds[i], gcp_qa_nop);
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);
252 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
253 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
255 for (int i = 0; i < NJOBS; i++){
256 mgr->free_job_desc(jds[i]);
261 qa_job_manager::t5_body()
263 gc_job_manager_sptr mgr;
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];
273 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
275 for (int i = 0; i < NJOBS; i++){
276 jds[i] = mgr->alloc_job_desc();
277 init_jd(jds[i], gcp_qa_nop);
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);
287 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
288 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
290 for (int i = 0; i < NJOBS; i++){
291 mgr->free_job_desc(jds[i]);
296 qa_job_manager::t6_body()
298 gc_job_manager_sptr mgr;
300 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
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();
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);
314 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
317 // test for JS_UNKNOWN_PROC with bogus procedure
319 if (!mgr->submit_job(jd)){
320 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
324 CPPUNIT_ASSERT_EQUAL(JS_UNKNOWN_PROC, jd->status);
327 mgr->free_job_desc(jd);
331 sum_shorts(short *p, int nshorts)
334 for (int i = 0; i < nshorts; i++)
341 test_sum_shorts(gc_job_manager_sptr mgr, short *buf, int nshorts)
343 gc_job_desc *jd = mgr->alloc_job_desc();
344 gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
346 init_jd(jd, gcp_qa_sum_shorts);
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);
353 if (!mgr->submit_job(jd)){
354 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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);
364 mgr->free_job_desc(jd);
367 static const int NS = 32768;
368 static short short_buf[NS] _AL128; // for known alignment
371 // test all "get" alignments and sizes
374 qa_job_manager::t7_body()
376 gc_job_manager_sptr mgr;
378 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
380 mgr = gc_make_job_manager(&opts);
382 int ea_args_maxsize = mgr->ea_args_maxsize();
384 for (int i = 0; i < NS; i++) // init buffer with known qty
385 short_buf[i] = 0x1234 + i;
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);
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));
400 // test "get" args too long
403 qa_job_manager::t8_body()
405 gc_job_manager_sptr mgr;
407 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
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");
413 init_jd(jd, gcp_qa_sum_shorts);
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;
419 if (!mgr->submit_job(jd)){
420 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
424 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
427 mgr->free_job_desc(jd);
431 // test MAX_ARGS_EA "get" case
434 qa_job_manager::t9_body()
436 static const int N = 127;
437 static const int M = 201;
438 gc_job_manager_sptr mgr;
440 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
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");
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);
454 if (!mgr->submit_job(jd)){
455 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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);
467 mgr->free_job_desc(jd);
471 confirm_const(const unsigned char *buf, size_t len, unsigned char v)
475 for (size_t i = 0; i < len; i++){
478 printf("confirm_const: buf[%6d] = 0x%02x, expected = 0x%02x\n",
487 confirm_seq(const unsigned char *buf, size_t len, unsigned char v)
491 for (size_t i = 0; i < len; i++, v++){
494 printf("confirm_seq: buf[%6d] = 0x%02x, expected = 0x%02x\n",
503 test_put_seq(gc_job_manager_sptr mgr, int offset, int len, int starting_val)
505 gc_job_desc *jd = mgr->alloc_job_desc();
506 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
508 unsigned char *buf = (unsigned char *) short_buf;
509 size_t buf_len = sizeof(short_buf);
510 memset(buf, 0xff, buf_len);
512 // two cache lines into the buffer, so we can check before and after
513 int fixed_offset = 256;
515 init_jd(jd, gcp_qa_put_seq);
517 jd->input.arg[0].s32 = starting_val;
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;
523 if (!mgr->submit_job(jd)){
524 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
528 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
531 CPPUNIT_ASSERT(confirm_const(&buf[0], fixed_offset + offset, 0xff));
534 CPPUNIT_ASSERT(confirm_seq(&buf[fixed_offset + offset], len, starting_val));
537 CPPUNIT_ASSERT(confirm_const(&buf[fixed_offset + offset + len],
538 buf_len - fixed_offset - offset - len, 0xff));
540 mgr->free_job_desc(jd);
544 // Test all "put" alignments and sizes
547 qa_job_manager::t10_body()
549 gc_job_manager_sptr mgr;
551 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
553 mgr = gc_make_job_manager(&opts);
555 int starting_val = 13;
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++);
563 int ea_args_maxsize = mgr->ea_args_maxsize();
565 // confirm maximum length
566 for (int offset = 0; offset <= 64; offset++){
567 test_put_seq(mgr, offset, ea_args_maxsize, starting_val++);
572 // test "put" args too long
575 qa_job_manager::t11_body()
577 gc_job_manager_sptr mgr;
579 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
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");
585 init_jd(jd, gcp_qa_put_seq);
587 jd->input.arg[0].s32 = 0;
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;
593 if (!mgr->submit_job(jd)){
594 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
598 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
601 mgr->free_job_desc(jd);
605 // test MAX_ARGS_EA "put" case
608 qa_job_manager::t12_body()
610 static const int N = 127;
611 static const int M = 201;
612 gc_job_manager_sptr mgr;
614 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
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");
620 unsigned char *buf = (unsigned char *) short_buf;
621 size_t buf_len = sizeof(short_buf);
622 memset(buf, 0xff, buf_len);
624 // two cache lines into the buffer, so we can check before and after
625 int fixed_offset = 256;
627 int starting_val = 13;
629 init_jd(jd, gcp_qa_put_seq);
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;
639 if (!mgr->submit_job(jd)){
640 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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));
651 mgr->free_job_desc(jd);
655 // test qa_copy primitive
658 qa_job_manager::t13_body()
660 gc_job_manager_sptr mgr;
662 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
664 mgr = gc_make_job_manager(&opts);
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;
672 gc_job_desc *jd = mgr->alloc_job_desc();
673 gc_proc_id_t gcp_qa_copy = mgr->lookup_proc("qa_copy");
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;
682 init_jd(jd, gcp_qa_copy);
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);
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);
693 if (!mgr->submit_job(jd)){
694 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
698 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
699 CPPUNIT_ASSERT_EQUAL(0, jd->output.arg[0].s32);
702 for (int i = 0; i < nshorts; i++){
703 if (short_buf[i] != short_buf[i + nshorts])
708 mgr->free_job_desc(jd);
712 * Parallel submission of NJOBS "put" jobs will test double buffered puts.
715 qa_job_manager::t14_body()
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];
726 static const int STARTING_VAL = 13;
728 memset(buf, 0xff, LEN_PER_JOB * NJOBS);
730 gc_job_manager_sptr mgr;
732 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
734 mgr = gc_make_job_manager(&opts);
737 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
739 // do all the initialization up front
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;
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);
762 int n = mgr->wait_jobs(NJOBS, jd, done, GC_WAIT_ALL);
763 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
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));
773 for (int i = 0; i < NJOBS; i++)
774 mgr->free_job_desc(jd[i]);
778 qa_job_manager::t15_body()
781 opts.program_handle = gc_program_handle_from_address(&gcell_runtime_qa_spx);
783 gc_job_manager_sptr mgr = gc_make_job_manager(&opts);
785 gc_job_manager::set_singleton(mgr);
787 CPPUNIT_ASSERT(gc_job_manager::singleton());
789 CPPUNIT_ASSERT_THROW(gc_job_manager::singleton(), boost::bad_weak_ptr);