diff options
author | Nick Pelly <npelly@google.com> | 2010-08-26 11:21:29 -0700 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2010-08-26 11:21:29 -0700 |
commit | 6ca26ef8a78cc46dd8c779dcd7c611a247dd22c7 (patch) | |
tree | 46642bc71242669bab8d2f3645f27123ff57deae /sane_schedstat | |
parent | 7ee0b1a6ed0c09e6bf2ff9b2311267df6f201a0a (diff) | |
download | extras-6ca26ef8a78cc46dd8c779dcd7c611a247dd22c7.tar.gz |
Add a couple of performance debug utilities.
micro_bench provides very simple tests for
o sleep accuracy
o cpu
o memcpy
o memset
sane_schedstat is a front-end for /proc/schedstat to diff and format the
counters.
Change-Id: I6e178fe37fcfc9bf0a83ec17852e31146a91e7a4
Signed-off-by: Nick Pelly <npelly@google.com>
Diffstat (limited to 'sane_schedstat')
-rw-r--r-- | sane_schedstat/Android.mk | 11 | ||||
-rw-r--r-- | sane_schedstat/sane_schedstat.c | 157 |
2 files changed, 168 insertions, 0 deletions
diff --git a/sane_schedstat/Android.mk b/sane_schedstat/Android.mk new file mode 100644 index 00000000..5843c43f --- /dev/null +++ b/sane_schedstat/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := sane_schedstat.c + +LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) +LOCAL_MODULE_TAGS := debug +LOCAL_MODULE := sane_schedstat + +include $(BUILD_EXECUTABLE) diff --git a/sane_schedstat/sane_schedstat.c b/sane_schedstat/sane_schedstat.c new file mode 100644 index 00000000..29d10633 --- /dev/null +++ b/sane_schedstat/sane_schedstat.c @@ -0,0 +1,157 @@ +/* +** Copyright 2010 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +/* Opens /proc/sched_stat and diff's the counters. + Currently support version 15, modify parse() to support other + versions +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <sys/uio.h> +#include <unistd.h> +#include <sys/time.h> +#include <fcntl.h> + +#define MAX_CPU 2 + +struct cpu_stat { + /* sched_yield() stats */ + unsigned int yld_count; /* sched_yield() called */ + + /* schedule() stats */ + unsigned int sched_switch; /* switched to expired queue and reused it */ + unsigned int sched_count; /* schedule() called */ + unsigned int sched_goidle; /* schedule() left the cpu idle */ + + /* try_to_wake_up() stats */ + unsigned int ttwu_count; /* try_to_wake_up() called */ + /* try_to_wake_up() called and found the process being awakened last ran on + * the waking cpu */ + unsigned int ttwu_local; + + /* latency stats */ + unsigned long long cpu_time; /* time spent running by tasks (ms) */ + unsigned long long run_delay; /* time spent waiting to run by tasks (ms) */ + unsigned long pcount; /* number of tasks (not necessarily unique) given */ +}; + +struct cpu_stat cpu_prev[MAX_CPU]; +struct cpu_stat cpu_delta[MAX_CPU]; +struct cpu_stat tmp; + +static const char *next_line(const char *b) { + while (1) { + switch (*b) { + case '\n': + return b + 1; + case '\0': + return NULL; + } + b++; + } +} +static int print() { + int i; + + printf("CPU yield() schedule() switch idle ttwu() local cpu_time wait_time timeslices\n"); + for (i=0; i<MAX_CPU; i++) { + printf(" %2d %7u %10u %6u %4u %8u %5u %9llu %9llu %10lu\n", + i, + cpu_delta[i].yld_count, + cpu_delta[i].sched_count, cpu_delta[i].sched_switch, cpu_delta[i].sched_goidle, + cpu_delta[i].ttwu_count, cpu_delta[i].ttwu_local, + cpu_delta[i].cpu_time / 1000000, cpu_delta[i].run_delay / 1000000, cpu_delta[i].pcount); + } + return 0; +} + +static int parse_cpu_v15(const char *b) { + int cpu; + + if (sscanf(b, "cpu%d %u %u %u %u %u %u %llu %llu %lu\n", + &cpu, &tmp.yld_count, + &tmp.sched_switch, &tmp.sched_count, &tmp.sched_goidle, + &tmp.ttwu_count, &tmp.ttwu_local, + &tmp.cpu_time, &tmp.run_delay, &tmp.pcount) != 10) { + printf("Could not parse %s\n", b); + return -1; + } + + cpu_delta[cpu].yld_count = tmp.yld_count - cpu_prev[cpu].yld_count; + cpu_delta[cpu].sched_switch = tmp.sched_switch - cpu_prev[cpu].sched_switch; + cpu_delta[cpu].sched_count = tmp.sched_count - cpu_prev[cpu].sched_count; + cpu_delta[cpu].sched_goidle = tmp.sched_goidle - cpu_prev[cpu].sched_goidle; + cpu_delta[cpu].ttwu_count = tmp.ttwu_count - cpu_prev[cpu].ttwu_count; + cpu_delta[cpu].ttwu_local = tmp.ttwu_local - cpu_prev[cpu].ttwu_local; + cpu_delta[cpu].cpu_time = tmp.cpu_time - cpu_prev[cpu].cpu_time; + cpu_delta[cpu].run_delay = tmp.run_delay - cpu_prev[cpu].run_delay; + cpu_delta[cpu].pcount = tmp.pcount - cpu_prev[cpu].pcount; + + cpu_prev[cpu] = tmp; + return 0; +} + + +static int parse(const char *b) { + unsigned int version; + unsigned long long ts; + + if (sscanf(b, "version %u\n", &version) != 1) { + printf("Could not parse version\n"); + return -1; + } + switch (version) { + case 15: + b = next_line(b); + if (!b || sscanf(b, "timestamp %llu\n", &ts) != 1) { + printf("Could not parse timestamp\n"); + return -1; + } + while (1) { + b = next_line(b); + if (!b) break; + if (b[0] == 'c') { + if (parse_cpu_v15(b)) return -1; + } + } + break; + default: + printf("Can not handle version %u\n", version); + return -1; + } + return 0; +} + +int main(int argc, char **argv) { + int i; + int fd; + char buf[4096]; + + while (1) { + fd = open("/proc/schedstat", O_RDONLY); + if (fd < 0) return -1; + i = read(fd, buf, sizeof(buf) - 1); + close(fd); + buf[i] = '\0'; + if (parse(buf)) return -1; + print(); + sleep(1); + } + return 0; +} |