]> arthur.barton.de Git - netdata.git/blob - src/global_statistics.c
global statistics now also report max API response time; global statistics implemente...
[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 pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
14
15 inline void global_statistics_lock(void) {
16     pthread_mutex_lock(&global_statistics_mutex);
17 }
18
19 inline void global_statistics_unlock(void) {
20     pthread_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 #ifndef NETDATA_NO_ATOMIC_INSTRUCTIONS
29     uint64_t old_web_usec_max = global_statistics.web_usec_max;
30     while(dt > old_web_usec_max) {
31         if(__sync_bool_compare_and_swap(&global_statistics.web_usec_max, old_web_usec_max, dt))
32             old_web_usec_max = dt;
33         else
34             old_web_usec_max = global_statistics.web_usec_max;
35     }
36
37     __sync_fetch_and_add(&global_statistics.web_requests, 1);
38     __sync_fetch_and_add(&global_statistics.web_usec, dt);
39     __sync_fetch_and_add(&global_statistics.bytes_received, bytes_received);
40     __sync_fetch_and_add(&global_statistics.bytes_sent, bytes_sent);
41     __sync_fetch_and_add(&global_statistics.content_size, content_size);
42     __sync_fetch_and_add(&global_statistics.compressed_content_size, compressed_content_size);
43 #else
44     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
45         global_statistics_lock();
46
47     if (dt > global_statistics.web_usec_max)
48         global_statistics.web_usec_max = dt;
49
50     global_statistics.web_requests++;
51     global_statistics.web_usec += dt;
52     global_statistics.bytes_received += bytes_received;
53     global_statistics.bytes_sent += bytes_sent;
54     global_statistics.content_size += content_size;
55     global_statistics.compressed_content_size += compressed_content_size;
56
57     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
58         global_statistics_unlock();
59 #endif
60 }
61
62 void web_client_connected(void) {
63 #ifndef NETDATA_NO_ATOMIC_INSTRUCTIONS
64     __sync_fetch_and_add(&global_statistics.connected_clients, 1);
65 #else
66     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
67         global_statistics_lock();
68
69     global_statistics.connected_clients++;
70
71     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
72         global_statistics_unlock();
73 #endif
74 }
75
76 void web_client_disconnected(void) {
77 #ifndef NETDATA_NO_ATOMIC_INSTRUCTIONS
78     __sync_fetch_and_sub(&global_statistics.connected_clients, 1);
79 #else
80     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
81         global_statistics_lock();
82
83     global_statistics.connected_clients--;
84
85     if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
86         global_statistics_unlock();
87 #endif
88 }
89
90
91 inline void global_statistics_copy(struct global_statistics *gs, uint8_t options) {
92 #ifndef NETDATA_NO_ATOMIC_INSTRUCTIONS
93     gs->connected_clients       = __sync_fetch_and_add(&global_statistics.connected_clients, 0);
94     gs->web_requests            = __sync_fetch_and_add(&global_statistics.web_requests, 0);
95     gs->web_usec                = __sync_fetch_and_add(&global_statistics.web_usec, 0);
96     gs->web_usec_max            = __sync_fetch_and_add(&global_statistics.web_usec_max, 0);
97     gs->bytes_received          = __sync_fetch_and_add(&global_statistics.bytes_received, 0);
98     gs->bytes_sent              = __sync_fetch_and_add(&global_statistics.bytes_sent, 0);
99     gs->content_size            = __sync_fetch_and_add(&global_statistics.content_size, 0);
100     gs->compressed_content_size = __sync_fetch_and_add(&global_statistics.compressed_content_size, 0);
101
102     if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX)
103         __sync_bool_compare_and_swap(&global_statistics.web_usec_max, gs->web_usec_max, 0);
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     if (!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_proc_cpu");
133     if (!stcpu_thread) {
134         stcpu_thread = rrdset_create("netdata", "plugin_proc_cpu", NULL, "proc.internal", NULL,
135                                      "NetData Proc Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every,
136                                      RRDSET_TYPE_STACKED);
137
138         rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
139         rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
140     } else rrdset_next(stcpu_thread);
141
142     rrddim_set(stcpu_thread, "user", thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
143     rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
144     rrdset_done(stcpu_thread);
145
146     // ----------------------------------------------------------------
147
148     if (!stcpu) stcpu = rrdset_find("netdata.server_cpu");
149     if (!stcpu) {
150         stcpu = rrdset_create("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage", "milliseconds/s",
151                               130000, rrd_update_every, RRDSET_TYPE_STACKED);
152
153         rrddim_add(stcpu, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
154         rrddim_add(stcpu, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
155     } else rrdset_next(stcpu);
156
157     rrddim_set(stcpu, "user", me.ru_utime.tv_sec * 1000000ULL + me.ru_utime.tv_usec);
158     rrddim_set(stcpu, "system", me.ru_stime.tv_sec * 1000000ULL + me.ru_stime.tv_usec);
159     rrdset_done(stcpu);
160
161     // ----------------------------------------------------------------
162
163     if (!stclients) stclients = rrdset_find("netdata.clients");
164     if (!stclients) {
165         stclients = rrdset_create("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients",
166                                   "connected clients", 130100, rrd_update_every, RRDSET_TYPE_LINE);
167
168         rrddim_add(stclients, "clients", NULL, 1, 1, RRDDIM_ABSOLUTE);
169     } else rrdset_next(stclients);
170
171     rrddim_set(stclients, "clients", gs.connected_clients);
172     rrdset_done(stclients);
173
174     // ----------------------------------------------------------------
175
176     if (!streqs) streqs = rrdset_find("netdata.requests");
177     if (!streqs) {
178         streqs = rrdset_create("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests", "requests/s",
179                                130200, rrd_update_every, RRDSET_TYPE_LINE);
180
181         rrddim_add(streqs, "requests", NULL, 1, 1, RRDDIM_INCREMENTAL);
182     } else rrdset_next(streqs);
183
184     rrddim_set(streqs, "requests", (collected_number) gs.web_requests);
185     rrdset_done(streqs);
186
187     // ----------------------------------------------------------------
188
189     if (!stbytes) stbytes = rrdset_find("netdata.net");
190     if (!stbytes) {
191         stbytes = rrdset_create("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic", "kilobits/s",
192                                 130300, rrd_update_every, RRDSET_TYPE_AREA);
193
194         rrddim_add(stbytes, "in", NULL, 8, 1024, RRDDIM_INCREMENTAL);
195         rrddim_add(stbytes, "out", NULL, -8, 1024, RRDDIM_INCREMENTAL);
196     } else rrdset_next(stbytes);
197
198     rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
199     rrddim_set(stbytes, "out", (collected_number) gs.bytes_sent);
200     rrdset_done(stbytes);
201
202     // ----------------------------------------------------------------
203
204     if (!stduration) stduration = rrdset_find("netdata.response_time");
205     if (!stduration) {
206         stduration = rrdset_create("netdata", "response_time", NULL, "netdata", NULL, "NetData API Response Time",
207                                    "ms/request", 130400, rrd_update_every, RRDSET_TYPE_LINE);
208
209         rrddim_add(stduration, "average", NULL, 1, 1000, RRDDIM_ABSOLUTE);
210         rrddim_add(stduration, "max", NULL, 1, 1000, RRDDIM_ABSOLUTE);
211     } else rrdset_next(stduration);
212
213     uint64_t gweb_usec = gs.web_usec;
214     uint64_t gweb_requests = gs.web_requests;
215
216     uint64_t web_usec = (gweb_usec >= old_web_usec) ? gweb_usec - old_web_usec : 0;
217     uint64_t web_requests = (gweb_requests >= old_web_requests) ? gweb_requests - old_web_requests : 0;
218
219     old_web_usec = gweb_usec;
220     old_web_requests = gweb_requests;
221
222     if (web_requests)
223         average_response_time = (collected_number) (web_usec / web_requests);
224
225     if (unlikely(average_response_time != -1))
226         rrddim_set(stduration, "average", average_response_time);
227     else
228         rrddim_set(stduration, "average", 0);
229
230     rrddim_set(stduration, "max", ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time));
231     rrdset_done(stduration);
232
233     // ----------------------------------------------------------------
234
235     if (!stcompression) stcompression = rrdset_find("netdata.compression_ratio");
236     if (!stcompression) {
237         stcompression = rrdset_create("netdata", "compression_ratio", NULL, "netdata", NULL,
238                                       "NetData API Responses Compression Savings Ratio", "percentage", 130500,
239                                       rrd_update_every, RRDSET_TYPE_LINE);
240
241         rrddim_add(stcompression, "savings", NULL, 1, 1000, RRDDIM_ABSOLUTE);
242     } else rrdset_next(stcompression);
243
244     // since we don't lock here to read the global statistics
245     // read the smaller value first
246     unsigned long long gcompressed_content_size = gs.compressed_content_size;
247     unsigned long long gcontent_size = gs.content_size;
248
249     unsigned long long compressed_content_size = gcompressed_content_size - old_compressed_content_size;
250     unsigned long long content_size = gcontent_size - old_content_size;
251
252     old_compressed_content_size = gcompressed_content_size;
253     old_content_size = gcontent_size;
254
255     if (content_size && content_size >= compressed_content_size)
256         compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
257
258     if (compression_ratio != -1)
259         rrddim_set(stcompression, "savings", compression_ratio);
260
261     rrdset_done(stcompression);
262 }