]> arthur.barton.de Git - netdata.git/blob - src/global_statistics.c
Merge pull request #1998 from ktsaou/master
[netdata.git] / src / global_statistics.c
1 #include "common.h"
2
3 volatile struct global_statistics global_statistics = {
4         .connected_clients = 0,
5         .web_requests = 0,
6         .web_usec = 0,
7         .bytes_received = 0,
8         .bytes_sent = 0,
9         .content_size = 0,
10         .compressed_content_size = 0
11 };
12
13 netdata_mutex_t global_statistics_mutex = NETDATA_MUTEX_INITIALIZER;
14
15 inline void global_statistics_lock(void) {
16     netdata_mutex_lock(&global_statistics_mutex);
17 }
18
19 inline void global_statistics_unlock(void) {
20     netdata_mutex_unlock(&global_statistics_mutex);
21 }
22
23 void finished_web_request_statistics(uint64_t dt,
24                                      uint64_t bytes_received,
25                                      uint64_t bytes_sent,
26                                      uint64_t content_size,
27                                      uint64_t compressed_content_size) {
28 #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
29     uint64_t old_web_usec_max = global_statistics.web_usec_max;
30     while(dt > old_web_usec_max)
31         __atomic_compare_exchange(&global_statistics.web_usec_max, &old_web_usec_max, &dt, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
32
33     __atomic_fetch_add(&global_statistics.web_requests, 1, __ATOMIC_SEQ_CST);
34     __atomic_fetch_add(&global_statistics.web_usec, dt, __ATOMIC_SEQ_CST);
35     __atomic_fetch_add(&global_statistics.bytes_received, bytes_received, __ATOMIC_SEQ_CST);
36     __atomic_fetch_add(&global_statistics.bytes_sent, bytes_sent, __ATOMIC_SEQ_CST);
37     __atomic_fetch_add(&global_statistics.content_size, content_size, __ATOMIC_SEQ_CST);
38     __atomic_fetch_add(&global_statistics.compressed_content_size, compressed_content_size, __ATOMIC_SEQ_CST);
39 #else
40 #warning NOT using atomic operations - using locks for global statistics
41     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
42         global_statistics_lock();
43
44     if (dt > global_statistics.web_usec_max)
45         global_statistics.web_usec_max = dt;
46
47     global_statistics.web_requests++;
48     global_statistics.web_usec += dt;
49     global_statistics.bytes_received += bytes_received;
50     global_statistics.bytes_sent += bytes_sent;
51     global_statistics.content_size += content_size;
52     global_statistics.compressed_content_size += compressed_content_size;
53
54     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
55         global_statistics_unlock();
56 #endif
57 }
58
59 void web_client_connected(void) {
60 #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
61     __atomic_fetch_add(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST);
62 #else
63     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
64         global_statistics_lock();
65
66     global_statistics.connected_clients++;
67
68     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
69         global_statistics_unlock();
70 #endif
71 }
72
73 void web_client_disconnected(void) {
74 #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
75     __atomic_fetch_sub(&global_statistics.connected_clients, 1, __ATOMIC_SEQ_CST);
76 #else
77     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
78         global_statistics_lock();
79
80     global_statistics.connected_clients--;
81
82     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
83         global_statistics_unlock();
84 #endif
85 }
86
87
88 inline void global_statistics_copy(struct global_statistics *gs, uint8_t options) {
89 #if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
90     gs->connected_clients       = __atomic_fetch_add(&global_statistics.connected_clients, 0, __ATOMIC_SEQ_CST);
91     gs->web_requests            = __atomic_fetch_add(&global_statistics.web_requests, 0, __ATOMIC_SEQ_CST);
92     gs->web_usec                = __atomic_fetch_add(&global_statistics.web_usec, 0, __ATOMIC_SEQ_CST);
93     gs->web_usec_max            = __atomic_fetch_add(&global_statistics.web_usec_max, 0, __ATOMIC_SEQ_CST);
94     gs->bytes_received          = __atomic_fetch_add(&global_statistics.bytes_received, 0, __ATOMIC_SEQ_CST);
95     gs->bytes_sent              = __atomic_fetch_add(&global_statistics.bytes_sent, 0, __ATOMIC_SEQ_CST);
96     gs->content_size            = __atomic_fetch_add(&global_statistics.content_size, 0, __ATOMIC_SEQ_CST);
97     gs->compressed_content_size = __atomic_fetch_add(&global_statistics.compressed_content_size, 0, __ATOMIC_SEQ_CST);
98
99     if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX) {
100         uint64_t n = 0;
101         __atomic_compare_exchange(&global_statistics.web_usec_max, &gs->web_usec_max, &n, 1, __ATOMIC_SEQ_CST,
102                                   __ATOMIC_SEQ_CST);
103     }
104 #else
105     global_statistics_lock();
106
107     memcpy(gs, (const void *)&global_statistics, sizeof(struct global_statistics));
108
109     if (options & GLOBAL_STATS_RESET_WEB_USEC_MAX)
110         global_statistics.web_usec_max = 0;
111
112     global_statistics_unlock();
113 #endif
114 }
115
116 void global_statistics_charts(void) {
117     static unsigned long long old_web_requests = 0, old_web_usec = 0,
118             old_content_size = 0, old_compressed_content_size = 0;
119
120     static collected_number compression_ratio = -1, average_response_time = -1;
121
122     static RRDSET *stcpu = NULL, *stcpu_thread = NULL, *stclients = NULL, *streqs = NULL, *stbytes = NULL, *stduration = NULL,
123             *stcompression = NULL;
124
125     struct global_statistics gs;
126     struct rusage me, thread;
127
128     global_statistics_copy(&gs, GLOBAL_STATS_RESET_WEB_USEC_MAX);
129     getrusage(RUSAGE_THREAD, &thread);
130     getrusage(RUSAGE_SELF, &me);
131
132 #ifdef __FreeBSD__
133     if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_freebsd_cpu");
134     if (!stcpu_thread) {
135         stcpu_thread = rrdset_create_localhost("netdata", "plugin_freebsd_cpu", NULL, "freebsd", NULL
136                                                , "NetData FreeBSD Plugin CPU usage", "milliseconds/s", 132000
137                                                , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
138 #else
139     if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_proc_cpu");
140     if (!stcpu_thread) {
141         stcpu_thread = rrdset_create_localhost("netdata", "plugin_proc_cpu", NULL, "proc", NULL
142                                                , "NetData Proc Plugin CPU usage", "milliseconds/s", 132000
143                                                , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
144 #endif
145
146         rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
147         rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
148     } else rrdset_next(stcpu_thread);
149
150     rrddim_set(stcpu_thread, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
151     rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
152     rrdset_done(stcpu_thread);
153
154     // ----------------------------------------------------------------
155
156     if (!stcpu) stcpu = rrdset_find_localhost("netdata.server_cpu");
157     if (!stcpu) {
158         stcpu = rrdset_create_localhost("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage"
159                                         , "milliseconds/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_STACKED);
160
161         rrddim_add(stcpu, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
162         rrddim_add(stcpu, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
163     } else rrdset_next(stcpu);
164
165     rrddim_set(stcpu, "user", me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec);
166     rrddim_set(stcpu, "system", me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec);
167     rrdset_done(stcpu);
168
169     // ----------------------------------------------------------------
170
171     if (!stclients) stclients = rrdset_find_localhost("netdata.clients");
172     if (!stclients) {
173         stclients = rrdset_create_localhost("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients"
174                                             , "connected clients", 130200, localhost->rrd_update_every, RRDSET_TYPE_LINE);
175
176         rrddim_add(stclients, "clients", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
177     } else rrdset_next(stclients);
178
179     rrddim_set(stclients, "clients", gs.connected_clients);
180     rrdset_done(stclients);
181
182     // ----------------------------------------------------------------
183
184     if (!streqs) streqs = rrdset_find_localhost("netdata.requests");
185     if (!streqs) {
186         streqs = rrdset_create_localhost("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests"
187                                          , "requests/s", 130300, localhost->rrd_update_every, RRDSET_TYPE_LINE);
188
189         rrddim_add(streqs, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
190     } else rrdset_next(streqs);
191
192     rrddim_set(streqs, "requests", (collected_number) gs.web_requests);
193     rrdset_done(streqs);
194
195     // ----------------------------------------------------------------
196
197     if (!stbytes) stbytes = rrdset_find_localhost("netdata.net");
198     if (!stbytes) {
199         stbytes = rrdset_create_localhost("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic"
200                                           , "kilobits/s", 130000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
201
202         rrddim_add(stbytes, "in", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
203         rrddim_add(stbytes, "out", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
204     } else rrdset_next(stbytes);
205
206     rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
207     rrddim_set(stbytes, "out", (collected_number) gs.bytes_sent);
208     rrdset_done(stbytes);
209
210     // ----------------------------------------------------------------
211
212     if (!stduration) stduration = rrdset_find_localhost("netdata.response_time");
213     if (!stduration) {
214         stduration = rrdset_create_localhost("netdata", "response_time", NULL, "netdata", NULL
215                                              , "NetData API Response Time", "ms/request", 130400, localhost->rrd_update_every
216                                              , RRDSET_TYPE_LINE);
217
218         rrddim_add(stduration, "average", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
219         rrddim_add(stduration, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
220     } else rrdset_next(stduration);
221
222     uint64_t gweb_usec = gs.web_usec;
223     uint64_t gweb_requests = gs.web_requests;
224
225     uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0;
226     uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0;
227
228     old_web_usec = gweb_usec;
229     old_web_requests = gweb_requests;
230
231     if (web_requests)
232         average_response_time = (collected_number) (web_usec / web_requests);
233
234     if (unlikely(average_response_time != -1))
235         rrddim_set(stduration, "average", average_response_time);
236     else
237         rrddim_set(stduration, "average", 0);
238
239     rrddim_set(stduration, "max", ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time));
240     rrdset_done(stduration);
241
242     // ----------------------------------------------------------------
243
244     if (!stcompression) stcompression = rrdset_find_localhost("netdata.compression_ratio");
245     if (!stcompression) {
246         stcompression = rrdset_create_localhost("netdata", "compression_ratio", NULL, "netdata", NULL
247                                                 , "NetData API Responses Compression Savings Ratio", "percentage"
248                                                 , 130500, localhost->rrd_update_every, RRDSET_TYPE_LINE);
249
250         rrddim_add(stcompression, "savings", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
251     } else rrdset_next(stcompression);
252
253     // since we don't lock here to read the global statistics
254     // read the smaller value first
255     unsigned long long gcompressed_content_size = gs.compressed_content_size;
256     unsigned long long gcontent_size = gs.content_size;
257
258     unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size;
259     unsigned long long content_size = gcontent_size - old_content_size;
260
261     old_compressed_content_size = gcompressed_content_size;
262     old_content_size = gcontent_size;
263
264     if (content_size && content_size >= compressed_content_size)
265         compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
266
267     if (compression_ratio != -1)
268         rrddim_set(stcompression, "savings", compression_ratio);
269
270     rrdset_done(stcompression);
271 }