Question

I'm trying to use “rusage” statistics in my program to get data similar to that of the time tool. However, I'm pretty sure that I'm doing something wrong. The values seem about right but can be a bit weird at times. I didn't find good resources online. Does somebody know how to do it better?

Sorry for the long code.

class StopWatch {
public:
    void start() {
        getrusage(RUSAGE_SELF, &m_begin);
        gettimeofday(&m_tmbegin, 0);
    }

    void stop() {
        getrusage(RUSAGE_SELF, &m_end);
        gettimeofday(&m_tmend, 0);
        timeval_sub(m_end.ru_utime, m_begin.ru_utime, m_diff.ru_utime);
        timeval_sub(m_end.ru_stime, m_begin.ru_stime, m_diff.ru_stime);
        timeval_sub(m_tmend, m_tmbegin, m_tmdiff);
    }

    void printf(std::ostream& out) const {
        using namespace std;

        timeval const& utime = m_diff.ru_utime;
        timeval const& stime = m_diff.ru_stime;

        format_time(out, utime);
        out << "u ";
        format_time(out, stime);
        out << "s ";
        format_time(out, m_tmdiff);
    }

private:
    rusage m_begin;
    rusage m_end;
    rusage m_diff;
    timeval m_tmbegin;
    timeval m_tmend;
    timeval m_tmdiff;

    static void timeval_add(timeval const& a, timeval const& b, timeval& ret) {
        ret.tv_usec = a.tv_usec + b.tv_usec;
        ret.tv_sec = a.tv_sec + b.tv_sec;
        if (ret.tv_usec > 999999) {
            ret.tv_usec -= 1000000;
            ++ret.tv_sec;
        }
    }

    static void timeval_sub(timeval const& a, timeval const& b, timeval& ret) {
        ret.tv_usec = a.tv_usec - b.tv_usec;
        ret.tv_sec = a.tv_sec - b.tv_sec;
        if (a.tv_usec < b.tv_usec) {
            ret.tv_usec += 1000000;
            --ret.tv_sec;
        }
    }

    static void format_time(std::ostream& out, timeval const& tv) {
        using namespace std;
        long usec = tv.tv_usec;
        while (usec >= 1000)
            usec /= 10;
        out << tv.tv_sec << '.' << setw(3) << setfill('0') << usec;
    }
}; // class StopWatch
Was it helpful?

Solution

What is the purpose of:

while (usec >= 1000)
    usec /= 10;

I gather that you want the most significant three digits of the usec; in that case, the most straightforward way I can think of is to divide usec by 1000, and be done with that.

Test cases:

  • 999999 ⇒ 999
  • 99999 ⇒ 999 (should be 099)
  • 9999 ⇒ 999 (should be 009)
  • 999 ⇒ 999 (should be 000)

OTHER TIPS

I think there's probably a bug somewhere in your composition of sec and usec. I can't really say what exactly without knowing the kinds of errors you're seeing. A rough guess would be that usec can never be > 999999, so you're relying on overflow to know when to adjust sec. It could also just be a problem with your duration output format.

Anyway. Why not store the utime and stime components as float seconds rather than trying to build your own rusage on output? I'm pretty sure the following will give you proper seconds.

static int timeval_diff_ms(timeval const& end, timeval const& start) {
    int micro_seconds = (end.tv_sec  - start.tv_sec) * 1000000 
        + end.tv_usec - start.tv_usec;

    return micro_seconds;
}

static float timeval_diff(timeval const& end, timeval const& start) {
    return (timeval_diff_ms(end, start)/1000000.0f);
}

If you want to decompose this back into an rusage, you can always int-div and modulo.

@Chris:

I gather that you want the most significant three digits of the usec

Yes. The overall number of digits in usec varies and I want to cut those below 1000. For example, if usec=1000, I want to get the result 100 (not 1, as you propose). Therefore, I can't simply divide by 1000.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top