/* Standard Container Benchmark Version 0.9, May 23, 2003 The primary purpose of this benchmark is to show how different standard containers are in terms of performance. We have observed that programmers often use sets, multisets, deques in the situations where sorted vectors are the optimal solutions. Similarly, programmers often choose lists simply because they do a few insertions and deletions without knowing that vectors are more efficient at that for small containers. Frequently, of course, performance does not matter, but it is important that programmers are aware of the consequences of their choices. We are not saying that only vectors should be used, there are cases when one really needs a more complicated data structure, but one needs to understand the price for additional functionality. The secondary purpose of the benchmark is to encourage compiler and library vendors to keep improving performance. For example, it is not acceptable that some compilers give you a sizable penalty for using vector iterators instead of pointer. It is also quite clear that performance of other standard containers could be improved. The benchmark is doing the same task 7 times using different data structures: array, vector (using a pointer as iterator), vector (using the defailt cector iterator), list, deque, set and multiset. The task is to remove duplicates from a sequence of doubles. This is a simple test, but it illustrates the performance of containers. It is clear that the benchmark needs to be eventually extended to slists and even to hash-sets and hash-maps, but we decided that at present it should work only with the standard containers. As the standard grows, so can the benchmark. The additional benefit of not including hash based containers is that now all the test have identical asymptotic complexity and, even more importantly, do almost the same number of comparisons. The difference is only in data structure overhead and cache behavior. The number of times that a given test is run inversly proportional to NlogN where N is the size of the sequence. This allows one to see how containers of different size behave. The instructive values used for the benchmark are: 10, 100, 1000, 10000, 100000, 1000000. The time taken for a run of the benchmark depends on the machine used, the compiler used, the compiler and optimizer settings used, as well as the standard library. Please note that the time taken could be several minutes - and much more if you use a slow debug mode. The output is a table where columns are separated by tabs and rows by newlines. This is barely ok for a human reader, but ideal for feeding into a program, such as a spreadsheet for display or analysis. If you want to add your own test of a container, add the name of your container to the "header string, write a test function like the existing ones, e.g. vector_test, and add a call of "run" for your test in "run_tests". Alex Stepanov stepa...@adobe.com Bjarne Stroustrup b...@cs.tamu.edu */ #include // some older implementations lack #include #include #include #include #include #include #include #include #include #include typedef double element_t; using namespace std; vector result_times; // results are puched into this vector typedef void(*Test)(element_t*, element_t*, int); void run(Test f, element_t* first, element_t* last, int number_of_times) { while (number_of_times-- > 0) f(first,last,number_of_times); } void array_test(element_t* first, element_t* last, int number_of_times) { element_t* array = new element_t[last - first]; copy(first, last, array); sort(array, array + (last - first)); unique(array, array + (last - first)); delete [] array; } void vector_pointer_test(element_t* first, element_t* last, int number_of_times) { vector container(first, last); // &*container.begin() gets us a pointer to the first element sort(&*container.begin(), &*container.end()); unique(&*container.begin(), &*container.end()); } void vector_iterator_test(element_t* first, element_t* last, int number_of_times) { vector container(first, last); sort(container.begin(), container.end()); unique(container.begin(), container.end()); } void deque_test(element_t* first, element_t* last, int number_of_times) { // deque container(first, last); CANNOT BE USED BECAUSE OF MVC++ 6 deque container(size_t(last - first), 0.0); copy(first, last, container.begin()); sort(container.begin(), container.end()); unique(container.begin(), container.end()); } void list_test(element_t* first, element_t* last, int number_of_times) { list container(first, last); container.sort(); container.unique(); } void set_test(element_t* first, element_t* last, int number_of_times) { set container(first, last); } void multiset_test(element_t* first, element_t* last, int number_of_times) { multiset container(first, last); typedef multiset::iterator iterator; { iterator first = container.begin(); iterator last = container.end(); while (first != last) { iterator next = first; if (++next == last) break; if (*first == *next) container.erase(next); else ++first; } } } void initialize(element_t* first, element_t* last) { element_t value = 0.0; while (first != last) { *first++ = value; value += 1.; } } double logtwo(double x) { return log(x)/log((double) 2.0); } const int largest_size = 1000000; int number_of_tests(int size) { double n = size; double largest_n = largest_size; return int(floor((largest_n * logtwo(largest_n)) / (n * logtwo(n)))); } void run_tests(int size) { const int n = number_of_tests(size); const size_t length = 2*size; result_times.clear(); // make a random test set of the chosen size: vector buf(length); element_t* buffer = &buf[0]; element_t* buffer_end = &buf[length]; initialize(buffer, buffer + size); // elements initialize(buffer + size, buffer_end); // duplicate elements random_shuffle(buffer, buffer_end); // test the containers: run(array_test, buffer, buffer_end, n); run(vector_pointer_test, buffer, buffer_end, n); run(vector_iterator_test, buffer, buffer_end, n); run(deque_test, buffer, buffer_end, n); run(list_test, buffer, buffer_end, n); run(set_test, buffer, buffer_end, n); run(multiset_test, buffer, buffer_end, n); } int main() { const int sizes [] = { 100000 }; const int n = sizeof(sizes)/sizeof(int); for (int i = 0; i < n; ++i) run_tests(sizes[i]); }