bootchart: don't parse /proc/uptime, use CLOCK_BOOTTIME

* systemd-bootchart always parses /proc/uptime, although the
  information is unnecessary when --rel specified

* use /proc/uptime is overkill, since Linux 2.6.39 we have
  clock_gettime(CLOCK_BOOTTIME, ...). The backend on kernel side is
  get_monotonic_boottime() in both cases.

* main() uses "if (graph_start <= 0.0)" to detect that /proc is
  available.

  This is fragile solution as graph_start is always smaller than zero
  on all systems after suspend/resume (e.g. laptops), because in this
  case the system uptime includes suspend time and uptime is always
  greater number than monotonic time. For example right now difference
  between uptime and monotonic time is 37 hours on my laptop.

  Note that main() calls log_uptime() (to parse /proc/uptime) for each
  sample when it believes that /proc is not available. So on my laptop
  systemd-boochars spends all live with /proc/uptime parsing +
  nanosleep(), try

    strace  /usr/lib/systemd/systemd-bootchart

  to see the never ending loop.

  This patch uses access("/proc/vmstat", F_OK) to detect procfs.
This commit is contained in:
Karel Zak 2014-07-31 10:15:39 +02:00 committed by Zbigniew Jędrzejewski-Szmek
parent 799a8f39d8
commit c358d728e7
3 changed files with 23 additions and 23 deletions

View File

@ -131,7 +131,9 @@
not graph the time elapsed since boot
and before systemd-bootchart was
started, as it may result in extremely
large graphs. </para></listitem>
large graphs. The time elapsed since boot
might also include any time that the system
was suspended.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -310,6 +310,7 @@ int main(int argc, char *argv[]) {
time_t t = 0;
int r;
struct rlimit rlim;
bool has_procfs = false;
parse_conf();
@ -349,6 +350,8 @@ int main(int argc, char *argv[]) {
log_uptime();
has_procfs = access("/proc/vmstat", F_OK) == 0;
LIST_HEAD_INIT(head);
/* main program loop */
@ -385,11 +388,11 @@ int main(int argc, char *argv[]) {
parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL);
}
/* wait for /proc to become available, discarding samples */
if (graph_start <= 0.0)
log_uptime();
else
if (has_procfs)
log_sample(samples, &sampledata);
else
/* wait for /proc to become available, discarding samples */
has_procfs = access("/proc/vmstat", F_OK) == 0;
sample_stop = gettime_ns();

View File

@ -57,27 +57,22 @@ double gettime_ns(void) {
return (n.tv_sec + (n.tv_nsec / 1000000000.0));
}
static double gettime_up(void) {
struct timespec n;
clock_gettime(CLOCK_BOOTTIME, &n);
return (n.tv_sec + (n.tv_nsec / 1000000000.0));
}
void log_uptime(void) {
_cleanup_fclose_ FILE *f = NULL;
char str[32];
double uptime;
f = fopen("/proc/uptime", "re");
if (!f)
return;
if (!fscanf(f, "%s %*s", str))
return;
uptime = strtod(str, NULL);
log_start = gettime_ns();
/* start graph at kernel boot time */
if (arg_relative)
graph_start = log_start;
else
graph_start = log_start = gettime_ns();
else {
double uptime = gettime_up();
log_start = gettime_ns();
graph_start = log_start - uptime;
}
}
static char *bufgetline(char *buf) {