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


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to