|  | 
|  | 1 | +#include <iostream> | 
|  | 2 | +#include <limits> | 
|  | 3 | +#include <sdsl/vectors.hpp> | 
|  | 4 | +#include <sdsl/coder.hpp> | 
|  | 5 | +  | 
|  | 6 | +/**** Benchmark for self - delimiting codes *********************************** | 
|  | 7 | +For information about usage of this benchmark, see displayUsage - function. | 
|  | 8 | +
 | 
|  | 9 | +To compile this benchmark, the following macros have to be defined  | 
|  | 10 | +(e.g. by passing them to compiler): | 
|  | 11 | +- VTYPES: a comma - separated list of sdsl vector types to be testet, | 
|  | 12 | +	e.g. vlc_vector<coder::elias_gamma>,vlc_vector<coder::elias_delta> | 
|  | 13 | +- VNAMES: symbolic names of the corresponding vector types, in same order  | 
|  | 14 | +	as in macro VTYPES, defined as a character array. | 
|  | 15 | +	According to the upper sample on macro VTYPES, VNAMES could be defined as | 
|  | 16 | +	{"VLC Vector with Elias Gamma Coder","VLC Vector with Elias Delta Coder"} | 
|  | 17 | +*/ | 
|  | 18 | + | 
|  | 19 | + | 
|  | 20 | +//assert that needed macros are defined | 
|  | 21 | +#ifndef VTYPES | 
|  | 22 | +#error "Macro VTYPES with comma - separated list of vector types has to be \ | 
|  | 23 | +	defined for compiling benchmark" | 
|  | 24 | +#endif | 
|  | 25 | +
 | 
|  | 26 | +#ifndef VNAMES | 
|  | 27 | +#error "Macro VNAMES with an array of characters has to be \ | 
|  | 28 | +	defined for compiling benchmark" | 
|  | 29 | +#endif | 
|  | 30 | +
 | 
|  | 31 | +using namespace std; | 
|  | 32 | +using namespace sdsl; | 
|  | 33 | +using namespace std::chrono; | 
|  | 34 | +using timer = std::chrono::high_resolution_clock; | 
|  | 35 | +
 | 
|  | 36 | +const char *(vectornames[]) = VNAMES; | 
|  | 37 | +const size_t vectorcount = sizeof(vectornames) / sizeof(vectornames[0]); | 
|  | 38 | +
 | 
|  | 39 | +struct iv_testresult { //testcase for one defined int vector | 
|  | 40 | +	double enc_MBperSec; //encoding rate: megabytes per second | 
|  | 41 | +	double dec_MBperSec; //decoding rate: megabytes per second | 
|  | 42 | +	double comp_percent; //compression rate: needed space in percentage compared | 
|  | 43 | +			//to original integer vector | 
|  | 44 | +}; | 
|  | 45 | +
 | 
|  | 46 | +//benchmark method declaration | 
|  | 47 | +template<class... Vectors> //used vectors for benchmark | 
|  | 48 | +bool runTestcase( const int_vector<> &iv, iv_testresult *result ); | 
|  | 49 | +
 | 
|  | 50 | +//stuff for nice printing | 
|  | 51 | +void displayUsage(const char *pname); | 
|  | 52 | +void displayHeading(); | 
|  | 53 | +void displayResult( const char *testcase, const iv_testresult *result ); | 
|  | 54 | +
 | 
