3 volatile struct global_statistics global_statistics = {
4 .connected_clients = 0,
10 .compressed_content_size = 0
13 pthread_mutex_t global_statistics_mutex = PTHREAD_MUTEX_INITIALIZER;
15 inline void global_statistics_lock(void) {
16 pthread_mutex_lock(&global_statistics_mutex);
19 inline void global_statistics_unlock(void) {
20 pthread_mutex_unlock(&global_statistics_mutex);
23 void finished_web_request_statistics(uint64_t dt,
24 uint64_t bytes_received,
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);
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);
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();
44 if (dt > global_statistics.web_usec_max)
45 global_statistics.web_usec_max = dt;
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;
54 if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
55 global_statistics_unlock();
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);
63 if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
64 global_statistics_lock();
66 global_statistics.connected_clients++;
68 if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
69 global_statistics_unlock();
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);
77 if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
78 global_statistics_lock();
80 global_statistics.connected_clients--;
82 if (web_server_mode == WEB_SERVER_MODE_MULTI_THREADED)
83 global_statistics_unlock();
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);
99 if(options & GLOBAL_STATS_RESET_WEB_USEC_MAX) {
101 __atomic_compare_exchange(&global_statistics.web_usec_max, &gs->web_usec_max, &n, 1, __ATOMIC_SEQ_CST,
105 global_statistics_lock();
107 memcpy(gs, (const void *)&global_statistics, sizeof(struct global_statistics));
109 if (options & GLOBAL_STATS_RESET_WEB_USEC_MAX)
110 global_statistics.web_usec_max = 0;
112 global_statistics_unlock();
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;
120 static collected_number compression_ratio = -1, average_response_time = -1;
122 static RRDSET *stcpu = NULL, *stcpu_thread = NULL, *stclients = NULL, *streqs = NULL, *stbytes = NULL, *stduration = NULL,
123 *stcompression = NULL;
125 struct global_statistics gs;
126 struct rusage me, thread;
128 global_statistics_copy(&gs, GLOBAL_STATS_RESET_WEB_USEC_MAX);
129 getrusage(RUSAGE_THREAD, &thread);
130 getrusage(RUSAGE_SELF, &me);
132 if (!stcpu_thread) stcpu_thread = rrdset_find("netdata.plugin_proc_cpu");
134 stcpu_thread = rrdset_create("netdata", "plugin_proc_cpu", NULL, "proc", NULL,
135 "NetData Proc Plugin CPU usage", "milliseconds/s", 132000, rrd_update_every,
136 RRDSET_TYPE_STACKED);
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);
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);
146 // ----------------------------------------------------------------
148 if (!stcpu) stcpu = rrdset_find("netdata.server_cpu");
150 stcpu = rrdset_create("netdata", "server_cpu", NULL, "netdata", NULL, "NetData CPU usage", "milliseconds/s",
151 130000, rrd_update_every, RRDSET_TYPE_STACKED);
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);
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);
161 // ----------------------------------------------------------------
163 if (!stclients) stclients = rrdset_find("netdata.clients");
165 stclients = rrdset_create("netdata", "clients", NULL, "netdata", NULL, "NetData Web Clients",
166 "connected clients", 130200, rrd_update_every, RRDSET_TYPE_LINE);
168 rrddim_add(stclients, "clients", NULL, 1, 1, RRDDIM_ABSOLUTE);
169 } else rrdset_next(stclients);
171 rrddim_set(stclients, "clients", gs.connected_clients);
172 rrdset_done(stclients);
174 // ----------------------------------------------------------------
176 if (!streqs) streqs = rrdset_find("netdata.requests");
178 streqs = rrdset_create("netdata", "requests", NULL, "netdata", NULL, "NetData Web Requests", "requests/s",
179 130300, rrd_update_every, RRDSET_TYPE_LINE);
181 rrddim_add(streqs, "requests", NULL, 1, 1, RRDDIM_INCREMENTAL);
182 } else rrdset_next(streqs);
184 rrddim_set(streqs, "requests", (collected_number) gs.web_requests);
187 // ----------------------------------------------------------------
189 if (!stbytes) stbytes = rrdset_find("netdata.net");
191 stbytes = rrdset_create("netdata", "net", NULL, "netdata", NULL, "NetData Network Traffic", "kilobits/s",
192 130000, rrd_update_every, RRDSET_TYPE_AREA);
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);
198 rrddim_set(stbytes, "in", (collected_number) gs.bytes_received);
199 rrddim_set(stbytes, "out", (collected_number) gs.bytes_sent);
200 rrdset_done(stbytes);
202 // ----------------------------------------------------------------
204 if (!stduration) stduration = rrdset_find("netdata.response_time");
206 stduration = rrdset_create("netdata", "response_time", NULL, "netdata", NULL, "NetData API Response Time",
207 "ms/request", 130400, rrd_update_every, RRDSET_TYPE_LINE);
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);
213 uint64_t gweb_usec = gs.web_usec;
214 uint64_t gweb_requests = gs.web_requests;
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;
219 old_web_usec = gweb_usec;
220 old_web_requests = gweb_requests;
223 average_response_time = (collected_number) (web_usec / web_requests);
225 if (unlikely(average_response_time != -1))
226 rrddim_set(stduration, "average", average_response_time);
228 rrddim_set(stduration, "average", 0);
230 rrddim_set(stduration, "max", ((gs.web_usec_max)?(collected_number)gs.web_usec_max:average_response_time));
231 rrdset_done(stduration);
233 // ----------------------------------------------------------------
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);
241 rrddim_add(stcompression, "savings", NULL, 1, 1000, RRDDIM_ABSOLUTE);
242 } else rrdset_next(stcompression);
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;
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;
252 old_compressed_content_size = gcompressed_content_size;
253 old_content_size = gcontent_size;
255 if (content_size && content_size >= compressed_content_size)
256 compression_ratio = ((content_size - compressed_content_size) * 100 * 1000) / content_size;
258 if (compression_ratio != -1)
259 rrddim_set(stcompression, "savings", compression_ratio);
261 rrdset_done(stcompression);