U
Hallo - ich habe einen kleinen Benchmark geschrieben. Zunächst mal der Code:
(geht nur unter Windows, weil ich zum Zeit nehmen QueryPerformanceCounter genommen habe. außerdem geht es nur mit dem msvc, wegen __declspec(noline) (er darf die fkt. nicht inlinen))
#include <algorithm>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <limits>
#include <string>
#include "to_test.h"
//console
void wait()
{
std::cin.clear();
std::cin.ignore(std::cin.rdbuf()->in_avail());
std::cin.get();
}
//timer
#define NOMINMAX
#include <windows.h>
struct timer_t
{
public:
timer_t()
{
QueryPerformanceCounter(&start);
}
LONGLONG stop() const
{
LARGE_INTEGER stop;
QueryPerformanceCounter(&stop);
LONGLONG ret_val = stop.QuadPart - start.QuadPart;
return ret_val;
}
private:
LARGE_INTEGER start;
timer_t(const timer_t& other);
timer_t& operator= (const timer_t& other);
};
template<typename T> __declspec(noinline)
void dont_optimize_me_away(const T&)
{}
template <typename T> __declspec(noinline)
void test_perf(T& functor, const char* ident = "unknown")
{
const size_t iterations = 3000;
LONGLONG this_min(std::numeric_limits<LONGLONG>::max());
LONGLONG min = this_min;
do
{
min = std::min(this_min, min);
for(std::size_t i(0); i != iterations; ++i)
{
timer_t timer;
T::result_type out = functor();
this_min = timer.stop();
dont_optimize_me_away(out);
}
}while(min >= this_min);
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
std::cout << ident << ": " << std::setw(8) << min << " ticks. Equals ca. " << std::fixed << std::setprecision(10) << min/float(frequency.QuadPart) << " seconds." << std::endl
<< "\tThese are data for " << iterations << " Iterations." << std::endl
<< "\tFor one function call we need " << std::setprecision(2) << min/float(iterations) << " Ticks." << std::endl;
}
//----------------------------------- TEST itself
template<typename T, typename U>
struct to_test : std::unary_function<T, U>
{
the_new(const argument_type &arg) : arg(arg) {}
result_type operator() () const
{
return test_fkt<result_type>(arg);
}
private:
argument_type arg;
};
int main()
{
//einfach ein test-file einlesen, da wir was zum testen brauchen, was der compiler nicht schon zuvor kennt
std::fstream stream("test.txt");
stream << std::noskipws;
std::string in;
in.assign(
std::istream_iterator<char>(stream),
std::istream_iterator<char>()
);
to_test<std::string, std::wstring> my_test(in); //in dem fall ne fkt, die strings converten kann
test_perf(my_test, "bla"); //der eigentliche test
wait();
}
die nicht - inline fkt. dummy soll bezwecken, dass er das ergebnis auf jeden fall berechnet, weil er die fkt ja aufrufen muss, richtig!?
die test_perf fkt hab ich nicht-inline, damit ich mehrere fkt vergleichen kann, indem ich mehrfach test_perf nacheinander aufruf, ohne das der cpu-cache "unfair" aufgeteilt wird und er nicht daten, die er beim ersten durchlauf berechnet hat, im zweiten noch hat und nicht noch mal neu berechnen muss...
ist die idee an sich korrekt?
mit meinen (sehr beschränkten) asm-kenntnissen hab ich auch mal über das disassemly angeguckt und es sah gut aus - allerdings bin ich mir eben doch nicht ganz sicher...
würdet ihr evtl ganz anders vorgehen?
die idee mit den zwei schleifen, hab ich mal von volkard so aufgeschnappt - klang auch recht logisch - man muss ja sichergehen, dass nicht 20mal so viel ticks vergehen, weil gerade ein anderer prozess rechenzeit bekommen hat...
ich hoffe, es ist nicht zu viel text^^
danke schon mal, bb^^