2016-12-14 2 views
1

생성자와 소멸자를 제외한 클래스의 모든 메서드에 대해 일종의 타이머를 '암시 적으로'추가하는 방법은 무엇입니까?클래스의 모든 메소드에 타이머를 추가하는 방법은 무엇입니까?

내가 클래스의 모든 메소드 지금 뭘하는지 :

void MyClass::SomeFunc() 
{ 
    cout << __PRETTY_FUNCTION__ <<endl; 

    boost::timer::cpu_timer timer; 

    //Some code 

    boost::timer::cpu_times elapsed = timer.elapsed(); 
    cout << __PRETTY_FUNCTION__ << " : WALLCLOCK TIME: " << elapsed.wall/1e9 << " seconds" << endl; 
} 

내가 원하는 무엇 : 코드의이 두 부분의

void MyClass::SomeFunc() 
{ 
    //Some code 
} 

가정 동작은 동등해야한다. 당신이 산업을 찾고 있다면

#define FL FunctionLogger _(__PRETTY_FUNCTION__) 

void MyClass::SomeFunc() 
{ 
    FL; 
    //Some code 
} 

: 이제

struct FunctionLogger { 
    FunctionLogger(const char* func) 
     : m_func(func) 
    { 
     cout << func <<endl; 
    } 
    ~FunctionLogger() { 
     boost::timer::cpu_times elapsed = timer.elapsed(); 
     GSULOG << m_func << " : WALLCLOCK TIME: " << elapsed.wall/1e9 << " seconds" << endl; 
    } 
    const char* m_func; 
    boost::timer::cpu_timer timer; 
}; 

:

void MyClass::SomeFunc() 
{ 
    FunctionLogger _(__PRETTY_FUNCTION__); 
    //Some code 
} 

물론 만약 당신이 좋아하면 매크로

답변

5

당신은 거의이 사용 RAII를 얻을 수 있습니다 이런 종류의 문제에 대한 해결책은 예술의 용어는 Aspect Oriented Programming입니다. 그러나 C++에서 직접 지원하지는 않습니다.

+0

함수에 람다 (lambda)로 실행되도록 코드를 전달하는 것보다 훨씬 낫습니다. – NathanOliver

+0

endl 대신 '\ n'을 사용하여 버퍼를 플러시하지 않도록주의 할 수 있습니다. – Jonas

+0

@Jonas : 어쩌면,하지만 OP가 아닌 나에게 제안해야합니다. 그가 원하거나 플러시 할 필요가 있든 나는 전혀 모른다. 나는 방금 같은 행동을 반복했다. –

4

프로파일 링 (각 함수 호출의 지속 시간 늘리기) 및 계측 (함수에 코드를 주입하여보다 자세하지만시기는 정확하지는 않은 타이밍 정보)을 수행하려고합니다.

far by 이것은 자신이 직접하는 것이 아니라 프로파일 러 (타이밍 및 선택적으로 계측을 자동으로 수행하는 상용 응용 프로그램)에서 코드를 실행함으로써 수행합니다. 당신의 소스 코드를 오염 시키십시오.)

2

코드를 수정하는 것을 피하고, __PRETTY_FUNCTION__ 출력을 희생 시키려한다면. 타이밍 핸들을 통해 클래스에 액세스하면이 작업을 수행 할 수 있습니다.

먼저 당신이 가지 존 Zwinck의 대답처럼, 타이밍에 대한 RAII 클래스를 정의 :

template<typename T> 
struct TimingDecorator { 
    T *ptr_; 
    boost::timer::cpu_timer timer; 

    TimingDecorator (T* ptr) : ptr_(ptr) {} 
    ~TimingDecorator() { 
     boost::timer::cpu_times elapsed = timer.elapsed(); 
     GSULOG << " : WALLCLOCK TIME: " << elapsed.wall/1e9 << " seconds" << endl; 
    } 
    T* operator->() { return ptr_; } 
    T const * operator->() const { return ptr_; } 
}; 

그런 다음 당신은 장식을 통해 클래스에 대한 모든 액세스를 강제로 핸들을 정의

template<typename T> 
struct TimingHandle { 
    T &obj_; 
    boost::timer::cpu_timer timer; 

    TimingHandle (T const& obj) : obj_(obj) {} 

