From ceafcb987730eaf5c4191afab12550ffc13ce89e Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Sat, 9 Jun 2001 23:08:24 +0000 Subject: [PATCH] New test. From-SVN: r43121 --- .../g++.old-deja/g++.other/stepanov_v1p2.C | 350 ++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/stepanov_v1p2.C diff --git a/gcc/testsuite/g++.old-deja/g++.other/stepanov_v1p2.C b/gcc/testsuite/g++.old-deja/g++.other/stepanov_v1p2.C new file mode 100644 index 00000000000..910629d353e --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/stepanov_v1p2.C @@ -0,0 +1,350 @@ +// Special g++ Options: -O2 + +/* KAI's version of Stepanov Benchmark -- Version 1.2 + + Version 1.2 -- removed some special code for GNU systems that + GNU complained about without -O + +To verify how efficiently C++ (and in particular STL) is compiled by +the present day compilers, I composed a little benchmark. It outputs +13 numbers. In the ideal world these numbers should be the same. In +the real world, however, ... + +The final number printed by the benchmark is a geometric mean of the +performance degradation factors of individual tests. It claims to +represent the factor by which you will be punished by your +compiler if you attempt to use C++ data abstraction features. I call +this number "Abstraction Penalty." + +As with any benchmark it is hard to prove such a claim; some people +told me that it does not represent typical C++ usage. It is, however, +a noteworthy fact that majority of the people who so object are +responsible for C++ compilers with disproportionatly large Abstraction +Penalty. + +The structure of the benchmark is really quite simple. It adds 2000 +doubles in an array 25000 times. It does it in 13 different ways that +introduce more and more abstract ways of doing it: + +0 - uses simple Fortran-like for loop. +1 - 12 use STL style accumulate template function with plus function object. +1, 3, 5, 7 ,9, 11 use doubles. +2, 4, 6, 8, 10, 12 use Double - double wrapped in a class. +1, 2 - use regular pointers. +3, 4 - use pointers wrapped in a class. +5, 6 - use pointers wrapped in a reverse-iterator adaptor. +7, 8 - use wrapped pointers wrapped in a reverse-iterator adaptor. +9, 10 - use pointers wrapped in a reverse-iterator adaptor wrapped in a + reverse-iterator adaptor. +11, 12 - use wrapped pointers wrapped in a reverse-iterator adaptor wrapped + in a reverse-iterator adaptor. + +All the operators on Double and different pointer-like classes are +declared inline. The only thing that is really measured is the penalty +for data abstraction. While templates are used, they do not cause any +performance degradation. They are used only to simplify the code. + +Since many of you are interested in the C++ performance issues, I +decided to post the benchmark here. I would appreciate if you run it +and (if possible) send me the results indicating what you have +compiled it with (CPU, clock rate, compiler, optimization level). It +is self contained and written so that it could be compiled even with +those compilers that at present cannot compile STL at all. + +It takes a fairly long time to run - on a really slow machine it might +take a full hour. (For those of you who want to run it faster - give +it a command line argument that specifies the number of +iterations. The default is 25000, but it gives an accurate predictions +even with 500 or a thousand.) + + +Alex Stepanov +stepanov@mti.sgi.com + +*/ + + +#include +#include +#include +#include +#include + +template +inline int operator!=(const T& x, const T& y) { + return !(x == y); +} + +struct Double { + double value; + Double() {} + Double(const double& x) : value(x) {} + operator double() { return value; } +}; + +inline Double operator+(const Double& x, const Double& y) { + return Double(x.value + y.value); +} + +struct double_pointer { + double* current; + double_pointer() {} + double_pointer(double* x) : current(x) {} + double& operator*() const { return *current; } + double_pointer& operator++() { + ++current; + return *this; + } + double_pointer operator++(int) { + double_pointer tmp = *this; + ++*this; + return tmp; + } + double_pointer& operator--() { + --current; + return *this; + } + double_pointer operator--(int) { + double_pointer tmp = *this; + --*this; + return tmp; + } +}; + + +inline int operator==(const double_pointer& x, + const double_pointer& y) { + return x.current == y.current; +} + +struct Double_pointer { + Double* current; + Double_pointer() {} + Double_pointer(Double* x) : current(x) {} + Double& operator*() const { return *current; } + Double_pointer& operator++() { + ++current; + return *this; + } + Double_pointer operator++(int) { + Double_pointer tmp = *this; + ++*this; + return tmp; + } + Double_pointer& operator--() { + --current; + return *this; + } + Double_pointer operator--(int) { + Double_pointer tmp = *this; + --*this; + return tmp; + } +}; + + +inline int operator==(const Double_pointer& x, + const Double_pointer& y) { + return x.current == y.current; +} + +template +struct reverse_iterator { + RandomAccessIterator current; + reverse_iterator(RandomAccessIterator x) : current(x) {} + T& operator*() const { + RandomAccessIterator tmp = current; + return *(--tmp); + } + reverse_iterator& operator++() { + --current; + return *this; + } + reverse_iterator operator++(int) { + reverse_iterator tmp = *this; + ++*this; + return tmp; + } + reverse_iterator& operator--() { + ++current; + return *this; + } + reverse_iterator operator--(int) { + reverse_iterator tmp = *this; + --*this; + return tmp; + } +}; + +template +inline int operator==(const reverse_iterator& x, + const reverse_iterator& y) { + return x.current == y.current; +} + +struct { + double operator()(const double& x, const double& y) {return x + y; } + Double operator()(const Double& x, const Double& y) {return x + y; } +} plus; + + +template +Number accumulate(Iterator first, Iterator last, Number result) { + while (first != last) result = plus(result, *first++); + return result; +} + +int iterations = 25000; +#define SIZE 2000 + +int current_test = 0; + +double result_times[20]; + +void summarize() { + printf("\ntest absolute additions ratio with\n"); + printf("number time per second test0\n\n"); + int i; + double millions = (double(SIZE) * iterations)/1000000.; + for (i = 0; i < current_test; ++i) + { + printf("%2i %5.2fsec %5.2fM %.2f\n", + i, + result_times[i], + millions/result_times[i], + result_times[i]/result_times[0]); + // To make the benchmark into a test-case we check that no + // version has a severe abstraction penalty. There will always + // be measurement errors, and we don't presently avoid all + // abstraction penalty. As the compiler improves, 1.2 should + // gradually be replaced with a smaller value. + if (result_times[i]/result_times[0] > 1.2) + abort (); + } + double gmean_times = 0.; + double total_absolute_times = 0.; // sam added 12/05/95 + double gmean_rate = 0.; + double gmean_ratio = 0.; + for (i = 0; i < current_test; ++i) { + total_absolute_times += result_times[i]; // sam added 12/05/95 + gmean_times += log(result_times[i]); + gmean_rate += log(millions/result_times[i]); + gmean_ratio += log(result_times[i]/result_times[0]); + } + printf("mean: %5.2fsec %5.2fM %.2f\n", + exp(gmean_times/current_test), + exp(gmean_rate/current_test), + exp(gmean_ratio/current_test)); + printf("\nTotal absolute time: %.2f sec\n", total_absolute_times); // sam added 12/05/95 + printf("\nAbstraction Penalty: %.2f\n\n", exp(gmean_ratio/current_test)); +} + +clock_t start_time, end_time; + +inline void start_timer() { start_time = clock(); } + +inline double timer() { + end_time = clock(); + return (end_time - start_time)/double(CLOCKS_PER_SEC); +} + +const double init_value = 3.; + + + +double data[SIZE]; + +Double Data[SIZE]; + +inline void check(double result) { + if (result != SIZE * init_value) printf("test %i failed\n", current_test); +} + +void test0(double* first, double* last) { + start_timer(); + for(int i = 0; i < iterations; ++i) { + double result = 0; + for (int n = 0; n < last - first; ++n) result += first[n]; + check(result); + } + result_times[current_test++] = timer(); +} + + +template +void test(Iterator first, Iterator last, T zero) { + int i; + start_timer(); + for(i = 0; i < iterations; ++i) + check(double(accumulate(first, last, zero))); + result_times[current_test++] = timer(); +} + +template +void fill(Iterator first, Iterator last, T value) { + while (first != last) *first++ = value; +} + + +double d = 0.; +Double D = 0.; +typedef double* dp; +dp dpb = data; +dp dpe = data + SIZE; +typedef Double* Dp; +Dp Dpb = Data; +Dp Dpe = Data + SIZE; +typedef double_pointer dP; +dP dPb(dpb); +dP dPe(dpe); +typedef Double_pointer DP; +DP DPb(Dpb); +DP DPe(Dpe); +typedef reverse_iterator rdp; +rdp rdpb(dpe); +rdp rdpe(dpb); +typedef reverse_iterator rDp; +rDp rDpb(Dpe); +rDp rDpe(Dpb); +typedef reverse_iterator rdP; +rdP rdPb(dPe); +rdP rdPe(dPb); +typedef reverse_iterator rDP; +rDP rDPb(DPe); +rDP rDPe(DPb); +typedef reverse_iterator rrdp; +rrdp rrdpb(rdpe); +rrdp rrdpe(rdpb); +typedef reverse_iterator rrDp; +rrDp rrDpb(rDpe); +rrDp rrDpe(rDpb); +typedef reverse_iterator rrdP; +rrdP rrdPb(rdPe); +rrdP rrdPe(rdPb); +typedef reverse_iterator rrDP; +rrDP rrDPb(rDPe); +rrDP rrDPe(rDPb); + +int main(int argv, char** argc) { + if (argv > 1) iterations = atoi(argc[1]); + fill(dpb, dpe, double(init_value)); + fill(Dpb, Dpe, Double(init_value)); + test0(dpb, dpe); + test(dpb, dpe, d); + test(Dpb, Dpe, D); + test(dPb, dPe, d); + test(DPb, DPe, D); + test(rdpb, rdpe, d); + test(rDpb, rDpe, D); + test(rdPb, rdPe, d); + test(rDPb, rDPe, D); + test(rrdpb, rrdpe, d); + test(rrDpb, rrDpe, D); + test(rrdPb, rrdPe, d); + test(rrDPb, rrDPe, D); + summarize(); + return 0; +} + + + -- 2.30.2