Общий измеритель продолжительности для любого оператора, вызова функции и конструктора - PullRequest
4 голосов
/ 25 июня 2019

Я использовал шаблонную функцию метр (см. Ниже) для измерения прошедшего времени для функций.Тогда я также хотел использовать его для конструкторов.

Насколько я знаю, нет способа напрямую передать тип в качестве параметра функции.Поэтому я нашел этот обходной путь, передав его исключительно в качестве параметра шаблона (минимальный пример):

template <typename T, typename ... P>
auto meter(T t, P ... p) {
    auto t1 = high_resolution_clock::now();
    t(p...);
    auto t2 = high_resolution_clock::now();
    auto dif = t2-t1;   
    return duration_cast<microseconds>(dif);
}

template <typename T, typename ... P>
auto meter(P ... p) {
    auto t1 = high_resolution_clock::now();
    auto t = T(p...);
    auto t2 = high_resolution_clock::now();
    auto dif = t2-t1;   
    return duration_cast<microseconds>(dif);
}

int main() {
    auto d = meter(g, 1.0, 20.0); //meter the function call g(1.0, 20.0)
    std::cout << "Ellapsed time: " << d.count() << " microseconds\n";
    d = meter(complex_obj{2}); //meter () operator of complex_obj, assuming complex_obj{int} is trivial;
    std::cout << "Ellapsed time: " << d.count() << " microseconds\n";
    d = meter<complex_obj>(); //meter constructor complex_obj();
    std::cout << "Ellapsed time: " << d.count() << " microseconds\n";
}

Попытка этого заставила меня задуматься.Есть ли общий / непротиворечивый способ переписать это, чтобы применить к любому виду вычислений (не только к конструктору, но, может быть, даже к другим операторам, таким как (obj1

Извините, если этот вопрос стал слишком широким, мой главный вопрос - если есть способ объединить синтаксис вызова meter для функций и конструкторов.

Ответы [ 2 ]

2 голосов
/ 25 июня 2019

Вы можете заключить код для измерения в лямбду (начиная с C ++ 11):

#include <chrono>
#include <iostream>

template<class F>
auto meter(F&& f) {
  auto t1 = std::chrono::high_resolution_clock::now();
  f();//                                                <-- operator() of the lambda
  auto t2 = std::chrono::high_resolution_clock::now();
  auto dif = t2-t1;
  return std::chrono::duration_cast<std::chrono::microseconds>(dif);
}

void g(double x, double y) {
  std::cout << "g(" << x << ", " << y << ")\n";
}

int main() {
  double x = 1.0;
  auto d = meter([&] {
    // This comment is inside the *body* of the lambda.
    // Code of the {body} is executed upon `operator()`.
    g(x, 20.0);// note that you can use `x` here thanks to the capture-default `[&]`
  });
  std::cout << "time: " << d.count() << " ms\n";
}
1 голос
/ 25 июня 2019

Несмотря на то, что вы инкапсулируете фактический вызов функции, вероятно, будет лучше, если вы заставите вашу функцию meter возвращать значение, возвращаемое функцией, которую она измеряет, чтобы сделать возможным цепочку вызовов - но все же с возможностьюпроверьте, сколько времени занимал каждый отдельный звонок.Это делает теоретически возможным запуск решения RVO / copy и, следовательно, не так сильно замедляет код.Пример:

#include <chrono>
#include <iostream>
#include <thread> // for debug sleeps only

using namespace std::chrono;

template<typename D, typename F, typename... P>
auto meter(D& dur, F func, P&&... params) {
    auto start = high_resolution_clock::now();
    auto retval = func(std::forward<P>(params)...);
    // put duration in the duration reference
    dur = duration_cast<D>(high_resolution_clock::now() - start);
    // and return func()'s return value
    return retval;
}

namespace m {
double add(double a, double b) {
    std::this_thread::sleep_for(milliseconds(10));
    return a + b;
}
double sub(double a, double b) {
    std::this_thread::sleep_for(milliseconds(11));
    return a - b;
}
double mul(double a, double b) {
    std::this_thread::sleep_for(milliseconds(12));
    return a * b;
}
double div(double a, double b) {
    std::this_thread::sleep_for(milliseconds(13));
    return a / b;
}
} // namespace m

int main() {
    milliseconds Add, Sub, Mul, Div;

    // chaining calls for this calculation:
    // (1000 / (100 * (4.3 - (1.1+2.2))))
    auto result = meter(Div, m::div,
        1000.0, meter(Mul, m::mul,
            100.0, meter(Sub, m::sub,
                4.3, meter(Add, m::add,
                    1.1, 2.2)
                )
        )
    );
    std::cout << "Add: " << Add.count() << " ms.\n";
    std::cout << "Sub: " << Sub.count() << " ms.\n";
    std::cout << "Mul: " << Mul.count() << " ms.\n";
    std::cout << "Div: " << Div.count() << " ms.\n";
    std::cout << result << "\n";
}

Вероятный вывод:

Add: 10 ms.
Sub: 11 ms.
Mul: 12 ms.
Div: 13 ms.
10
...