    TimingDecorator<T> operator->() { return &obj_; } 
    TimingDecorator<T const> operator->() const { return &obj_; } 
}; 

그리고 타이밍 당신이 핸들을 통해 모든 액세스 할 :

MyClass obj; 
TimingHandle<MyClass> obj_timing(obj); 

GSULOG << "MyClass::SomeFunc" << endl; 
obj_timing->SomeFunc(); 

반복하지 않으려면 마지막 두 줄을 매크로로 래핑 할 수 있습니다 (사용하는 데 신경 쓰지 않는다면).

#define MYCLASS_TIME_FUNC(handle, func) \ 
    GSULOG << "MyClass::" #func << endl; \ 
    (handle)->func 

MYCLASS_TIME_FUNC(obj_timing, SomeFunc2)(/* params for SomeFunc2 */); 
1

이 이니셔티브를 반전 당신이 궁극적으로 사용할 수있는 약간은 당신은 또한 사용할 수 있습니다 Live On Coliru

timed_rand = time("Generate a random number", &::rand); 

for (int i = 0; i<10; ++i) 
    std::cout << timed_rand() << " "; 
:

template <typename Caption, typename F> 
auto timed(Caption const& task, F&& f) { 
    return [f=std::forward<F>(f), task](auto&&... args) { 
     using namespace std::chrono; 

     struct measure { 
      high_resolution_clock::time_point start; 
      Caption task; 
      ~measure() { GSU_LOCK << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; } 
     } timing { high_resolution_clock::now(), task }; 

     return f(std::forward<decltype(args)>(args)...); 
    }; 
} 

는 어떤 당신이처럼 사용할 수 있습니다

위트 당신은 또한 람다 다른 데이터를 축적 할 수

$ clang++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp 
$ for a in x xx xxx; do sleep 0.5; echo "$a"; done | ./a.out 

-- (main.cpp:25 std::getline(std::cin, line) completed in 497455µs) 
-- (main.cpp:26 line.length() completed in 36µs) 
-- (main.cpp:26 42 * TIMED(line.length()) completed in 106µs) 
Simple arithmetic: 42 
-- (main.cpp:25 std::getline(std::cin, line) completed in 503516µs) 
-- (main.cpp:26 line.length() completed in 14µs) 
-- (main.cpp:26 42 * TIMED(line.length()) completed in 42µs) 
Simple arithmetic: 84 
-- (main.cpp:25 std::getline(std::cin, line) completed in 508554µs) 
-- (main.cpp:26 line.length() completed in 14µs) 
-- (main.cpp:26 42 * TIMED(line.length()) completed in 38µs) 
Simple arithmetic: 126 
-- (main.cpp:25 std::getline(std::cin, line) completed in 286µs) 

Live On Coliru

#include <iostream> 
#include <chrono> 
using namespace std::literals::string_literals; 
#define GSU_LOG std::clog 

template <typename Caption, typename F> 
auto timed(Caption const& task, F&& f) { 
    return [f=std::forward<F>(f), task](auto&&... args) -> decltype(auto) { 
     using namespace std::chrono; 

     struct measure { 
      high_resolution_clock::time_point start; 
      Caption task; 
      ~measure() { GSU_LOG << " -- (" << task << " completed in " << duration_cast<microseconds>(high_resolution_clock::now() - start).count() << "µs)\n"; } 
     } timing { high_resolution_clock::now(), task }; 

     return f(std::forward<decltype(args)>(args)...); 
    }; 
} 

#define TIMED(expr) (timed(__FILE__ + (":" + std::to_string(__LINE__)) + " " #expr, [&]() -> decltype(auto) {return (expr);})()) 

int main() { 
    std::string line; 
    while (TIMED(std::getline(std::cin, line))) { 
     std::cout << "Simple arithmetic: " << TIMED(42 * TIMED(line.length())) << "\n"; 
    } 
} 

인쇄 : 하 MACRO 도움의 비트 당신은 더 verstatile 사용할 수 있습니다 합계/평균을보고하고보고합니다.

+0

'(T)'(http://coliru.stacked-crooked.com/a/065edfbe265d214c) [' main.cpp : 25 std :: getline (std :: cin, line) 497455μs에서 완성 됨)' – sehe

관련 문제