summaryrefslogtreecommitdiff
path: root/volk/lib/qa_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'volk/lib/qa_utils.cc')
-rw-r--r--volk/lib/qa_utils.cc223
1 files changed, 223 insertions, 0 deletions
diff --git a/volk/lib/qa_utils.cc b/volk/lib/qa_utils.cc
new file mode 100644
index 000000000..4d93ca62a
--- /dev/null
+++ b/volk/lib/qa_utils.cc
@@ -0,0 +1,223 @@
+#include "qa_utils.h"
+#include <stdlib.h>
+#include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <vector>
+#include <time.h>
+//#include <math.h>
+//#include <volk/volk_runtime.h>
+#include <volk/volk_registry.h>
+#include <volk/volk.h>
+#include <boost/typeof/typeof.hpp>
+#include <boost/type_traits.hpp>
+//#include <boost/test/unit_test.hpp>
+
+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 ();
+}
+
+template <class t>
+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<void *> &buffs, std::vector<std::string> inputsig, unsigned int vlen) {
+ BOOST_FOREACH(std::string sig, inputsig) {
+ if (sig=="32fc" || sig=="64f") buffs.push_back((void *) make_aligned_buffer<lv_32fc_t>(vlen));
+ else if(sig=="32f" || sig=="32u" || sig=="32s" || sig=="16sc") buffs.push_back((void *) make_aligned_buffer<float>(vlen));
+ else if(sig=="16s" || sig=="16u") buffs.push_back((void *) make_aligned_buffer<int16_t>(vlen));
+ else if(sig=="8s" || sig=="8u") buffs.push_back((void *) make_aligned_buffer<int8_t>(vlen));
+ else std::cout << "Invalid type!" << std::endl;
+ }
+}
+
+static std::vector<std::string> get_arch_list(const int archs[]) {
+ std::vector<std::string> 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<<LV_GENERIC):
+ archlist.push_back("generic");
+ break;
+ case (1<<LV_ORC):
+ archlist.push_back("orc");
+ break;
+ case (1<<LV_SSE):
+ archlist.push_back("sse");
+ break;
+ case (1<<LV_SSE2):
+ archlist.push_back("sse2");
+ break;
+ case (1<<LV_SSSE3):
+ archlist.push_back("ssse3");
+ break;
+ case (1<<LV_SSE4_1):
+ archlist.push_back("sse4_1");
+ break;
+ case (1<<LV_SSE4_2):
+ archlist.push_back("sse4_2");
+ break;
+ case (1<<LV_SSE4_A):
+ archlist.push_back("sse4_a");
+ break;
+ case (1<<LV_MMX):
+ archlist.push_back("mmx");
+ break;
+ case (1<<LV_AVX):
+ archlist.push_back("avx");
+ break;
+ default:
+ break;
+ }
+ }
+ return archlist;
+}
+
+static bool is_valid_type(std::string type) {
+ std::vector<std::string> valid_types = boost::assign::list_of("32fc")("32f")("32s")("32u")("16sc")("16s")("16u")("8s")("8u");
+
+ BOOST_FOREACH(std::string this_type, valid_types) {
+ if(type == this_type) return true;
+ }
+ return false;
+}
+
+
+static void get_function_signature(std::vector<std::string> &inputsig,
+ std::vector<std::string> &outputsig,
+ std::string name) {
+ boost::char_separator<char> sep("_");
+ boost::tokenizer<boost::char_separator<char> > tok(name, sep);
+ std::vector<std::string> 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;
+ 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 explicit output sig then assume the output is the same as the first input
+ 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<void *> &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<void *> &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<void *> &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<std::string> 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<std::string> inputsig, outputsig;
+ get_function_signature(inputsig, outputsig, name);
+
+ for(int i=0; i<inputsig.size(); i++) std::cout << "Input: " << inputsig[i] << std::endl;
+ for(int i=0; i<outputsig.size(); i++) std::cout << "Output: " << outputsig[i] << std::endl;
+
+ //now that we have that, we'll set up input and output buffers based on the function signature
+ std::vector<void *> inbuffs;
+ make_buffer_for_signature(inbuffs, inputsig, vlen);
+
+ //and set the input buffers to something random
+ //TODO
+
+ //allocate output buffers -- one for each output for each arch
+ std::vector<void *> 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<arch_list.size(); i++)
+ if(arch_list[i] == "generic") generic_offset=i;
+
+ for(int i=0; i<arch_list.size(); i++) {
+ if(arch_list[i] != "generic") {
+ for(int j=0; i<vlen; j++) {
+ BOOST_CHECK_CLOSE(((float *)(outbuffs[generic_offset]))[j], ((float *)(outbuffs[i]))[j], tol);
+ }
+ }
+ }
+
+ BOOST_FOREACH(void *buf, inbuffs) {
+ free(buf);
+ }
+ BOOST_FOREACH(void *buf, outbuffs) {
+ free(buf);
+ }
+ return 0;
+}
+
+