|  | 55 | +int main(const int argc, const char **argv) | 
|  | 56 | +{ | 
|  | 57 | +	//check args | 
|  | 58 | +	if ((argc - 1) % 3 != 0) { | 
|  | 59 | +		displayUsage(argv[0]); | 
|  | 60 | +		return 1; | 
|  | 61 | +	} | 
|  | 62 | +
 | 
|  | 63 | +	//set up needed structures | 
|  | 64 | +	const size_t testcasecount = (argc - 1) / 3; | 
|  | 65 | +	iv_testresult overallresult[vectorcount]; | 
|  | 66 | +	 | 
|  | 67 | +	//prepare overall result | 
|  | 68 | +	for (size_t i = 0; i < vectorcount; i++) { | 
|  | 69 | +		overallresult[i].enc_MBperSec = 0.0; | 
|  | 70 | +		overallresult[i].dec_MBperSec = 0.0; | 
|  | 71 | +		overallresult[i].comp_percent = 0.0; | 
|  | 72 | +	} | 
|  | 73 | +
 | 
|  | 74 | +	//start fetching test cases and run benchmark | 
|  | 75 | +	displayHeading(); | 
|  | 76 | +	for (size_t i = 0; i < testcasecount; i++) { | 
|  | 77 | +		const char *testcase = argv[3*i + 1]; | 
|  | 78 | +		const char *file =     argv[3*i + 2]; //file of saved vector | 
|  | 79 | +		const char *type =     argv[3*i + 3]; //type of saved vector | 
|  | 80 | +		uint8_t v_type = type[0]=='d' ? 'd' : type[0] - '0'; | 
|  | 81 | +
 | 
|  | 82 | +		//load vector | 
|  | 83 | +		int_vector<> iv; | 
|  | 84 | +		if (!load_vector_from_file(iv, file, v_type)) { | 
|  | 85 | +			cerr << "ERROR: vector from file " << file  | 
|  | 86 | +			     << " with type " << type << " could not be loaded"  | 
|  | 87 | +			     << endl; | 
|  | 88 | +			displayUsage(argv[0]); | 
|  | 89 | +			return 1; | 
|  | 90 | +		} | 
|  | 91 | +
 | 
|  | 92 | +		//run test | 
|  | 93 | +		iv_testresult result[vectorcount]; | 
|  | 94 | +		if (!runTestcase<VTYPES>( iv, result )) { | 
|  | 95 | +			cerr << "Testcase " << testcase << "failed" << endl; | 
|  | 96 | +			return 1; | 
|  | 97 | +		} | 
|  | 98 | +
 | 
|  | 99 | +		//print result | 
|  | 100 | +		displayResult( testcase, result ); | 
|  | 101 | +
 | 
|  | 102 | +		//and sum up results for overall result | 
|  | 103 | +		for (size_t j = 0; j < vectorcount; j++) { | 
|  | 104 | +			overallresult[j].enc_MBperSec += result[j].enc_MBperSec; | 
|  | 105 | +			overallresult[j].dec_MBperSec += result[j].dec_MBperSec; | 
|  | 106 | +			overallresult[j].comp_percent += result[j].comp_percent; | 
|  | 107 | +		} | 
|  | 108 | +	} | 
|  | 109 | +
 | 
|  | 110 | +	//build average for overall result | 
|  | 111 | +	for (size_t i = 0; i < vectorcount; i++) { | 
|  | 112 | +		overallresult[i].enc_MBperSec /= testcasecount; | 
|  | 113 | +		overallresult[i].dec_MBperSec /= testcasecount; | 
|  | 114 | +		overallresult[i].comp_percent /= testcasecount; | 
|  | 115 | +	} | 
|  | 116 | +
 | 
|  | 117 | +	//and display overall results | 
|  | 118 | +	displayResult( "Overall", overallresult ); | 
|  | 119 | +	return 0; | 
|  | 120 | +} | 
|  | 121 | +
 | 
