C ++ použití std :: Chrono měřit výkon funkce členů v příjemném způsobem

hlasů
1

Chci optimalizovat mé žádosti, a to zejména na rychlost provádění určitých funkcí.

Představte si, že existuje třída s některými členskými funkcemi

class Test
{
public:
    Test();
    virtual ~Test();
    int init(int arg1, double arg2);

private:
    [...]

a ve svém konstruktoru říkám jednu z těchto metod

Test::Test()
{
    [...]
    int value = init(1, 1.2);
}

Jak mohu měřit čas spuštění mé metody init(...)v pěkné a čisté způsobem, aniž by zlomil program?

V tuto chvíli jsem použít následující kód

Test::Test()
{
    [...]
    auto start = std::chrono::high_resolution_clock::now();

    int value = init(1, 1.2);

    auto stop = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration = stop - start;
    std::cout << duration.count() * 1000 << ms\n;
}

Funguje to, jak se očekávalo, ale myslím, že je dost špinavá a já chci mít „čistší“ řešení.

Existuje způsob, jak mít nějakou funkci, která vezme funkci člena a další parametry jako tak

int value = countTime(function, arg1, arg2);

Nevím, zda je možné předat návratovou hodnotu od function()do countTime(), aby se nepřerušují workflow mém kódu.

EDIT: To je můj TimeMeasure třída

namespace tools 
{
    class TimeMeasure 
    {
    public:
        TimeMeasure() 
        {
            m_start = std::chrono::high_resolution_clock::now();
        }

        virtual ~TimeMeasure()
        {
            m_stop = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> duration = m_stop - m_start;
            std::cout << duration.count() << ms\n;
        }

    public:
        typedef std::chrono::time_point<std::chrono::high_resolution_clock> HighResClock;

    private:
        HighResClock m_start;
        HighResClock m_stop;
    };

    template <typename T, typename F, typename... Args>
    auto measure(T *t, F &&fn, Args... args)
    {
        tools::TimeMeasure timeMeasure;
        return (t->*fn)(std::forward<Args>(args)...);
    }
}

a ve svém konstruktoru Test()I použít funkci measuretímto způsobem

Test()
{
    [...]
    tools::measure(this, Test::init, filepath);
}

int init(const std::string& filepath) constbere tu řetězec do souboru. Takže v mém případě je to jen jeden argument

Bohužel jsem si invalid use of non-static member function 'int init(const string&) const'chybu

Rád bych věděl, jestli konstruktor není členskou funkci. Tak proč jsem se dostat tuto chybu?

EDIT 2:

Podle OznOg své odpovědi jsem jen zapomněl ruku v ukazatel na mé funkce.

Takže by to bylo správné volání funkce

tools::measure(this, &Test::init, filepath);
Položena 20/10/2018 v 12:58
zdroj uživatelem
V jiných jazycích...                            


3 odpovědí

hlasů
4

Dalo by se vytvořit třídu jako:

struct MeasureTime {
    MeasureTime() : _start(std::chrono::high_resolution_clock::now()) {}

    ~MeasureTime() {
        auto stop = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double> duration = stop - _start;
        std::cout << duration.count() * 1000 << "ms\n";
    }
private:
    std::chrono::time_point<std::chrono::high_resolution_clock>  _start;
};

a jednoduše použít ve svém kódu:

Test::Test()
{
    MeasureTime mt;
    [...]
    { //or even this for just the init call
    MeasureTime mt2;
    int value = init(1, 1.2);
    }
}

IMHO to je méně rušivé než to, co navrhoval.

Pokud opravdu chcete funkci, můžete zkusit obal, jako je:

template <class T, class F, class... Args>
auto MeasureTimeFn(T *t, F &&fn, Args... args) {
    MeasureTime timer;
     return (t->*fn)(std::forward<Args>(args)...);
}

A volání, jako jsou:

int value = MeasureTimeFn(this, &Test::init, 1, 1.2);

ale nejste si jisti, že je ve skutečnosti mnohem lepší.

Můžete se pokusit skrýt věc pomocí makra:

#define MEASURE(f, ...) \
  MeasureTimeFn(this, &std::remove_reference_t<decltype(*this)>::f, __VA_ARGS__)

Tímto způsobem můžete psát

int value = MEASURE(init, 1, 1.2);

co je úplně jako to, co jste chtěl, ale funguje pouze uvnitř členských funkcí, s členské funkce (non statická).

Každopádně asi dobré místo pro začátek.

* EDIT * Pokud můžete upravit dědictví vás třídy, můžete zkusit

template<class T>
struct MeasureTool {
    template <class F, class... Args>
    auto measure(F &&fn, Args... args) {
        tools::TimeMeasure timeMeasure;
        return (static_cast<T*>(this)->*fn)(std::forward<Args>(args)...);
    }
};

class Test : public MeasureTool<Test>
{
public:
    Test();
    virtual ~Test() {}
    int init(const std::string &filepath) { _path = filepath; return 0; }
    const auto &getPath() const { return _path; }
private:
    std::string _path;

};

Test::Test()
{
    std::string filepath("/some/where");
    int value = measure(&Test::init, filepath);
    measure(&Test::getPath);
}

A tentokrát, zdá se, aby odpovídaly svůj první požadavek (ale je docela rušivé ...)

Nyní je to všechno ve svých rukou :)

