Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / system / multicpu1sec / multicpu1sec-c.c @ d0216f00

Historique | Voir | Annoter | Télécharger (4,65 ko)

1 81e9ffca Steve Schnepp
/*
2
 * multicpu1sec C plugin
3
 */
4 16b017fc Steve Schnepp
#include <stdlib.h>
5 81e9ffca Steve Schnepp
#include <stdio.h>
6
#include <string.h>
7 9ac74f8d Steve Schnepp
#include <unistd.h>
8 7d88587f Steve Schnepp
#include <fcntl.h>
9 9ac74f8d Steve Schnepp
10
#include <time.h>
11 81e9ffca Steve Schnepp
12 339bfec6 Steve Schnepp
#include <sys/file.h>
13
14 81e9ffca Steve Schnepp
#define PROC_STAT "/proc/stat"
15
16
int fail(char* msg) {
17
        perror(msg);
18
19
        return 1;
20
}
21
22
int config() {
23
        /* Get the number of CPU */
24 2db160e2 Steve Schnepp
        int f;
25
        if ( !(f=open(PROC_STAT, O_RDONLY)) ) {
26 81e9ffca Steve Schnepp
                return fail("cannot open " PROC_STAT);
27
        }
28
29
        // Starting with -1, since the first line is the "global cpu line"
30
        int ncpu = -1;
31
32 2db160e2 Steve Schnepp
        const int buffer_size = 64 * 1024;
33
        char buffer[buffer_size];
34
35
        // whole /proc/stat can be read in 1 syscall
36
        if (read(f, buffer, buffer_size) <= 0) {
37
                return fail("cannot read " PROC_STAT);
38
        }
39
40
        // tokenization per-line
41
        char* line;
42
        char* newl = "\n";
43
        for (line = strtok(buffer, newl); line; line = strtok(NULL, newl)) {
44
                if (! strncmp(line, "cpu", 3)) ncpu ++;
45 81e9ffca Steve Schnepp
        }
46
47 2db160e2 Steve Schnepp
        close(f);
48 81e9ffca Steve Schnepp
49
        printf(
50
                "graph_title multicpu1sec\n"
51
                "graph_category system::1sec\n"
52 9ac74f8d Steve Schnepp
                "graph_vlabel average cpu use %%\n"
53 81e9ffca Steve Schnepp
                "graph_scale no\n"
54
                "graph_total All CPUs\n"
55
                "update_rate 1\n"
56
                "graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y\n"
57
        );
58
59
        int i;
60
        for (i = 0; i < ncpu; i++) {
61
                printf("cpu%d.label CPU %d\n", i, i);
62
                printf("cpu%d.draw %s\n", i, "AREASTACK");
63 b0e8dcea Steve Schnepp
                printf("cpu%d.type %s\n", i, "DERIVE");
64 81e9ffca Steve Schnepp
                printf("cpu%d.min 0\n", i);
65
        }
66
67
68 9ac74f8d Steve Schnepp
        return 0;
69
}
70
71 308ba475 Steve Schnepp
char* pid_filename;
72
char* cache_filename;
73 9ac74f8d Steve Schnepp
74
/* Wait until the next second, and return the EPOCH */
75
time_t wait_until_next_second() {
76
        struct timespec tp;
77
        clock_gettime(CLOCK_REALTIME, &tp);
78
79
        time_t current_epoch = tp.tv_sec;
80
        long nsec_to_sleep = 1000*1000*1000 - tp.tv_nsec;
81
82
83
        /* Only sleep if needed */
84
        if (nsec_to_sleep > 0) {
85
                tp.tv_sec = 0;
86
                tp.tv_nsec = nsec_to_sleep;
87
                nanosleep(&tp, NULL);
88
        }
89
90
        return current_epoch + 1;
91 81e9ffca Steve Schnepp
}
92
93
int acquire() {
94 9ac74f8d Steve Schnepp
95 16b017fc Steve Schnepp
        /* fork ourselves if not asked otherwise */
96
        char* no_fork = getenv("no_fork");
97
        if (! no_fork || strcmp("1", no_fork)) {
98
                if (fork()) return;
99
                // we are the child, complete the daemonization
100
101
                /* Close standard IO */
102
                fclose(stdin);
103
                fclose(stdout);
104
                fclose(stderr);
105
106
                /* create new session and process group */
107
                setsid();
108
        }
109
110 9ac74f8d Steve Schnepp
        /* write the pid */
111
        FILE* pid_file = fopen(pid_filename, "w");
112
        fprintf(pid_file, "%d\n", getpid());
113
        fclose(pid_file);
114
115 9901e001 Steve Schnepp
        /* Reading /proc/stat */
116
        int f = open(PROC_STAT, O_RDONLY);
117
118
        /* open the spoolfile */
119
        int cache_file = open(cache_filename, O_CREAT | O_APPEND | O_WRONLY);
120
121 9ac74f8d Steve Schnepp
        /* loop each second */
122
        while (1) {
123
                /* wait until next second */
124
                time_t epoch = wait_until_next_second();
125
126 7d88587f Steve Schnepp
127
                const int buffer_size = 64 * 1024;
128
                char buffer[buffer_size];
129
130 9901e001 Steve Schnepp
                if (lseek(f, 0, SEEK_SET) < 0) {
131
                        return fail("cannot seek " PROC_STAT);
132
                }
133
134 7d88587f Steve Schnepp
                // whole /proc/stat can be read in 1 syscall
135
                if (read(f, buffer, buffer_size) <= 0) {
136
                        return fail("cannot read " PROC_STAT);
137
                }
138
139
                // ignore the 1rst line
140
                char* line;
141
                const char* newl = "\n";
142
                line = strtok(buffer, newl);
143 9ac74f8d Steve Schnepp
144 7d88587f Steve Schnepp
                /* lock */
145
                flock(cache_file, LOCK_EX);
146 9ac74f8d Steve Schnepp
147 7d88587f Steve Schnepp
                for (line = strtok(NULL, newl); line; line = strtok(NULL, newl)) {
148 9ac74f8d Steve Schnepp
                        // Not on CPU lines anymore
149 7d88587f Steve Schnepp
                        if (strncmp(line, "cpu", 3)) break;
150 9ac74f8d Steve Schnepp
151
                        char cpu_id[64];
152
                        long usr, nice, sys, idle, iowait, irq, softirq;
153 7d88587f Steve Schnepp
                        sscanf(line, "%s %ld %ld %ld %ld %ld %ld %ld", cpu_id, &usr, &nice, &sys, &idle, &iowait, &irq, &softirq);
154 9ac74f8d Steve Schnepp
155 79f72b87 Steve Schnepp
                        long used = usr + nice + sys + iowait + irq + softirq;
156 9ac74f8d Steve Schnepp
157 7d88587f Steve Schnepp
                        char out_buffer[1024];
158
                        sprintf(out_buffer, "%s.value %ld:%ld\n", cpu_id, epoch, used);
159
160
                        write(cache_file, out_buffer, strlen(out_buffer));
161 9ac74f8d Steve Schnepp
                }
162
163 9901e001 Steve Schnepp
                /* unlock */
164
                flock(cache_file, LOCK_UN);
165 9ac74f8d Steve Schnepp
        }
166 9901e001 Steve Schnepp
167
        close(cache_file);
168
        close(f);
169 c5238dbc Steve Schnepp
170
        return 0;
171 81e9ffca Steve Schnepp
}
172
173
int fetch() {
174 6dec8c33 Steve Schnepp
        FILE* cache_file = fopen(cache_filename, "r+");
175 9ac74f8d Steve Schnepp
176 339bfec6 Steve Schnepp
        /* lock */
177
        flock(fileno(cache_file), LOCK_EX);
178
179 c86e4ab2 Steve Schnepp
        /* cat the cache_file to stdout */
180
        char buffer[1024];
181
        while (fgets(buffer, 1024, cache_file)) {
182
                printf("%s", buffer);
183
        }
184
185
        ftruncate(fileno(cache_file), 0);
186
        fclose(cache_file);
187 c5238dbc Steve Schnepp
188
        return 0;
189 81e9ffca Steve Schnepp
}
190
191
int main(int argc, char **argv) {
192 308ba475 Steve Schnepp
        /* resolve paths */
193
        char *MUNIN_PLUGSTATE = getenv("MUNIN_PLUGSTATE");
194
195
        /* Default is current directory */
196
        if (! MUNIN_PLUGSTATE) MUNIN_PLUGSTATE = ".";
197
198
        size_t MUNIN_PLUGSTATE_length = strlen(MUNIN_PLUGSTATE);
199
200
        pid_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/multicpu1sec.") + strlen("pid") + 1); pid_filename[0] = '\0';
201
        cache_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/multicpu1sec.") + strlen("value") + 1); cache_filename[0] = '\0';
202
203
        strcat(pid_filename, MUNIN_PLUGSTATE);
204
        strcat(pid_filename, "/multicpu1sec.pid");
205
206
        strcat(cache_filename, MUNIN_PLUGSTATE);
207
        strcat(cache_filename, "/multicpu1sec.value");
208
209 81e9ffca Steve Schnepp
        if (argc > 1) {
210
                char* first_arg = argv[1];
211
                if (! strcmp(first_arg, "config")) {
212
                        return config();
213
                }
214
215
                if (! strcmp(first_arg, "acquire")) {
216
                        return acquire();
217
                }
218
        }
219
220
        return fetch();
221
}