diff options
author | Karel Zak <kzak@redhat.com> | 2014-07-31 10:15:39 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2014-08-03 01:12:53 -0400 |
commit | c358d728e7d6bf38a0176a9d5d013c6e972cddbf (patch) | |
tree | 8a27c6735605fb635811690b2d474a40a1be983e | |
parent | 799a8f39d8eb9ea725e85a598c0f5dbd658c8ba7 (diff) |
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.
-rw-r--r-- | man/systemd-bootchart.xml | 4 | ||||
-rw-r--r-- | src/bootchart/bootchart.c | 11 | ||||
-rw-r--r-- | src/bootchart/store.c | 29 |
3 files changed, 22 insertions, 22 deletions
diff --git a/man/systemd-bootchart.xml b/man/systemd-bootchart.xml index e19bbc11d4..150ca48f39 100644 --- a/man/systemd-bootchart.xml +++ b/man/systemd-bootchart.xml @@ -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> diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 0ae72c29bb..fc00b4e3f2 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -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(); diff --git a/src/bootchart/store.c b/src/bootchart/store.c index e0719838d5..cedcba88ed 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -57,27 +57,22 @@ double gettime_ns(void) { 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); +static double gettime_up(void) { + struct timespec n; - log_start = gettime_ns(); + clock_gettime(CLOCK_BOOTTIME, &n); + return (n.tv_sec + (n.tv_nsec / 1000000000.0)); +} - /* start graph at kernel boot time */ +void log_uptime(void) { 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) { |