Projet

Général

Profil

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

root / plugins / cpu / multicpu1sec-c.c @ a720b6c9

Historique | Voir | Annoter | Télécharger (4,84 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 1f5ef093 dipohl
                "graph_category 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 0a40358f Steve Schnepp
                pid_t child_pid = fork();
99
                if (child_pid) {
100
                        printf("# acquire() launched as PID %d\n", child_pid);
101
                        return 0;
102
                }
103 16b017fc Steve Schnepp
                // we are the child, complete the daemonization
104
105
                /* Close standard IO */
106
                fclose(stdin);
107
                fclose(stdout);
108
                fclose(stderr);
109
110
                /* create new session and process group */
111
                setsid();
112
        }
113
114 9ac74f8d Steve Schnepp
        /* write the pid */
115
        FILE* pid_file = fopen(pid_filename, "w");
116
        fprintf(pid_file, "%d\n", getpid());
117
        fclose(pid_file);
118
119 9901e001 Steve Schnepp
        /* Reading /proc/stat */
120
        int f = open(PROC_STAT, O_RDONLY);
121
122
        /* open the spoolfile */
123 52905275 Steve Schnepp
        FILE* cache_file = fopen(cache_filename, "a");
124
        if (!cache_file) {
125 a720b6c9 Steve Schnepp
                return fail("cannot create cache_file");
126 52905275 Steve Schnepp
        }
127
128
        int cache_file_fd = fileno(cache_file);
129 9901e001 Steve Schnepp
130 9ac74f8d Steve Schnepp
        /* loop each second */
131
        while (1) {
132
                /* wait until next second */
133
                time_t epoch = wait_until_next_second();
134
135 7d88587f Steve Schnepp
136
                const int buffer_size = 64 * 1024;
137
                char buffer[buffer_size];
138
139 9901e001 Steve Schnepp
                if (lseek(f, 0, SEEK_SET) < 0) {
140
                        return fail("cannot seek " PROC_STAT);
141
                }
142
143 7d88587f Steve Schnepp
                // whole /proc/stat can be read in 1 syscall
144
                if (read(f, buffer, buffer_size) <= 0) {
145
                        return fail("cannot read " PROC_STAT);
146
                }
147
148
                // ignore the 1rst line
149
                char* line;
150
                const char* newl = "\n";
151
                line = strtok(buffer, newl);
152 9ac74f8d Steve Schnepp
153 7d88587f Steve Schnepp
                /* lock */
154 52905275 Steve Schnepp
                flock(cache_file_fd, LOCK_EX);
155 9ac74f8d Steve Schnepp
156 7d88587f Steve Schnepp
                for (line = strtok(NULL, newl); line; line = strtok(NULL, newl)) {
157 9ac74f8d Steve Schnepp
                        // Not on CPU lines anymore
158 7d88587f Steve Schnepp
                        if (strncmp(line, "cpu", 3)) break;
159 9ac74f8d Steve Schnepp
160
                        char cpu_id[64];
161
                        long usr, nice, sys, idle, iowait, irq, softirq;
162 7d88587f Steve Schnepp
                        sscanf(line, "%s %ld %ld %ld %ld %ld %ld %ld", cpu_id, &usr, &nice, &sys, &idle, &iowait, &irq, &softirq);
163 9ac74f8d Steve Schnepp
164 79f72b87 Steve Schnepp
                        long used = usr + nice + sys + iowait + irq + softirq;
165 9ac74f8d Steve Schnepp
166 52905275 Steve Schnepp
                        fprintf(cache_file, "%s.value %ld:%ld\n", cpu_id, epoch, used);
167
                        fflush(cache_file);
168 9ac74f8d Steve Schnepp
                }
169
170 9901e001 Steve Schnepp
                /* unlock */
171 52905275 Steve Schnepp
                flock(cache_file_fd, LOCK_UN);
172 9ac74f8d Steve Schnepp
        }
173 9901e001 Steve Schnepp
174 52905275 Steve Schnepp
        fclose(cache_file);
175 9901e001 Steve Schnepp
        close(f);
176 c5238dbc Steve Schnepp
177
        return 0;
178 81e9ffca Steve Schnepp
}
179
180
int fetch() {
181 6dec8c33 Steve Schnepp
        FILE* cache_file = fopen(cache_filename, "r+");
182 52905275 Steve Schnepp
        if (!cache_file) {
183 0a40358f Steve Schnepp
                return acquire();
184 52905275 Steve Schnepp
        }
185 9ac74f8d Steve Schnepp
186 339bfec6 Steve Schnepp
        /* lock */
187 52905275 Steve Schnepp
        int cache_file_fd = fileno(cache_file);
188
        flock(cache_file_fd, LOCK_EX);
189 339bfec6 Steve Schnepp
190 c86e4ab2 Steve Schnepp
        /* cat the cache_file to stdout */
191
        char buffer[1024];
192
        while (fgets(buffer, 1024, cache_file)) {
193
                printf("%s", buffer);
194
        }
195
196 52905275 Steve Schnepp
        ftruncate(cache_file_fd, 0);
197 c86e4ab2 Steve Schnepp
        fclose(cache_file);
198 c5238dbc Steve Schnepp
199
        return 0;
200 81e9ffca Steve Schnepp
}
201
202
int main(int argc, char **argv) {
203 308ba475 Steve Schnepp
        /* resolve paths */
204
        char *MUNIN_PLUGSTATE = getenv("MUNIN_PLUGSTATE");
205
206
        /* Default is current directory */
207
        if (! MUNIN_PLUGSTATE) MUNIN_PLUGSTATE = ".";
208
209
        size_t MUNIN_PLUGSTATE_length = strlen(MUNIN_PLUGSTATE);
210
211
        pid_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/multicpu1sec.") + strlen("pid") + 1); pid_filename[0] = '\0';
212
        cache_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/multicpu1sec.") + strlen("value") + 1); cache_filename[0] = '\0';
213
214
        strcat(pid_filename, MUNIN_PLUGSTATE);
215
        strcat(pid_filename, "/multicpu1sec.pid");
216
217
        strcat(cache_filename, MUNIN_PLUGSTATE);
218
        strcat(cache_filename, "/multicpu1sec.value");
219
220 81e9ffca Steve Schnepp
        if (argc > 1) {
221
                char* first_arg = argv[1];
222
                if (! strcmp(first_arg, "config")) {
223
                        return config();
224
                }
225
226
                if (! strcmp(first_arg, "acquire")) {
227
                        return acquire();
228
                }
229
        }
230
231
        return fetch();
232
}