|  | 122 | +//// BENCHMARK METHODS //////////////////////////////////////////////////////// | 
|  | 123 | +template<class Vector> //used compression vector type | 
|  | 124 | +bool runSingleTest( const int_vector<> &testcase, iv_testresult &result ) { | 
|  | 125 | +	//test encoding rate by constructing Vector | 
|  | 126 | +	auto start = timer::now(); | 
|  | 127 | +	Vector test( testcase ); | 
|  | 128 | +	auto stop = timer::now(); | 
|  | 129 | +	result.enc_MBperSec = size_in_mega_bytes( testcase ) | 
|  | 130 | +		 / duration_cast<seconds>(stop-start).count(); | 
|  | 131 | +
 | 
|  | 132 | +	//care for compression rate | 
|  | 133 | +	result.comp_percent = size_in_mega_bytes(test)  | 
|  | 134 | +		/ size_in_mega_bytes(testcase) * 100.0; | 
|  | 135 | +
 | 
|  | 136 | +	//and finally for decoding rate | 
|  | 137 | +	//use a trick to decode all values: since (currently) all vectors are | 
|  | 138 | +	//using sample tables, access the element right before the next sampling | 
|  | 139 | +	//entry, so everything between 2 samples has to be decoded. | 
|  | 140 | +	size_t sample_dens = test.get_sample_dens(); | 
|  | 141 | +	start = timer::now(); | 
|  | 142 | +	//repeat test 5 times to avoid infinite decoding rates | 
|  | 143 | +	for (size_t j = 0; j < 5; j++) { | 
|  | 144 | +		size_t i = sample_dens - 1; | 
|  | 145 | +		for (; i < test.size(); i += sample_dens) { | 
|  | 146 | +			test[i]; //acess element right before next sample entry | 
|  | 147 | +		} | 
|  | 148 | +		//and finally access last element if not done yet | 
|  | 149 | +		if (i != test.size() + sample_dens - 1) | 
|  | 150 | +			test[test.size() - 1]; | 
|  | 151 | +	} | 
|  | 152 | +	stop = timer::now(); | 
|  | 153 | +	result.dec_MBperSec = size_in_mega_bytes( testcase ) | 
|  | 154 | +		 / duration_cast<seconds>(stop-start).count()  | 
|  | 155 | +		* 5.0; //multiply with 5 since vector was decoded 5 times | 
|  | 156 | +
 | 
|  | 157 | +	return true; //may use this return type for error detection in future | 
|  | 158 | +} | 
|  | 159 | +
 | 
|  | 160 | +template<class... Vectors> //used vectors for benchmark | 
|  | 161 | +bool runTestcase( const int_vector<> &testcase, iv_testresult *result ) { | 
|  | 162 | +	size_t i = 0; | 
|  | 163 | +	//do variadic template pack expansion | 
|  | 164 | +	bool testfine[] = { runSingleTest<Vectors>( testcase, result[i++] )... }; | 
|  | 165 | +	bool testsfine = true; | 
|  | 166 | +	for (i = 0; i < vectorcount; i++) { | 
|  | 167 | +		if (!testfine[i]) { | 
|  | 168 | +			cerr << "Test on Vector " << vectornames[i] | 
|  | 169 | +			     << "failed" << endl; | 
|  | 170 | +			testsfine = false; | 
|  | 171 | +		} | 
|  | 172 | +	} | 
|  | 173 | +	return testsfine;	 | 
|  | 174 | +} | 
|  | 175 | +
 | 
|  | 176 | +//// DISPLAYING OF RESULTS //////////////////////////////////////////////////// | 
|  | 177 | +
 | 
