0

Backstory

(You can skip. Useful if you want to expand and adopt my approach.)

I am trying to expand a debugging library I created to be able to do unintrusive benchmarking and debugging. So far, it looks something like this, however I am open to revamping. This is just similar to what I was using for doing type flexible debugging:

#define BENCH(FUNC,N)CT::bench(#FUNC,FUNC,N,__FILE__,__LINE__,__PRETTY_FUNCTION__)
// #FUNC is a string of the code for the function placed in the macro
// FUNC is the function. How it should be captured, I am not sure yet.
// N Should be the number of times you wish to run the captured function
// __FILE__, __LINE__, __PRETTY_FUNCTION__ are GCC predefined macros
// Used for easily locating the code that is generating the output.

template <typename First> // Problem: Ensure only functions used as arguments?
static First bench(const QString expression,
          First &&type, // This is the type. Needed for the return.
          quint64 repeatN, // Negative repeats make no sense.
          const QString &_file,
          const int     &_line,
          const QString &_pretty_function)
{
      QString typeName = QConsoleToolkit::demangle(typeid(type).name());

      int initial(-1); // Time required to execute function first time 
      int average(-1); // Average execution time.
      for (int i=0; i < repeatN; i++) {
           // * 
           // * 
           // No idea how to do this. 
           // Please help.
           // * 
           // * 
      }

      QTextStream(stdout) 
      << "Benchmark: " << typeName 
      << "\t" << expression
      << "\t" << _pretty_function 
      << "\t" << _file 
      << ":"  << _line << endl
      << " Repeat: " << QString::number(repeatN) << endl
      << "Initial: " << QString::number(initial) << endl
      << "Average: " << QString::number(average) << endl;

      // Unsure if this will work with void
      return std::forward<First>(type);
}

// Returns string for type
QString CT::demangle(const QString &name)
{
    int status;
    std::unique_ptr<char, void(*)(void*)> res {
        abi::__cxa_demangle(name.toLatin1(), NULL, NULL, &status),
                std::free
    };
    return {(status==0) ? QLatin1String(res.get()) : name};
}

Actual Question

Take the following code:

void MyClass::foo()
{
    //dostuff
}
QString MyClass::funString()
{
    return "The quick brown fox jumps over the lazy dog";
}
void MyClass::bar()
{
     BENCH(foo(), 1000);
     QString s = BENCH(funString(),2000);
     QTextStream(stdout) << s << endl;
}

My goal is to have MyClass::bar() output this: (Random numbers are made up for initial and average)

Benchmark: void foo() void MyClass::bar() /home/akiva/myclass.cpp:31
 Repeat: 1000
Initial: 2523 
Average: 1234
Benchmark: QString funString() void MyClass::bar() /home/akiva/myclass.cpp:32
 Repeat: 2000
Initial: 5003 
Average: 4025
The quick brown fox jumps over the lazy dog

Thus, how can I make it so the macro BENCH() can take any type of function, run it N times, benchmarking how long each iteration takes to run, and have it return the first initial value received upon initial run?

It can not be intrusive, thus making this line possible:

QString s = BENCH(funString(),2000);
Anon
  • 2,267
  • 3
  • 34
  • 51
  • 1
    _Problem: Ensure only functions used as arguments?_: [`std::is_function`](https://en.cppreference.com/w/cpp/types/is_function). May be, you should have look onto [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function). For an arbitrary number of arguments, you may consider a [parameter pack](https://en.cppreference.com/w/cpp/language/parameter_pack). For `void` functions, (if an issue), a template specialization may work. – Scheff's Cat Dec 04 '18 at 08:53
  • 1
    Have a look at this: [SO: Easily measure elapsed time](https://stackoverflow.com/a/21995693/7478597). I believe, it can provide good inspiration for what you want to achieve. – Scheff's Cat Dec 04 '18 at 08:57

0 Answers0