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 extern spe_program_handle_t gcell_qa; // handle to embedded SPU executable w/ QA routines
36 gc_msleep(unsigned long millisecs)
40 tv.tv_sec = millisecs / 1000;
41 tv.tv_nsec = (millisecs - (tv.tv_sec * 1000)) * 1000000;
44 r = nanosleep(&tv, &tv);
47 if (r == -1 && errno == EINTR)
56 qa_job_manager::leak_check(test_t t, const std::string &name)
58 struct mallinfo before, after;
64 size_t delta = after.uordblks - before.uordblks;
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);
76 //leak_check(&qa_job_manager::t1_body, "t1-0");
82 t1_body(); // leaks 800 bytes first time, could be one-time inits
83 leak_check(&qa_job_manager::t1_body, "t1");
89 leak_check(&qa_job_manager::t2_body, "t2");
95 t3_body(); // leaks first time only, could be cppunit
96 leak_check(&qa_job_manager::t3_body, "t3");
102 leak_check(&qa_job_manager::t4_body, "t4");
108 leak_check(&qa_job_manager::t5_body, "t5");
114 leak_check(&qa_job_manager::t6_body, "t6");
120 leak_check(&qa_job_manager::t7_body, "t7");
126 leak_check(&qa_job_manager::t8_body, "t8");
132 leak_check(&qa_job_manager::t9_body, "t9");
136 qa_job_manager::t10()
138 leak_check(&qa_job_manager::t10_body, "t10");
142 qa_job_manager::t11()
144 leak_check(&qa_job_manager::t11_body, "t11");
148 qa_job_manager::t12()
150 leak_check(&qa_job_manager::t12_body, "t12");
154 qa_job_manager::t13()
156 leak_check(&qa_job_manager::t13_body, "t13");
160 qa_job_manager::t14()
162 leak_check(&qa_job_manager::t14_body, "t14");
166 qa_job_manager::t15()
168 leak_check(&qa_job_manager::t15_body, "t15");
171 // ----------------------------------------------------------------
174 qa_job_manager::t1_body()
178 opts.program_handle = &gcell_qa;
179 mgr = gc_make_job_manager(&opts);
184 qa_job_manager::t2_body()
186 gc_job_manager *mgr = 0;
188 opts.program_handle = &gcell_qa;
190 opts.gang_schedule = false;
191 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 *mgr = 0;
205 opts.program_handle = &gcell_qa;
207 opts.gang_schedule = true;
208 CPPUNIT_ASSERT_THROW(mgr = gc_make_job_manager(&opts), std::out_of_range);
214 init_jd(gc_job_desc *jd, gc_proc_id_t proc_id)
216 jd->proc_id = proc_id;
218 jd->output.nargs = 0;
223 qa_job_manager::t4_body()
227 opts.program_handle = &gcell_qa;
229 mgr = gc_make_job_manager(&opts);
230 //mgr->set_debug(-1);
231 static const int NJOBS = 32;
232 gc_job_desc *jds[NJOBS];
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);
238 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
239 CPPUNIT_ASSERT(gcp_qa_nop != GCP_UNKNOWN_PROC);
241 for (int i = 0; i < NJOBS; i++){
242 jds[i] = mgr->alloc_job_desc();
243 init_jd(jds[i], gcp_qa_nop);
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);
253 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
254 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
256 for (int i = 0; i < NJOBS; i++){
257 mgr->free_job_desc(jds[i]);
264 qa_job_manager::t5_body()
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];
276 gc_proc_id_t gcp_qa_nop = mgr->lookup_proc("qa_nop");
278 for (int i = 0; i < NJOBS; i++){
279 jds[i] = mgr->alloc_job_desc();
280 init_jd(jds[i], gcp_qa_nop);
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);
290 int n = mgr->wait_jobs(NJOBS, jds, done, GC_WAIT_ALL);
291 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
293 for (int i = 0; i < NJOBS; i++){
294 mgr->free_job_desc(jds[i]);
301 qa_job_manager::t6_body()
305 opts.program_handle = &gcell_qa;
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();
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);
319 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
322 // test for JS_UNKNOWN_PROC with bogus procedure
324 if (!mgr->submit_job(jd)){
325 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
329 CPPUNIT_ASSERT_EQUAL(JS_UNKNOWN_PROC, jd->status);
332 mgr->free_job_desc(jd);
337 sum_shorts(short *p, int nshorts)
340 for (int i = 0; i < nshorts; i++)
347 test_sum_shorts(gc_job_manager *mgr, short *buf, int nshorts)
349 gc_job_desc *jd = mgr->alloc_job_desc();
350 gc_proc_id_t gcp_qa_sum_shorts = mgr->lookup_proc("qa_sum_shorts");
352 init_jd(jd, gcp_qa_sum_shorts);
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);
359 if (!mgr->submit_job(jd)){
360 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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);
370 mgr->free_job_desc(jd);
373 static const int NS = 32768;
374 static short short_buf[NS] _AL128; // for known alignment
377 // test all "get" alignments and sizes
380 qa_job_manager::t7_body()
384 opts.program_handle = &gcell_qa;
386 mgr = gc_make_job_manager(&opts);
388 int ea_args_maxsize = mgr->ea_args_maxsize();
390 for (int i = 0; i < NS; i++) // init buffer with known qty
391 short_buf[i] = 0x1234 + i;
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);
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));
408 // test "get" args too long
411 qa_job_manager::t8_body()
415 opts.program_handle = &gcell_qa;
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");
421 init_jd(jd, gcp_qa_sum_shorts);
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;
427 if (!mgr->submit_job(jd)){
428 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
432 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
435 mgr->free_job_desc(jd);
440 // test MAX_ARGS_EA "get" case
443 qa_job_manager::t9_body()
445 static const int N = 127;
446 static const int M = 201;
449 opts.program_handle = &gcell_qa;
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");
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);
463 if (!mgr->submit_job(jd)){
464 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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);
476 mgr->free_job_desc(jd);
481 confirm_const(const unsigned char *buf, size_t len, unsigned char v)
485 for (size_t i = 0; i < len; i++){
488 printf("confirm_const: buf[%6d] = 0x%02x, expected = 0x%02x\n",
497 confirm_seq(const unsigned char *buf, size_t len, unsigned char v)
501 for (size_t i = 0; i < len; i++, v++){
504 printf("confirm_seq: buf[%6d] = 0x%02x, expected = 0x%02x\n",
513 test_put_seq(gc_job_manager *mgr, int offset, int len, int starting_val)
515 gc_job_desc *jd = mgr->alloc_job_desc();
516 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
518 unsigned char *buf = (unsigned char *) short_buf;
519 size_t buf_len = sizeof(short_buf);
520 memset(buf, 0xff, buf_len);
522 // two cache lines into the buffer, so we can check before and after
523 int fixed_offset = 256;
525 init_jd(jd, gcp_qa_put_seq);
527 jd->input.arg[0].s32 = starting_val;
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;
533 if (!mgr->submit_job(jd)){
534 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
538 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
541 CPPUNIT_ASSERT(confirm_const(&buf[0], fixed_offset + offset, 0xff));
544 CPPUNIT_ASSERT(confirm_seq(&buf[fixed_offset + offset], len, starting_val));
547 CPPUNIT_ASSERT(confirm_const(&buf[fixed_offset + offset + len],
548 buf_len - fixed_offset - offset - len, 0xff));
550 mgr->free_job_desc(jd);
554 // Test all "put" alignments and sizes
557 qa_job_manager::t10_body()
561 opts.program_handle = &gcell_qa;
563 mgr = gc_make_job_manager(&opts);
565 int starting_val = 13;
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++);
573 int ea_args_maxsize = mgr->ea_args_maxsize();
575 // confirm maximum length
576 for (int offset = 0; offset <= 64; offset++){
577 test_put_seq(mgr, offset, ea_args_maxsize, starting_val++);
584 // test "put" args too long
587 qa_job_manager::t11_body()
591 opts.program_handle = &gcell_qa;
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");
597 init_jd(jd, gcp_qa_put_seq);
599 jd->input.arg[0].s32 = 0;
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;
605 if (!mgr->submit_job(jd)){
606 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
610 CPPUNIT_ASSERT_EQUAL(JS_ARGS_TOO_LONG, jd->status);
613 mgr->free_job_desc(jd);
618 // test MAX_ARGS_EA "put" case
621 qa_job_manager::t12_body()
623 static const int N = 127;
624 static const int M = 201;
627 opts.program_handle = &gcell_qa;
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");
633 unsigned char *buf = (unsigned char *) short_buf;
634 size_t buf_len = sizeof(short_buf);
635 memset(buf, 0xff, buf_len);
637 // two cache lines into the buffer, so we can check before and after
638 int fixed_offset = 256;
640 int starting_val = 13;
642 init_jd(jd, gcp_qa_put_seq);
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;
652 if (!mgr->submit_job(jd)){
653 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
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));
664 mgr->free_job_desc(jd);
669 // test qa_copy primitive
672 qa_job_manager::t13_body()
676 opts.program_handle = &gcell_qa;
678 mgr = gc_make_job_manager(&opts);
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;
686 gc_job_desc *jd = mgr->alloc_job_desc();
687 gc_proc_id_t gcp_qa_copy = mgr->lookup_proc("qa_copy");
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;
696 init_jd(jd, gcp_qa_copy);
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);
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);
707 if (!mgr->submit_job(jd)){
708 printf("%d: submit_job(jd) failed, status = %d\n", __LINE__, jd->status);
712 CPPUNIT_ASSERT_EQUAL(JS_OK, jd->status);
713 CPPUNIT_ASSERT_EQUAL(0, jd->output.arg[0].s32);
716 for (int i = 0; i < nshorts; i++){
717 if (short_buf[i] != short_buf[i + nshorts])
722 mgr->free_job_desc(jd);
728 * Parallel submission of NJOBS "put" jobs will test double buffered puts.
731 qa_job_manager::t14_body()
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];
742 static const int STARTING_VAL = 13;
744 memset(buf, 0xff, LEN_PER_JOB * NJOBS);
748 opts.program_handle = &gcell_qa;
750 mgr = gc_make_job_manager(&opts);
753 gc_proc_id_t gcp_qa_put_seq = mgr->lookup_proc("qa_put_seq");
755 // do all the initialization up front
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;
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);
778 int n = mgr->wait_jobs(NJOBS, jd, done, GC_WAIT_ALL);
779 CPPUNIT_ASSERT_EQUAL(NJOBS, n);
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));
789 for (int i = 0; i < NJOBS; i++)
790 mgr->free_job_desc(jd[i]);
796 qa_job_manager::t15_body()