summaryrefslogtreecommitdiff
path: root/sane_schedstat/sane_schedstat.c
blob: 29d10633fecd55f401a25073178dc8ab3ad30af9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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;
}