|  | 178 | +void displayUsage(const char *pname) { | 
|  | 179 | +	cerr << "USAGE: " << pname << " [testcase file vectortype]*" | 
|  | 180 | +	     << endl; | 
|  | 181 | +	cerr << "DESCRIPTION:" << endl; | 
|  | 182 | +	cerr << "\tThis Program runs a benchmark on self-delimiting " | 
|  | 183 | +                    << "Codes." << endl; | 
|  | 184 | +	cerr << "\tProgram needs triples of parameters " | 
|  | 185 | +	     << "for each test case, see Parameter section." << endl; | 
|  | 186 | +	cerr << "\tProgram will test a couple of compression vectors "  | 
|  | 187 | +	     << endl | 
|  | 188 | +	     << "\ton measured encoding and decoding rates," << endl | 
|  | 189 | +	     << "\tplus the compression rate in percent "  | 
|  | 190 | +	     << "(compared to the original integer vector)" << endl | 
|  | 191 | +	     << "\tfor each testcase."  | 
|  | 192 | +	     << endl | 
|  | 193 | +	     << "\tAdditionally, an overall result on different "  | 
|  | 194 | +	     << endl << "\tcompression vectors is printed." << endl; | 
|  | 195 | +	cerr << "\tThe generated output uses a CSV format, so "  | 
|  | 196 | +	     << "you may save it to a csv file for better visability" | 
|  | 197 | +	     << endl << "\tand other utilites." << endl; | 
|  | 198 | +	cerr << "PARAMETERS: The parameters have to be passed as " | 
|  | 199 | +	     << " triples for each test case." << endl | 
|  | 200 | +	     << "\tA Triple consist of " << endl | 
|  | 201 | +	     << "\t\t- testcase: A name for the test case" << endl | 
|  | 202 | +	     << "\t\t- file: a path to the file where the test case" << endl | 
|  | 203 | +	     << "\t\t\t(an integer vector) is contained" << endl | 
|  | 204 | +	     << "\t\t- vectortype: type of saved integer vector" << endl | 
|  | 205 | +	     << "\t\t\t0: serialized int_vector<>" << endl | 
|  | 206 | +	     << "\t\t\t1: byte sequence" << endl | 
|  | 207 | +	     << "\t\t\t2: 16-bit word sequence" << endl | 
|  | 208 | +	     << "\t\t\t4: 32-bit word sequence" << endl | 
|  | 209 | +	     << "\t\t\t8: 64-bit word sequence" << endl | 
|  | 210 | +	     << "\t\t\td: Parse decimal numbers" << endl; | 
|  | 211 | +	cerr << "TESTET COMPRESSION VECTORS:" << endl; | 
|  | 212 | +	for (size_t i = 0; i < vectorcount; i++) { | 
|  | 213 | +		cerr << "\t- " << vectornames[i] << endl; | 
|  | 214 | +	} | 
|  | 215 | +} | 
|  | 216 | +void displayHeading() { | 
|  | 217 | +	cout << left; //left justify | 
|  | 218 | +	//add a comment how to read values | 
|  | 219 | +	cout << "# encoding / decoding rate unit: MB/s" << endl; | 
|  | 220 | +	cout << "# compression : percentage of needed space " | 
|  | 221 | +	     << " compared to original vector" << endl; | 
|  | 222 | +	//and print a header for csv output | 
|  | 223 | +	cout << setw(20) << "testcase"  | 
|  | 224 | +	     << setw(1) << ";" << setw(20) << "vector" | 
|  | 225 | +	     << setw(1) << ";" << setw(20) << "encodingrate" | 
|  | 226 | +	     << setw(1) << ";" << setw(20) << "decodingrate" | 
|  | 227 | +	     << setw(1) << ";" << "compressionrate" << endl; | 
|  | 228 | +} | 
|  | 229 | +
 | 
|  | 230 | +void displayResult( const char *testcase, const iv_testresult *result ) { | 
|  | 231 | +	cout << left << fixed; //prepare cout | 
|  | 232 | +	for (size_t i = 0; i < vectorcount; i++) { | 
|  | 233 | +		cout << setw(20) << testcase  | 
|  | 234 | +		     << setw(1) << ";" << setw(20) << vectornames[i] | 
|  | 235 | +		     << setw(1) << ";" << setw(20) << result[i].enc_MBperSec | 
|  | 236 | +		     << setw(1) << ";" << setw(20) << result[i].dec_MBperSec | 
|  | 237 | +		     << setw(1) << ";" << result[i].comp_percent << endl; | 
|  | 238 | +	} | 
|  | 239 | +} | 
0 commit comments