Your message dated Sun, 21 Oct 2012 23:45:09 +0200
with message-id <[email protected]>
and subject line Re: Bug#426565: /usr/share/man/man2/times.2.gz: interpretation 
of times(2) return value is based on HZ (obsolete?) value
has caused the Debian Bug report #426565,
regarding /usr/share/man/man2/times.2.gz: interpretation of times(2) return 
value is based on HZ (obsolete?) value
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
426565: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=426565
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: manpages-dev
Version: 2.49-1
Severity: normal
File: /usr/share/man/man2/times.2.gz

I have a problem with the following sentence in times(2) manual page, 
RETURN VALUE section:

Since Linux 2.6, this point is (2^32/HZ) - 300 (i.e., about 429 million) 
seconds  before  system  boot time.

The problem is that in order to be able to use the return value (map it to my 
wall-clock) I have to know the value of HZ. It appears that the value of HZ 
depends on the kernel configuration option (recent Linux versions can have 
100Hz, 250Hz, 1000Hz etc), so it's not possible to compile once and use 
the same binary on other machines. On Google I also found some discussion 
that HZ can be 1024 on some architectures
So this HZ variable is a very bad idea.

Google says that sysconf(_SC_CLK_TCK) should be used instead of HZ.
This seems to be reasonable and works for time (jiffies) numbers in /proc,
but it does NOT work for the return value, consider the following:

1) I compiled my kernel (2.6.20.11 with completely fair scheduler 14 on 
for Pentium 4) with the following options:
CONFIG_HZ_1000=y
CONFIG_HZ=1000

2) sysconf(_SC_CLK_TCK) returns 100, and it works correctly with timing 
numbers in the structure and /proc/#/stat (i.e. starttime field).

3) expression 2^32/sysconf(_SC_CLK_TCK)-300 evaluates to 42949372 
this is about 42 million (not about 429 million as in manual)

4) I found the following formula to be useful to convert the returned 
ticks to milli seconds since boot:
struct tms mytimes;
uint64_t ms=(times(&mytimes)*1000/sysconf(_SC_CLK_TCK) - (1LLU<<32) + 951416);

The idea is that times(&mytimes) returns the number of ticks since arbitrary 
point in time, I multiply it with 1000/sysconf(_SC_CLK_TCK) which is the 
number of milliseconds per one tick. Then the offset of the arbitrary point 
in time is adjusted.

Interestingly, the constant 951416 is not firm (it seems to be shrinking by 
100ms per hour or so), but (1LLU<<32) is not to be divided and the constant 
difference is far from 300 seconds as manual says.
I just wonder what is really happening here.

I used the following program to find out the formula and the difference 
between the values of times(2) and /proc/#/stat startime:

#include <sys/times.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <fstream>

using namespace std;

long long myStartTime(){
  char statname[64] = "";
  char info[64];
  snprintf(statname, 64, "/proc/%d/stat", getpid());
  ifstream stat(statname);
  stat.width(64); stat>>info; // PID
  if (atol(info)!=getpid()) {
    cout << "bad proc stat file" << endl;
    exit(EXIT_FAILURE);
  }
  stat.width(64); stat>>info; // filename of executable
  stat.width(64); stat>>info; // state
  stat.width(64); stat>>info; // parent PID
  stat.width(64); stat>>info; // process group
  stat.width(64); stat>>info; // session
  stat.width(64); stat>>info; // tty nr
  stat.width(64); stat>>info; // process group ID of tty owner
  stat.width(64); stat>>info; // flags
  stat.width(64); stat>>info; // No. minor faults
  stat.width(64); stat>>info; // No. minor faults in children
  stat.width(64); stat>>info; // No. major faults
  stat.width(64); stat>>info; // No. major faults in children
  stat.width(64); stat>>info; // No. jiffies in user mode
  stat.width(64); stat>>info; // No. jiffies in kernel mode
  stat.width(64); stat>>info; // children jiffies in user mode
  stat.width(64); stat>>info; // children jiffies in kernel mode
  stat.width(64); stat>>info; // priority
  stat.width(64); stat>>info; // nice value
  stat.width(64); stat>>info; // 0 (zero)
  stat.width(64); stat>>info; // jiffies before next SIGALARM
  stat.width(64); stat>>info; // jiffies since start after boot
  return (atoll(info)*1000/sysconf(_SC_CLK_TCK));
}

long ticks_per_sec = sysconf(_SC_CLK_TCK);

inline long long ticks2ms(long long &ticks) {
  return (ticks*1000/ticks_per_sec - (1LLU<<32) + 951416);
}

struct tms mytimes;
long long start, before, after;

int main(){
  before = times(&mytimes);
  sleep(1);
  after = times(&mytimes);
  before = ticks2ms(before);
  after = ticks2ms(after);
  start = myStartTime();
  long long diff;
  if (before>start) {
    diff = (before-start);
    cout << "Too late by " << diff << "ms" << endl;
  } else if (start>before) {
    diff = (start - before);
    cout << "TOO EARLY BY " << diff << "ms" << endl;
    cout << "startt="<<start<<"ms\nbefore=" << before 
         << "ms after="<<after << "ms duration="<<(after-before)<<"ms" << endl;
  } else cout << "GOOD" << endl;
}

-- System Information:
Debian Release: lenny/sid
  APT prefers testing
  APT policy: (990, 'testing'), (500, 'stable'), (50, 'unstable'), (1, 
'experimental')
Architecture: i386 (i686)

Kernel: Linux 2.6.20.11-cfs-v13 (PREEMPT)
Locale: LANG=lt_LT.UTF-8, LC_CTYPE=lt_LT.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages manpages-dev depends on:
ii  manpages                      2.43-0     Manual pages about using a GNU/Lin

manpages-dev recommends no packages.

-- no debconf information


--- End Message ---
--- Begin Message ---
Version: 2.74-1

On Tue, May 29, 2007 at 06:46:11PM +0200, Marius Mikucionis wrote:
> Package: manpages-dev
> Version: 2.49-1
> Severity: normal
> File: /usr/share/man/man2/times.2.gz
> 
> I have a problem with the following sentence in times(2) manual page, 
> RETURN VALUE section:
> 
> Since Linux 2.6, this point is (2^32/HZ) - 300 (i.e., about 429 million) 
> seconds  before  system  boot time.
> 
> The problem is that in order to be able to use the return value (map it to my 
> wall-clock) I have to know the value of HZ. It appears that the value of HZ 
> depends on the kernel configuration option (recent Linux versions can have 
> 100Hz, 250Hz, 1000Hz etc), so it's not possible to compile once and use 
> the same binary on other machines. On Google I also found some discussion 
> that HZ can be 1024 on some architectures
> So this HZ variable is a very bad idea.
[..] 

A long time ago in a galaxy far .. manpages maintainer improved this and warns
the reader how much he should probably not use times() because HZ is bad.

http://git.kernel.org/?p=docs/man-pages/man-pages.git;a=commitdiff;h=5e27f149be682ba

   On Linux, the "arbitrary point in the past" from which the return value of
times() is measured has varied across kernel versions.  On Linux 2.4 and
earlier this point is the  moment the  system  was  booted.   Since  Linux
2.6, this point is (2^32/HZ) - 300 (i.e., about 429 million) seconds before
system boot time.  This variability across kernel versions (and across UNIX
implementations), combined with the fact that the returned value may overflow
the range of clock_t, means that a portable application would be wise to avoid
using  this value.  To measure changes in elapsed time, use gettimeofday(2)
instead.


-- 
Simon Paillard

--- End Message ---

Reply via email to