#include "qa_utils.h" #include #include #include #include //#include #include #include #include //#include //#include #include #include #include #include float uniform() { return 2.0 * ((float) rand() / RAND_MAX - 0.5); // uniformly (-1, 1) } void random_floats (float *buf, unsigned n) { for (unsigned i = 0; i < n; i++) buf[i] = uniform (); } void load_random_data(void *data, std::string sig, unsigned int n) { if(sig == "32fc") { random_floats((float *)data, n*2); } else if(sig == "32f") { random_floats((float *)data, n); } else if(sig == "32u") { for(int i=0; i((RAND_MAX/2))) * 32768.0)); } else if(sig == "16sc") { for(int i=0; i((RAND_MAX/2))) * 32768.0)); } else if(sig == "8u") { for(int i=0; i((RAND_MAX/2)) * 256.0)); } else if(sig == "8s") { for(int i=0; i((RAND_MAX/2)) * 128.0)); } else std::cout << "load_random_data(): Invalid sig: " << sig << std::endl; } template t *make_aligned_buffer(unsigned int len) { t *buf; int ret; ret = posix_memalign((void**)&buf, 16, len * sizeof(t)); assert(ret == 0); return buf; } void make_buffer_for_signature(std::vector &buffs, std::vector inputsig, unsigned int vlen) { BOOST_FOREACH(std::string sig, inputsig) { if (sig=="32fc" || sig=="64f" || sig=="64u") buffs.push_back((void *) make_aligned_buffer(vlen)); else if(sig=="32f" || sig=="32u" || sig=="32s" || sig=="16sc") buffs.push_back((void *) make_aligned_buffer(vlen)); else if(sig=="16s" || sig=="16u" || sig=="8sc") buffs.push_back((void *) make_aligned_buffer(vlen)); else if(sig=="8s" || sig=="8u") buffs.push_back((void *) make_aligned_buffer(vlen)); else std::cout << "Invalid type: " << sig << std::endl; } } static std::vector get_arch_list(const int archs[]) { std::vector archlist; int num_archs = archs[0]; //there has got to be a way to query these arches for(int i = 0; i < num_archs; i++) { switch(archs[i+1]) { case (1< valid_types = boost::assign::list_of("64f")("64u")("32fc")("32f")("32s")("32u")("16sc")("16s")("16u")("8s")("8sc")("8u"); BOOST_FOREACH(std::string this_type, valid_types) { if(type == this_type) return true; } return false; } static void get_function_signature(std::vector &inputsig, std::vector &outputsig, std::string name) { boost::char_separator sep("_"); boost::tokenizer > tok(name, sep); std::vector toked; tok.assign(name); toked.assign(tok.begin(), tok.end()); assert(toked[0] == "volk"); inputsig.push_back(toked[1]); //mandatory int pos = 2; bool valid_type = true; while(valid_type && pos < toked.size()) { if(is_valid_type(toked[pos])) inputsig.push_back(toked[pos]); else valid_type = false; pos++; } while(!valid_type && pos < toked.size()) { if(is_valid_type(toked[pos])) valid_type = true; else pos++; } while(valid_type && pos < toked.size()) { if(is_valid_type(toked[pos])) outputsig.push_back(toked[pos]); else valid_type = false; pos++; } //if there's no output sig and only one input sig, assume there are 2 inputs //this handles conversion fn's (which have a specified output sig) and most of the rest if(outputsig.size() == 0 && inputsig.size() == 1) { outputsig.push_back(inputsig[0]); inputsig.push_back(inputsig[0]); }//if there's no explicit output sig then assume the output is the same as the first input else if(outputsig.size() == 0) outputsig.push_back(inputsig[0]); assert(inputsig.size() != 0); assert(outputsig.size() != 0); } inline void run_cast_test2(volk_fn_2arg func, void *outbuff, std::vector &inbuffs, unsigned int vlen, unsigned int iter, std::string arch) { while(iter--) func(outbuff, inbuffs[0], vlen, arch.c_str()); } inline void run_cast_test3(volk_fn_3arg func, void *outbuff, std::vector &inbuffs, unsigned int vlen, unsigned int iter, std::string arch) { while(iter--) func(outbuff, inbuffs[0], inbuffs[1], vlen, arch.c_str()); } inline void run_cast_test4(volk_fn_4arg func, void *outbuff, std::vector &inbuffs, unsigned int vlen, unsigned int iter, std::string arch) { while(iter--) func(outbuff, inbuffs[0], inbuffs[1], inbuffs[2], vlen, arch.c_str()); } bool run_volk_tests(const int archs[], void (*manual_func)(), std::string name, float tol, int vlen, int iter) { std::cout << "RUN_VOLK_TESTS: " << name << std::endl; //first let's get a list of available architectures for the test std::vector arch_list = get_arch_list(archs); BOOST_FOREACH(std::string arch, arch_list) { std::cout << "Found an arch: " << arch << std::endl; } //now we have to get a function signature by parsing the name std::vector inputsig, outputsig; get_function_signature(inputsig, outputsig, name); for(int i=0; i inbuffs; make_buffer_for_signature(inbuffs, inputsig, vlen); //and set the input buffers to something random for(int i=0; i outbuffs; BOOST_FOREACH(std::string arch, arch_list) { make_buffer_for_signature(outbuffs, outputsig, vlen); } //now run the test clock_t start, end; for(int i = 0; i < arch_list.size(); i++) { start = clock(); switch(outputsig.size()+inputsig.size()) { case 2: run_cast_test2((volk_fn_2arg)(manual_func), outbuffs[i], inbuffs, vlen, iter, arch_list[i]); break; case 3: run_cast_test3((volk_fn_3arg)(manual_func), outbuffs[i], inbuffs, vlen, iter, arch_list[i]); break; case 4: run_cast_test4((volk_fn_4arg)(manual_func), outbuffs[i], inbuffs, vlen, iter, arch_list[i]); break; default: break; } end = clock(); std::cout << arch_list[i] << " completed in " << (double)(end-start)/(double)CLOCKS_PER_SEC << "s" << std::endl; } //and now compare each output to the generic output //first we have to know which output is the generic one, they aren't in order... int generic_offset; for(int i=0; i tol) { std::cout << "Generic: " << ((float *)(outbuffs[generic_offset]))[j] << " " << arch_list[i] << ": " << ((float *)(outbuffs[i]))[j] << std::endl; return 1; } } } else if(outputsig[0] == "32f") { for(int j=0; j tol) { std::cout << "Generic: " << ((float *)(outbuffs[generic_offset]))[j] << " " << arch_list[i] << ": " << ((float *)(outbuffs[i]))[j] << std::endl; return 1; } } } else if(outputsig[0] == "32u" || outputsig[0] == "32s" || outputsig[0] == "16sc") { for(int j=0; j