source: vendor/current/source3/profile/profile.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 11.7 KB
Line 
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
6
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.
11
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.
16
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/>.
19
20*/
21
22#include "includes.h"
23#include "system/shmem.h"
24#include "system/filesys.h"
25#include "system/time.h"
26#include "messages.h"
27#include "smbprofile.h"
28#include "lib/tdb_wrap/tdb_wrap.h"
29#include <tevent.h>
30#include "../lib/crypto/crypto.h"
31
32#ifdef HAVE_SYS_RESOURCE_H
33#include <sys/resource.h>
34#endif
35
36struct profile_stats *profile_p;
37struct smbprofile_global_state smbprofile_state;
38
39/****************************************************************************
40Set a profiling level.
41****************************************************************************/
42void set_profile_level(int level, struct server_id src)
43{
44 SMB_ASSERT(smbprofile_state.internal.db != NULL);
45
46 switch (level) {
47 case 0: /* turn off profiling */
48 smbprofile_state.config.do_count = false;
49 smbprofile_state.config.do_times = false;
50 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
51 (int)procid_to_pid(&src)));
52 break;
53 case 1: /* turn on counter profiling only */
54 smbprofile_state.config.do_count = true;
55 smbprofile_state.config.do_times = false;
56 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
57 (int)procid_to_pid(&src)));
58 break;
59 case 2: /* turn on complete profiling */
60 smbprofile_state.config.do_count = true;
61 smbprofile_state.config.do_times = true;
62 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
63 (int)procid_to_pid(&src)));
64 break;
65 case 3: /* reset profile values */
66 ZERO_STRUCT(profile_p->values);
67 tdb_wipe_all(smbprofile_state.internal.db->tdb);
68 DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
69 (int)procid_to_pid(&src)));
70 break;
71 }
72}
73
74/****************************************************************************
75receive a set profile level message
76****************************************************************************/
77static void profile_message(struct messaging_context *msg_ctx,
78 void *private_data,
79 uint32_t msg_type,
80 struct server_id src,
81 DATA_BLOB *data)
82{
83 int level;
84
85 if (data->length != sizeof(level)) {
86 DEBUG(0, ("got invalid profile message\n"));
87 return;
88 }
89
90 memcpy(&level, data->data, sizeof(level));
91 set_profile_level(level, src);
92}
93
94/****************************************************************************
95receive a request profile level message
96****************************************************************************/
97static void reqprofile_message(struct messaging_context *msg_ctx,
98 void *private_data,
99 uint32_t msg_type,
100 struct server_id src,
101 DATA_BLOB *data)
102{
103 int level;
104
105 level = 1;
106 if (smbprofile_state.config.do_count) {
107 level += 2;
108 }
109 if (smbprofile_state.config.do_times) {
110 level += 4;
111 }
112
113 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
114 (unsigned int)procid_to_pid(&src)));
115 messaging_send_buf(msg_ctx, src, MSG_PROFILELEVEL,
116 (uint8_t *)&level, sizeof(level));
117}
118
119/*******************************************************************
120 open the profiling shared memory area
121 ******************************************************************/
122bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
123{
124 unsigned char tmp[16] = {};
125 MD5_CTX md5;
126 char *db_name;
127
128 if (smbprofile_state.internal.db != NULL) {
129 return true;
130 }
131
132 db_name = cache_path("smbprofile.tdb");
133 if (db_name == NULL) {
134 return false;
135 }
136
137 smbprofile_state.internal.db = tdb_wrap_open(
138 NULL, db_name, 0,
139 rdonly ? 0 : TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING,
140 O_CREAT | (rdonly ? O_RDONLY : O_RDWR), 0644);
141 if (smbprofile_state.internal.db == NULL) {
142 return false;
143 }
144
145 if (msg_ctx != NULL) {
146 messaging_register(msg_ctx, NULL, MSG_PROFILE,
147 profile_message);
148 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
149 reqprofile_message);
150 }
151
152 MD5Init(&md5);
153
154 MD5Update(&md5,
155 (const uint8_t *)&smbprofile_state.stats.global,
156 sizeof(smbprofile_state.stats.global));
157
158#define __UPDATE(str) do { \
159 MD5Update(&md5, (const uint8_t *)str, strlen(str)); \
160} while(0)
161#define SMBPROFILE_STATS_START
162#define SMBPROFILE_STATS_SECTION_START(name, display) do { \
163 __UPDATE(#name "+" #display); \
164} while(0);
165#define SMBPROFILE_STATS_COUNT(name) do { \
166 __UPDATE(#name "+count"); \
167} while(0);
168#define SMBPROFILE_STATS_TIME(name) do { \
169 __UPDATE(#name "+time"); \
170} while(0);
171#define SMBPROFILE_STATS_BASIC(name) do { \
172 __UPDATE(#name "+count"); \
173 __UPDATE(#name "+time"); \
174} while(0);
175#define SMBPROFILE_STATS_BYTES(name) do { \
176 __UPDATE(#name "+count"); \
177 __UPDATE(#name "+time"); \
178 __UPDATE(#name "+idle"); \
179 __UPDATE(#name "+bytes"); \
180} while(0);
181#define SMBPROFILE_STATS_IOBYTES(name) do { \
182 __UPDATE(#name "+count"); \
183 __UPDATE(#name "+time"); \
184 __UPDATE(#name "+idle"); \
185 __UPDATE(#name "+inbytes"); \
186 __UPDATE(#name "+outbytes"); \
187} while(0);
188#define SMBPROFILE_STATS_SECTION_END
189#define SMBPROFILE_STATS_END
190 SMBPROFILE_STATS_ALL_SECTIONS
191#undef __UPDATE
192#undef SMBPROFILE_STATS_START
193#undef SMBPROFILE_STATS_SECTION_START
194#undef SMBPROFILE_STATS_COUNT
195#undef SMBPROFILE_STATS_TIME
196#undef SMBPROFILE_STATS_BASIC
197#undef SMBPROFILE_STATS_BYTES
198#undef SMBPROFILE_STATS_IOBYTES
199#undef SMBPROFILE_STATS_SECTION_END
200#undef SMBPROFILE_STATS_END
201
202 MD5Final(tmp, &md5);
203
204 profile_p = &smbprofile_state.stats.global;
205
206 profile_p->magic = BVAL(tmp, 0);
207 if (profile_p->magic == 0) {
208 profile_p->magic = BVAL(tmp, 8);
209 }
210
211 return True;
212}
213
214void smbprofile_dump_setup(struct tevent_context *ev)
215{
216 TALLOC_FREE(smbprofile_state.internal.te);
217 smbprofile_state.internal.ev = ev;
218}
219
220static void smbprofile_dump_timer(struct tevent_context *ev,
221 struct tevent_timer *te,
222 struct timeval current_time,
223 void *private_data)
224{
225 smbprofile_dump();
226}
227
228void smbprofile_dump_schedule_timer(void)
229{
230 struct timeval tv;
231
232 GetTimeOfDay(&tv);
233 tv.tv_sec += 1;
234
235 smbprofile_state.internal.te = tevent_add_timer(
236 smbprofile_state.internal.ev,
237 smbprofile_state.internal.ev,
238 tv,
239 smbprofile_dump_timer,
240 NULL);
241}
242
243static int profile_stats_parser(TDB_DATA key, TDB_DATA value,
244 void *private_data)
245{
246 struct profile_stats *s = private_data;
247
248 if (value.dsize != sizeof(struct profile_stats)) {
249 *s = (struct profile_stats) {};
250 return 0;
251 }
252
253 memcpy(s, value.dptr, value.dsize);
254 if (s->magic != profile_p->magic) {
255 *s = (struct profile_stats) {};
256 return 0;
257 }
258
259 return 0;
260}
261
262void smbprofile_dump(void)
263{
264 pid_t pid = getpid();
265 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
266 struct profile_stats s = {};
267 int ret;
268#ifdef HAVE_GETRUSAGE
269 struct rusage rself;
270#endif /* HAVE_GETRUSAGE */
271
272 TALLOC_FREE(smbprofile_state.internal.te);
273
274 if (smbprofile_state.internal.db == NULL) {
275 return;
276 }
277
278#ifdef HAVE_GETRUSAGE
279 ret = getrusage(RUSAGE_SELF, &rself);
280 if (ret != 0) {
281 ZERO_STRUCT(rself);
282 }
283
284 profile_p->values.cpu_user_stats.time =
285 (rself.ru_utime.tv_sec * 1000000) +
286 rself.ru_utime.tv_usec;
287 profile_p->values.cpu_system_stats.time =
288 (rself.ru_stime.tv_sec * 1000000) +
289 rself.ru_stime.tv_usec;
290#endif /* HAVE_GETRUSAGE */
291
292 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
293 if (ret != 0) {
294 return;
295 }
296
297 tdb_parse_record(smbprofile_state.internal.db->tdb,
298 key, profile_stats_parser, &s);
299
300 smbprofile_stats_accumulate(profile_p, &s);
301
302 tdb_store(smbprofile_state.internal.db->tdb, key,
303 (TDB_DATA) {
304 .dptr = (uint8_t *)profile_p,
305 .dsize = sizeof(*profile_p)
306 },
307 0);
308
309 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
310 ZERO_STRUCT(profile_p->values);
311
312 return;
313}
314
315void smbprofile_cleanup(pid_t pid, pid_t dst)
316{
317 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
318 struct profile_stats s = {};
319 struct profile_stats acc = {};
320 int ret;
321
322 if (smbprofile_state.internal.db == NULL) {
323 return;
324 }
325
326 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
327 if (ret != 0) {
328 return;
329 }
330 ret = tdb_parse_record(smbprofile_state.internal.db->tdb,
331 key, profile_stats_parser, &s);
332 if (ret == -1) {
333 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
334 return;
335 }
336 tdb_delete(smbprofile_state.internal.db->tdb, key);
337 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
338
339 pid = dst;
340 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
341 if (ret != 0) {
342 return;
343 }
344 tdb_parse_record(smbprofile_state.internal.db->tdb,
345 key, profile_stats_parser, &acc);
346
347 /*
348 * We may have to fix the disconnect count
349 * in case the process died
350 */
351 s.values.disconnect_stats.count = s.values.connect_stats.count;
352
353 smbprofile_stats_accumulate(&acc, &s);
354
355 acc.magic = profile_p->magic;
356 tdb_store(smbprofile_state.internal.db->tdb, key,
357 (TDB_DATA) {
358 .dptr = (uint8_t *)&acc,
359 .dsize = sizeof(acc)
360 },
361 0);
362
363 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
364}
365
366void smbprofile_stats_accumulate(struct profile_stats *acc,
367 const struct profile_stats *add)
368{
369#define SMBPROFILE_STATS_START
370#define SMBPROFILE_STATS_SECTION_START(name, display)
371#define SMBPROFILE_STATS_COUNT(name) do { \
372 acc->values.name##_stats.count += add->values.name##_stats.count; \
373} while(0);
374#define SMBPROFILE_STATS_TIME(name) do { \
375 acc->values.name##_stats.time += add->values.name##_stats.time; \
376} while(0);
377#define SMBPROFILE_STATS_BASIC(name) do { \
378 acc->values.name##_stats.count += add->values.name##_stats.count; \
379 acc->values.name##_stats.time += add->values.name##_stats.time; \
380} while(0);
381#define SMBPROFILE_STATS_BYTES(name) do { \
382 acc->values.name##_stats.count += add->values.name##_stats.count; \
383 acc->values.name##_stats.time += add->values.name##_stats.time; \
384 acc->values.name##_stats.idle += add->values.name##_stats.idle; \
385 acc->values.name##_stats.bytes += add->values.name##_stats.bytes; \
386} while(0);
387#define SMBPROFILE_STATS_IOBYTES(name) do { \
388 acc->values.name##_stats.count += add->values.name##_stats.count; \
389 acc->values.name##_stats.time += add->values.name##_stats.time; \
390 acc->values.name##_stats.idle += add->values.name##_stats.idle; \
391 acc->values.name##_stats.inbytes += add->values.name##_stats.inbytes; \
392 acc->values.name##_stats.outbytes += add->values.name##_stats.outbytes; \
393} while(0);
394#define SMBPROFILE_STATS_SECTION_END
395#define SMBPROFILE_STATS_END
396 SMBPROFILE_STATS_ALL_SECTIONS
397#undef SMBPROFILE_STATS_START
398#undef SMBPROFILE_STATS_SECTION_START
399#undef SMBPROFILE_STATS_COUNT
400#undef SMBPROFILE_STATS_TIME
401#undef SMBPROFILE_STATS_BASIC
402#undef SMBPROFILE_STATS_BYTES
403#undef SMBPROFILE_STATS_IOBYTES
404#undef SMBPROFILE_STATS_SECTION_END
405#undef SMBPROFILE_STATS_END
406}
407
408static int smbprofile_collect_fn(struct tdb_context *tdb,
409 TDB_DATA key, TDB_DATA value,
410 void *private_data)
411{
412 struct profile_stats *acc = (struct profile_stats *)private_data;
413 const struct profile_stats *v;
414
415 if (value.dsize != sizeof(struct profile_stats)) {
416 return 0;
417 }
418
419 v = (const struct profile_stats *)value.dptr;
420
421 if (v->magic != profile_p->magic) {
422 return 0;
423 }
424
425 smbprofile_stats_accumulate(acc, v);
426 return 0;
427}
428
429void smbprofile_collect(struct profile_stats *stats)
430{
431 *stats = (struct profile_stats) {};
432
433 if (smbprofile_state.internal.db == NULL) {
434 return;
435 }
436
437 tdb_traverse_read(smbprofile_state.internal.db->tdb,
438 smbprofile_collect_fn, stats);
439}
Note: See TracBrowser for help on using the repository browser.