ldb: change the version to 2.8.0 for Samba 4.19
[Samba.git] / source3 / profile / profile.c
blobefb603d85cbd0b5ec3fc2e2039ac174ba55ee63b
1 /*
2 Unix SMB/CIFS implementation.
3 store smbd profiling information in shared memory
4 Copyright (C) Andrew Tridgell 1999
5 Copyright (C) James Peach 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "system/time.h"
25 #include "messages.h"
26 #include "smbprofile.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
28 #include <tevent.h>
29 #include "../lib/crypto/crypto.h"
31 #ifdef HAVE_SYS_RESOURCE_H
32 #include <sys/resource.h>
33 #endif
35 #include <gnutls/gnutls.h>
36 #include <gnutls/crypto.h>
37 #include "lib/crypto/gnutls_helpers.h"
39 struct profile_stats *profile_p;
40 struct smbprofile_global_state smbprofile_state;
42 /****************************************************************************
43 Set a profiling level.
44 ****************************************************************************/
45 void set_profile_level(int level, const struct server_id *src)
47 SMB_ASSERT(smbprofile_state.internal.db != NULL);
49 switch (level) {
50 case 0: /* turn off profiling */
51 smbprofile_state.config.do_count = false;
52 smbprofile_state.config.do_times = false;
53 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
54 (int)procid_to_pid(src)));
55 break;
56 case 1: /* turn on counter profiling only */
57 smbprofile_state.config.do_count = true;
58 smbprofile_state.config.do_times = false;
59 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
60 (int)procid_to_pid(src)));
61 break;
62 case 2: /* turn on complete profiling */
63 smbprofile_state.config.do_count = true;
64 smbprofile_state.config.do_times = true;
65 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
66 (int)procid_to_pid(src)));
67 break;
68 case 3: /* reset profile values */
69 ZERO_STRUCT(profile_p->values);
70 tdb_wipe_all(smbprofile_state.internal.db->tdb);
71 DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
72 (int)procid_to_pid(src)));
73 break;
77 /****************************************************************************
78 receive a set profile level message
79 ****************************************************************************/
80 static void profile_message(struct messaging_context *msg_ctx,
81 void *private_data,
82 uint32_t msg_type,
83 struct server_id src,
84 DATA_BLOB *data)
86 int level;
88 if (data->length != sizeof(level)) {
89 DEBUG(0, ("got invalid profile message\n"));
90 return;
93 memcpy(&level, data->data, sizeof(level));
94 set_profile_level(level, &src);
97 /****************************************************************************
98 receive a request profile level message
99 ****************************************************************************/
100 static void reqprofile_message(struct messaging_context *msg_ctx,
101 void *private_data,
102 uint32_t msg_type,
103 struct server_id src,
104 DATA_BLOB *data)
106 int level;
108 level = 1;
109 if (smbprofile_state.config.do_count) {
110 level += 2;
112 if (smbprofile_state.config.do_times) {
113 level += 4;
116 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
117 (unsigned int)procid_to_pid(&src)));
118 messaging_send_buf(msg_ctx, src, MSG_PROFILELEVEL,
119 (uint8_t *)&level, sizeof(level));
122 /*******************************************************************
123 open the profiling shared memory area
124 ******************************************************************/
125 bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
127 uint8_t digest[gnutls_hash_get_len(GNUTLS_DIG_SHA1)];
128 gnutls_hash_hd_t hash_hnd = NULL;
129 char *db_name;
130 bool ok = false;
131 int rc;
133 if (smbprofile_state.internal.db != NULL) {
134 return true;
137 db_name = cache_path(talloc_tos(), "smbprofile.tdb");
138 if (db_name == NULL) {
139 return false;
142 smbprofile_state.internal.db = tdb_wrap_open(
143 NULL, db_name, 0,
144 rdonly ? 0 : TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING,
145 O_CREAT | (rdonly ? O_RDONLY : O_RDWR), 0644);
146 if (smbprofile_state.internal.db == NULL) {
147 return false;
150 if (msg_ctx != NULL) {
151 messaging_register(msg_ctx, NULL, MSG_PROFILE,
152 profile_message);
153 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
154 reqprofile_message);
157 GNUTLS_FIPS140_SET_LAX_MODE();
159 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA1);
160 if (rc < 0) {
161 goto out;
163 rc = gnutls_hash(hash_hnd,
164 &smbprofile_state.stats.global,
165 sizeof(smbprofile_state.stats.global));
167 #define __UPDATE(str) do { \
168 rc |= gnutls_hash(hash_hnd, str, strlen(str)); \
169 } while(0)
170 #define SMBPROFILE_STATS_START
171 #define SMBPROFILE_STATS_SECTION_START(name, display) do { \
172 __UPDATE(#name "+" #display); \
173 } while(0);
174 #define SMBPROFILE_STATS_COUNT(name) do { \
175 __UPDATE(#name "+count"); \
176 } while(0);
177 #define SMBPROFILE_STATS_TIME(name) do { \
178 __UPDATE(#name "+time"); \
179 } while(0);
180 #define SMBPROFILE_STATS_BASIC(name) do { \
181 __UPDATE(#name "+count"); \
182 __UPDATE(#name "+time"); \
183 } while(0);
184 #define SMBPROFILE_STATS_BYTES(name) do { \
185 __UPDATE(#name "+count"); \
186 __UPDATE(#name "+time"); \
187 __UPDATE(#name "+idle"); \
188 __UPDATE(#name "+bytes"); \
189 } while(0);
190 #define SMBPROFILE_STATS_IOBYTES(name) do { \
191 __UPDATE(#name "+count"); \
192 __UPDATE(#name "+time"); \
193 __UPDATE(#name "+idle"); \
194 __UPDATE(#name "+inbytes"); \
195 __UPDATE(#name "+outbytes"); \
196 } while(0);
197 #define SMBPROFILE_STATS_SECTION_END
198 #define SMBPROFILE_STATS_END
199 SMBPROFILE_STATS_ALL_SECTIONS
200 #undef __UPDATE
201 #undef SMBPROFILE_STATS_START
202 #undef SMBPROFILE_STATS_SECTION_START
203 #undef SMBPROFILE_STATS_COUNT
204 #undef SMBPROFILE_STATS_TIME
205 #undef SMBPROFILE_STATS_BASIC
206 #undef SMBPROFILE_STATS_BYTES
207 #undef SMBPROFILE_STATS_IOBYTES
208 #undef SMBPROFILE_STATS_SECTION_END
209 #undef SMBPROFILE_STATS_END
210 if (rc != 0) {
211 gnutls_hash_deinit(hash_hnd, NULL);
212 goto out;
215 gnutls_hash_deinit(hash_hnd, digest);
217 GNUTLS_FIPS140_SET_STRICT_MODE();
219 profile_p = &smbprofile_state.stats.global;
221 profile_p->magic = BVAL(digest, 0);
222 if (profile_p->magic == 0) {
223 profile_p->magic = BVAL(digest, 8);
226 ok = true;
227 out:
228 GNUTLS_FIPS140_SET_STRICT_MODE();
230 return ok;
233 void smbprofile_dump_setup(struct tevent_context *ev)
235 TALLOC_FREE(smbprofile_state.internal.te);
236 smbprofile_state.internal.ev = ev;
239 static void smbprofile_dump_timer(struct tevent_context *ev,
240 struct tevent_timer *te,
241 struct timeval current_time,
242 void *private_data)
244 smbprofile_dump();
247 void smbprofile_dump_schedule_timer(void)
249 struct timeval tv;
251 GetTimeOfDay(&tv);
252 tv.tv_sec += 1;
254 smbprofile_state.internal.te = tevent_add_timer(
255 smbprofile_state.internal.ev,
256 smbprofile_state.internal.ev,
258 smbprofile_dump_timer,
259 NULL);
262 static int profile_stats_parser(TDB_DATA key, TDB_DATA value,
263 void *private_data)
265 struct profile_stats *s = private_data;
267 if (value.dsize != sizeof(struct profile_stats)) {
268 *s = (struct profile_stats) {};
269 return 0;
272 memcpy(s, value.dptr, value.dsize);
273 if (s->magic != profile_p->magic) {
274 *s = (struct profile_stats) {};
275 return 0;
278 return 0;
281 void smbprofile_dump(void)
283 pid_t pid = 0;
284 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
285 struct profile_stats s = {};
286 int ret;
287 #ifdef HAVE_GETRUSAGE
288 struct rusage rself;
289 #endif /* HAVE_GETRUSAGE */
291 TALLOC_FREE(smbprofile_state.internal.te);
293 if (! (smbprofile_state.config.do_count ||
294 smbprofile_state.config.do_times)) {
295 return;
298 if (smbprofile_state.internal.db == NULL) {
299 return;
302 pid = tevent_cached_getpid();
304 #ifdef HAVE_GETRUSAGE
305 ret = getrusage(RUSAGE_SELF, &rself);
306 if (ret != 0) {
307 ZERO_STRUCT(rself);
310 profile_p->values.cpu_user_stats.time =
311 (rself.ru_utime.tv_sec * 1000000) +
312 rself.ru_utime.tv_usec;
313 profile_p->values.cpu_system_stats.time =
314 (rself.ru_stime.tv_sec * 1000000) +
315 rself.ru_stime.tv_usec;
316 #endif /* HAVE_GETRUSAGE */
318 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
319 if (ret != 0) {
320 return;
323 tdb_parse_record(smbprofile_state.internal.db->tdb,
324 key, profile_stats_parser, &s);
326 smbprofile_stats_accumulate(profile_p, &s);
328 tdb_store(smbprofile_state.internal.db->tdb, key,
329 (TDB_DATA) {
330 .dptr = (uint8_t *)profile_p,
331 .dsize = sizeof(*profile_p)
335 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
336 ZERO_STRUCT(profile_p->values);
338 return;
341 void smbprofile_cleanup(pid_t pid, pid_t dst)
343 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
344 struct profile_stats s = {};
345 struct profile_stats acc = {};
346 int ret;
348 if (smbprofile_state.internal.db == NULL) {
349 return;
352 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
353 if (ret != 0) {
354 return;
356 ret = tdb_parse_record(smbprofile_state.internal.db->tdb,
357 key, profile_stats_parser, &s);
358 if (ret == -1) {
359 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
360 return;
362 tdb_delete(smbprofile_state.internal.db->tdb, key);
363 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
365 pid = dst;
366 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
367 if (ret != 0) {
368 return;
370 tdb_parse_record(smbprofile_state.internal.db->tdb,
371 key, profile_stats_parser, &acc);
374 * We may have to fix the disconnect count
375 * in case the process died
377 s.values.disconnect_stats.count = s.values.connect_stats.count;
379 smbprofile_stats_accumulate(&acc, &s);
381 acc.magic = profile_p->magic;
382 tdb_store(smbprofile_state.internal.db->tdb, key,
383 (TDB_DATA) {
384 .dptr = (uint8_t *)&acc,
385 .dsize = sizeof(acc)
389 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
392 void smbprofile_stats_accumulate(struct profile_stats *acc,
393 const struct profile_stats *add)
395 #define SMBPROFILE_STATS_START
396 #define SMBPROFILE_STATS_SECTION_START(name, display)
397 #define SMBPROFILE_STATS_COUNT(name) do { \
398 acc->values.name##_stats.count += add->values.name##_stats.count; \
399 } while(0);
400 #define SMBPROFILE_STATS_TIME(name) do { \
401 acc->values.name##_stats.time += add->values.name##_stats.time; \
402 } while(0);
403 #define SMBPROFILE_STATS_BASIC(name) do { \
404 acc->values.name##_stats.count += add->values.name##_stats.count; \
405 acc->values.name##_stats.time += add->values.name##_stats.time; \
406 } while(0);
407 #define SMBPROFILE_STATS_BYTES(name) do { \
408 acc->values.name##_stats.count += add->values.name##_stats.count; \
409 acc->values.name##_stats.time += add->values.name##_stats.time; \
410 acc->values.name##_stats.idle += add->values.name##_stats.idle; \
411 acc->values.name##_stats.bytes += add->values.name##_stats.bytes; \
412 } while(0);
413 #define SMBPROFILE_STATS_IOBYTES(name) do { \
414 acc->values.name##_stats.count += add->values.name##_stats.count; \
415 acc->values.name##_stats.time += add->values.name##_stats.time; \
416 acc->values.name##_stats.idle += add->values.name##_stats.idle; \
417 acc->values.name##_stats.inbytes += add->values.name##_stats.inbytes; \
418 acc->values.name##_stats.outbytes += add->values.name##_stats.outbytes; \
419 } while(0);
420 #define SMBPROFILE_STATS_SECTION_END
421 #define SMBPROFILE_STATS_END
422 SMBPROFILE_STATS_ALL_SECTIONS
423 #undef SMBPROFILE_STATS_START
424 #undef SMBPROFILE_STATS_SECTION_START
425 #undef SMBPROFILE_STATS_COUNT
426 #undef SMBPROFILE_STATS_TIME
427 #undef SMBPROFILE_STATS_BASIC
428 #undef SMBPROFILE_STATS_BYTES
429 #undef SMBPROFILE_STATS_IOBYTES
430 #undef SMBPROFILE_STATS_SECTION_END
431 #undef SMBPROFILE_STATS_END
434 static int smbprofile_collect_fn(struct tdb_context *tdb,
435 TDB_DATA key, TDB_DATA value,
436 void *private_data)
438 struct profile_stats *acc = (struct profile_stats *)private_data;
439 const struct profile_stats *v;
441 if (value.dsize != sizeof(struct profile_stats)) {
442 return 0;
445 v = (const struct profile_stats *)value.dptr;
447 if (v->magic != profile_p->magic) {
448 return 0;
451 smbprofile_stats_accumulate(acc, v);
452 return 0;
455 void smbprofile_collect(struct profile_stats *stats)
457 *stats = (struct profile_stats) {};
459 if (smbprofile_state.internal.db == NULL) {
460 return;
463 tdb_traverse_read(smbprofile_state.internal.db->tdb,
464 smbprofile_collect_fn, stats);