Odpovězeno 20/10/2018 v 13:15
zdroj uživatelem

hlasů
0

Používám vždy Boost.Timer .

#include <boost/timer/timer.hpp>

...
boost::timer::cpu_timer timer;

for(int i = 0; i < 1000; ++i)
  funct();

std::cout << timer.format();

Ukazuje stěnu , na uživatele , a systémový čas.

Odpovězeno 25/10/2018 v 14:45
zdroj uživatelem

hlasů
-1

Můžete použít takové implementace:

template<typename Fn, typename... Args>
typename std::enable_if<!std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value, 
    std::tuple<std::chrono::duration<double>, typename std::result_of<Fn&&(Args...)>::type>
>::type
countTime(Fn&& fn, Args&&... args) {
    auto start = std::chrono::high_resolution_clock::now();
    auto fnret = std::forward<Fn>(fn)(std::forward<Args>(args)...);
    auto stop = std::chrono::high_resolution_clock::now();
    return std::make_tuple(stop - start, fnret);
}

template<typename Fn, typename... Args>
typename std::enable_if<std::is_void<typename std::result_of<Fn&&(Args...)>::type>::value, 
    std::tuple<std::chrono::duration<double>>
>::type
countTime(Fn&& fn, Args&&... args) {
    auto start = std::chrono::high_resolution_clock::now();
    std::forward<Fn>(fn)(std::forward<Args>(args)...);
    auto stop = std::chrono::high_resolution_clock::now();
    return std::make_tuple(stop - start);
}

template<typename R, class C, typename... Args>
typename std::enable_if<!std::is_same<R, void>::value,
    std::tuple<std::chrono::duration<double>, R>
>::type
countTime(R (C::*fn)(Args...), C& obj, Args&&... args) {
    auto start = std::chrono::high_resolution_clock::now();
    auto fnret = (obj.*fn)(std::forward<Args>(args)...);
    auto stop = std::chrono::high_resolution_clock::now();
    return std::make_tuple(stop - start, fnret);
}

template<class C, typename... Args>
std::tuple<std::chrono::duration<double>>
countTime(void (C::*fn)(Args...), C& obj, Args&&... args) {
    auto start = std::chrono::high_resolution_clock::now();
    (obj.*fn)(std::forward<Args>(args)...);
    auto stop = std::chrono::high_resolution_clock::now();
    return std::make_tuple(stop - start);
}

To vrátí n-tice s platností jednoho člena v případě void (*) (...) funkce a n-tice s trváním a vrátit typu v případě funkcí vracejících smth. Pracuje s std :: vázaných a členských funkcí. Pravděpodobně přetížení mohou být sloučeny do jedné nebo dvou implementacích, ale nemám ponětí, jak to udělat.

Příklad volání:

auto ret = countTime([](int a) -> int { 
    std::this_thread::sleep_for(std::chrono::milliseconds(a)); 
    return a * 2;
}, 10);
std::cout << "function executed in: " <<
    std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() <<
    " milliseconds." << std::endl;
std::cout << "function returned: " << std::get<1>(ret) << std::endl;

Jednodušší příklad volání:

auto ret = countTime(&Test::init, *this, 1, 1.2);
int value = std::get<1>(ret);

std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() << "ms" << std::endl;

Jednoduchý příklad jednodušší volání, za předpokladu, že int init(int, int)funkce:

auto ret = countTime(init, 1, 1.2);
int value = std::get<1>(ret);

std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::get<0>(ret)).count() << "ms" << std::endl;

Živá verze je k dispozici na onlinegdb .

Odpovězeno 21/10/2018 v 10:05
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more