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/>.
23 #include "system/filesys.h"
24 #include "system/time.h"
26 #include "smbprofile.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
29 #include "../lib/crypto/crypto.h"
31 #ifdef HAVE_SYS_RESOURCE_H
32 #include <sys/resource.h>
35 struct profile_stats
*profile_p
;
36 struct smbprofile_global_state smbprofile_state
;
38 /****************************************************************************
39 Set a profiling level.
40 ****************************************************************************/
41 void set_profile_level(int level
, const struct server_id
*src
)
43 SMB_ASSERT(smbprofile_state
.internal
.db
!= NULL
);
46 case 0: /* turn off profiling */
47 smbprofile_state
.config
.do_count
= false;
48 smbprofile_state
.config
.do_times
= false;
49 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
50 (int)procid_to_pid(src
)));
52 case 1: /* turn on counter profiling only */
53 smbprofile_state
.config
.do_count
= true;
54 smbprofile_state
.config
.do_times
= false;
55 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
56 (int)procid_to_pid(src
)));
58 case 2: /* turn on complete profiling */
59 smbprofile_state
.config
.do_count
= true;
60 smbprofile_state
.config
.do_times
= true;
61 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
62 (int)procid_to_pid(src
)));
64 case 3: /* reset profile values */
65 ZERO_STRUCT(profile_p
->values
);
66 tdb_wipe_all(smbprofile_state
.internal
.db
->tdb
);
67 DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
68 (int)procid_to_pid(src
)));
73 /****************************************************************************
74 receive a set profile level message
75 ****************************************************************************/
76 static void profile_message(struct messaging_context
*msg_ctx
,
84 if (data
->length
!= sizeof(level
)) {
85 DEBUG(0, ("got invalid profile message\n"));
89 memcpy(&level
, data
->data
, sizeof(level
));
90 set_profile_level(level
, &src
);
93 /****************************************************************************
94 receive a request profile level message
95 ****************************************************************************/
96 static void reqprofile_message(struct messaging_context
*msg_ctx
,
105 if (smbprofile_state
.config
.do_count
) {
108 if (smbprofile_state
.config
.do_times
) {
112 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
113 (unsigned int)procid_to_pid(&src
)));
114 messaging_send_buf(msg_ctx
, src
, MSG_PROFILELEVEL
,
115 (uint8_t *)&level
, sizeof(level
));
118 /*******************************************************************
119 open the profiling shared memory area
120 ******************************************************************/
121 bool profile_setup(struct messaging_context
*msg_ctx
, bool rdonly
)
127 if (smbprofile_state
.internal
.db
!= NULL
) {
131 db_name
= cache_path(talloc_tos(), "smbprofile.tdb");
132 if (db_name
== NULL
) {
136 smbprofile_state
.internal
.db
= tdb_wrap_open(
138 rdonly
? 0 : TDB_CLEAR_IF_FIRST
|TDB_MUTEX_LOCKING
,
139 O_CREAT
| (rdonly
? O_RDONLY
: O_RDWR
), 0644);
140 TALLOC_FREE(db_name
);
141 if (smbprofile_state
.internal
.db
== NULL
) {
145 if (msg_ctx
!= NULL
) {
146 messaging_register(msg_ctx
, NULL
, MSG_PROFILE
,
148 messaging_register(msg_ctx
, NULL
, MSG_REQ_PROFILELEVEL
,
152 profile_p
= &smbprofile_state
.stats
.global
;
154 rc
= smbprofile_magic(profile_p
, &profile_p
->magic
);
165 void smbprofile_dump_setup(struct tevent_context
*ev
)
167 TALLOC_FREE(smbprofile_state
.internal
.te
);
168 smbprofile_state
.internal
.ev
= ev
;
171 static void smbprofile_dump_timer(struct tevent_context
*ev
,
172 struct tevent_timer
*te
,
173 struct timeval current_time
,
179 void smbprofile_dump_schedule_timer(void)
186 smbprofile_state
.internal
.te
= tevent_add_timer(
187 smbprofile_state
.internal
.ev
,
188 smbprofile_state
.internal
.ev
,
190 smbprofile_dump_timer
,
194 static int profile_stats_parser(TDB_DATA key
, TDB_DATA value
,
197 struct profile_stats
*s
= private_data
;
199 if (value
.dsize
!= sizeof(struct profile_stats
)) {
200 *s
= (struct profile_stats
) {};
204 memcpy(s
, value
.dptr
, value
.dsize
);
205 if (s
->magic
!= profile_p
->magic
) {
206 *s
= (struct profile_stats
) {};
213 void smbprofile_dump(void)
216 TDB_DATA key
= { .dptr
= (uint8_t *)&pid
, .dsize
= sizeof(pid
) };
217 struct profile_stats s
= {};
219 #ifdef HAVE_GETRUSAGE
221 #endif /* HAVE_GETRUSAGE */
223 TALLOC_FREE(smbprofile_state
.internal
.te
);
225 if (! (smbprofile_state
.config
.do_count
||
226 smbprofile_state
.config
.do_times
)) {
230 if (smbprofile_state
.internal
.db
== NULL
) {
234 pid
= tevent_cached_getpid();
236 ret
= tdb_chainlock(smbprofile_state
.internal
.db
->tdb
, key
);
241 tdb_parse_record(smbprofile_state
.internal
.db
->tdb
,
242 key
, profile_stats_parser
, &s
);
244 smbprofile_stats_accumulate(profile_p
, &s
);
246 #ifdef HAVE_GETRUSAGE
247 ret
= getrusage(RUSAGE_SELF
, &rself
);
252 profile_p
->values
.cpu_user_stats
.time
=
253 (rself
.ru_utime
.tv_sec
* 1000000) +
254 rself
.ru_utime
.tv_usec
;
255 profile_p
->values
.cpu_system_stats
.time
=
256 (rself
.ru_stime
.tv_sec
* 1000000) +
257 rself
.ru_stime
.tv_usec
;
258 #endif /* HAVE_GETRUSAGE */
260 tdb_store(smbprofile_state
.internal
.db
->tdb
, key
,
262 .dptr
= (uint8_t *)profile_p
,
263 .dsize
= sizeof(*profile_p
)
267 tdb_chainunlock(smbprofile_state
.internal
.db
->tdb
, key
);
268 ZERO_STRUCT(profile_p
->values
);
273 void smbprofile_cleanup(pid_t pid
, pid_t dst
)
275 TDB_DATA key
= { .dptr
= (uint8_t *)&pid
, .dsize
= sizeof(pid
) };
276 struct profile_stats s
= {};
277 struct profile_stats acc
= {};
280 if (smbprofile_state
.internal
.db
== NULL
) {
284 ret
= tdb_chainlock(smbprofile_state
.internal
.db
->tdb
, key
);
288 ret
= tdb_parse_record(smbprofile_state
.internal
.db
->tdb
,
289 key
, profile_stats_parser
, &s
);
291 tdb_chainunlock(smbprofile_state
.internal
.db
->tdb
, key
);
294 tdb_delete(smbprofile_state
.internal
.db
->tdb
, key
);
295 tdb_chainunlock(smbprofile_state
.internal
.db
->tdb
, key
);
298 ret
= tdb_chainlock(smbprofile_state
.internal
.db
->tdb
, key
);
302 tdb_parse_record(smbprofile_state
.internal
.db
->tdb
,
303 key
, profile_stats_parser
, &acc
);
306 * We may have to fix the disconnect count
307 * in case the process died
309 s
.values
.disconnect_stats
.count
= s
.values
.connect_stats
.count
;
311 smbprofile_stats_accumulate(&acc
, &s
);
313 acc
.magic
= profile_p
->magic
;
314 tdb_store(smbprofile_state
.internal
.db
->tdb
, key
,
316 .dptr
= (uint8_t *)&acc
,
321 tdb_chainunlock(smbprofile_state
.internal
.db
->tdb
, key
);
324 void smbprofile_collect(struct profile_stats
*stats
)
326 if (smbprofile_state
.internal
.db
== NULL
) {
329 smbprofile_collect_tdb(smbprofile_state
.internal
.db
->tdb
,