views:

1052

answers:

3

Hello,

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
+2  A: 

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.

Mike Haboustak
+3  A: 

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)
Chris Jester-Young
A: 

@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.

Konrad Rudolph
I'm not sure what you mean by the number of digits in usec varying. As far as I know, all values in it are meant to be between 0 and 999,999, corresponding to 0 ms and 999.999 ms respectively. "Most significant three digits" to me meant you wanted the millisecond count. Did I read something wrong?
Chris Jester-Young
Chris, the @tag doesn't seem to work either way.About your comment: I don't work on this code anymore and I'm no longer sure what exactly I wanted to obtain. :-/ AFAIR I wanted to calculate the 999 numbers in your answer, i.e. *not* those you listed as “should be”. I now think you were right.
Konrad Rudolph