Мне нужно было измерить время выполнения отдельных функций в библиотеке. Я не хотел оборачивать каждый вызов каждой функции функцией измерения времени, потому что это уродливо и углубляет стек вызовов. Я также не хотел помещать код таймера в верхнюю и нижнюю часть каждой функции, потому что это создает беспорядок, когда функция может выйти рано или выдать, например, исключения. Итак, в итоге я сделал таймер, который использует свое время жизни для измерения времени.
Таким образом, я могу измерить время простоя блока кода, просто создав экземпляр одного из этих объектов в начале рассматриваемого блока кода (функция или область действия), а затем позволяя деструктору экземпляров измерить время, прошедшее с момента создания, когда экземпляр выходит из области видимости. Вы можете найти полный пример здесь , но структура чрезвычайно проста:
template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
using duration_t = typename clock_t::duration;
const std::function<void(const duration_t&)> callback;
const std::chrono::time_point<clock_t> start;
scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
callback(finished_callback), start(clock_t::now()) { }
scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
callback(finished_callback), start(clock_t::now()) { }
~scoped_timer() { callback(clock_t::now() - start); }
};
Структура перезвонит вам в предоставленном функторе, когда он выйдет из области видимости, чтобы вы могли что-то сделать с информацией о времени (распечатать или сохранить ее или что-то еще). Если вам нужно сделать что-то еще более сложное, вы можете использовать std::bind
с std::placeholders
для вызова функций с большим количеством аргументов.
Вот краткий пример его использования:
void test(bool should_throw) {
scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
std::cout << "took " << e << "ms" << std::endl;
});
std::this_thread::sleep_for(std::chrono::seconds(1));
if (should_throw)
throw nullptr;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
Если вы хотите быть более преднамеренным, вы также можете использовать new
и delete
, чтобы явно запускать и останавливать таймер, не полагаясь на то, что вы можете это сделать.