darwin-performance-statistics [plain text]
Index: samba/source/include/messages.h
===================================================================
--- samba/source/include/messages.h.orig
+++ samba/source/include/messages.h
@@ -42,6 +42,7 @@
#define MSG_REQ_DMALLOC_LOG_CHANGED 12
#define MSG_SHUTDOWN 13
+#define MSG_USR_STATS 14
/* nmbd messages */
#define MSG_FORCE_ELECTION 1001
Index: samba/source/include/smbprofile.h
===================================================================
--- samba/source/include/smbprofile.h.orig
+++ samba/source/include/smbprofile.h
@@ -863,4 +863,36 @@ static inline SMB_BIG_UINT profile_times
#endif /* WITH_PROFILE */
+/*
+* The following are used to maintain
+* a count of the number of operations (requests) invoked
+* and a countt of bytes transmitted/received
+*/
+#ifdef WITH_DARWIN_STATS
+#define SERV_STAT_SHMEM_KEY ((key_t)0x60022006)
+u_int64_t user_op_count;
+u_int64_t user_byte_count;
+
+typedef struct service_stats {
+ u_int64_t op_count;
+ u_int64_t byte_count;
+}service_stats;
+typedef struct service_header {
+ int count;
+ service_stats service_detail[1];
+} service_header;
+extern service_header *service_h;
+extern service_stats *service_c;
+#define INC_OP_COUNT(s) \
+ if ((int32_t)s >= 0 && s < service_h->count) { \
+ user_op_count++; \
+ service_c[s].op_count++; \
+ }
+#define INC_BYTE_COUNT(s, n) \
+ if ((int32_t)s >= 0 && s < service_h->count && n > 0) { \
+ user_byte_count += n; \
+ service_c[s].byte_count += n; \
+ }
+#endif /*WITH_DARWIN_STATS*/
+
#endif
Index: samba/source/profile/profile.c
===================================================================
--- samba/source/profile/profile.c.orig
+++ samba/source/profile/profile.c
@@ -439,3 +439,73 @@ BOOL profile_setup(BOOL rdonly)
}
#endif /* WITH_PROFILE */
+
+#ifdef WITH_DARWIN_STATS
+# ifndef IPC_PERMS
+#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
+#endif
+struct service_header *service_h;
+struct service_stats *service_c;
+static int service_stat_shm_id;
+static BOOL stat_read_only;
+BOOL service_stats_setup(BOOL rdonly)
+{
+ int size = 0;
+ int count = 0;
+ struct shmid_ds shm_ds;
+ stat_read_only = rdonly;
+ again:
+ count = lp_numservices();
+ size = (sizeof(service_stats) * count) + sizeof(int);
+ /* try to use an existing key */
+ service_stat_shm_id = shmget(SERV_STAT_SHMEM_KEY, 0, 0);
+ /* if that failed then create one. There is a race condition here
+ if we are running from inetd. Bad luck. */
+ if (service_stat_shm_id == -1) {
+ if (stat_read_only)
+ return False;
+ service_stat_shm_id = shmget(SERV_STAT_SHMEM_KEY,
+ size,
+ IPC_CREAT | IPC_EXCL | IPC_PERMS);
+ if (service_stat_shm_id == -1) {
+ DEBUG(0,("Can't create or use IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+ }
+ service_h = (service_header *)shmat(service_stat_shm_id, 0,
+ stat_read_only?SHM_RDONLY:0);
+
+ if ((long)service_h == -1) {
+ DEBUG(0,("Can't attach to IPC area. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+ /* find out who created this memory area */
+ if (shmctl(service_stat_shm_id, IPC_STAT, &shm_ds) != 0) {
+ DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
+ strerror(errno)));
+ return False;
+ }
+ if (shm_ds.shm_perm.cuid != sec_initial_uid() || shm_ds.shm_perm.cgid != sec_initial_gid()) {
+ DEBUG(0,("ERROR: we did not create the shmem (owned by another user)\n"));
+ return False;
+ }
+ if (shm_ds.shm_segsz < size) {
+ DEBUG(0,("WARNING: service_stat struct size is %d (expected %d). Deleting\n",
+ (int)shm_ds.shm_segsz, size));
+ if (shmctl(service_stat_shm_id, IPC_RMID, &shm_ds) == 0)
+ goto again;
+ else
+ return False;
+ }
+ if (!stat_read_only && (shm_ds.shm_nattch == 1)) {
+ memset((char *)service_h, 0, size);
+ service_h->count = count;
+ DEBUG(3,("Initialised service stats area\n"));
+ }
+ service_c = &service_h->service_detail[0];
+ return True;
+}
+
+#endif /*WITH_DARWIN_STATS*/
Index: samba/source/smbd/process.c
===================================================================
--- samba/source/smbd/process.c.orig
+++ samba/source/smbd/process.c
@@ -999,8 +999,16 @@ static int switch_message(int type,char
return(ERROR_DOS(ERRSRV,ERRaccess));
}
+ INC_OP_COUNT(SNUM(conn));
+ INC_BYTE_COUNT(SNUM(conn), size);
+
current_inbuf = inbuf; /* In case we need to defer this message in open... */
outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize);
+
+ /* Handling the message can deallocate conn, eg. SMBtdis. */
+ if (conn && conn->params) {
+ INC_BYTE_COUNT(SNUM(conn), outsize);
+ }
}
smb_dump(smb_fn_name(type), 0, outbuf, outsize);
Index: samba/source/smbd/server.c
===================================================================
--- samba/source/smbd/server.c.orig
+++ samba/source/smbd/server.c
@@ -175,6 +175,34 @@ static void msg_sam_repl(int msg_type, s
low_serial));
}
+
+#ifdef WITH_DARWIN_STATS
+/****************************************************************************
+ Process user stat message.
+****************************************************************************/
+
+static void msg_usr_stat(int msg_type, struct process_id src,
+ void *buf, size_t len, void * UNUSED(context))
+{
+
+ if (len != 0) {
+ DEBUG(10,("Received NON 0 USTAT message from PID %u \n", src));
+ return;
+ } else {
+ pid_t pid = procid_to_pid(&src);
+ u_int64_t data[2] = {user_op_count, user_byte_count};
+
+ DEBUG(1,("USTAT message send to PID %u for size %d\n",
+ (unsigned)pid, sizeof(u_int64_t) * 2));
+
+ become_root();
+ message_send_pid(src, msg_type, &data[0],
+ sizeof(u_int64_t) * 2, False);
+ unbecome_root();
+ }
+}
+#endif /*WITH_DARWIN_STATS*/
+
/****************************************************************************
Open the socket communication - inetd.
****************************************************************************/
@@ -978,6 +1006,13 @@ extern void build_options(BOOL screen);
set_profile_level(pl, src);
}
#endif
+#ifdef WITH_DARWIN_STATS
+ if (!service_stats_setup(False)) {
+ DEBUG(0,("ERROR: failed to setup service stats\n"));
+ return -1;
+ }
+#endif /*WITH_DARWIN_STATS*/
+
DEBUG(3,( "loaded services\n"));
@@ -1017,6 +1052,11 @@ extern void build_options(BOOL screen);
if (!message_init())
exit(1);
+#ifdef WITH_DARWIN_STATS
+ /*Required for both -D and -F options*/
+ message_register(MSG_USR_STATS, msg_usr_stat, NULL);
+#endif
+
/* Initialise the password backed before the global_sam_sid
to ensure that we fetch from ldap before we make a domain sid up */
Index: samba/source/utils/status.c
===================================================================
--- samba/source/utils/status.c.orig
+++ samba/source/utils/status.c
@@ -44,6 +44,7 @@ static int shares_only = 0;
static int locks_only = 0; /* Added by RJS */
static BOOL processes_only=False;
static int show_brl;
+static int show_counts = 0;
static BOOL numeric_only = False;
const char *username = NULL;
@@ -240,8 +241,132 @@ static int traverse_sessionid(TDB_CONTEX
return 0;
}
+#ifdef WITH_DARWIN_STATS
+u_int64_t buffer[3];
+int num_replies;
+static BOOL send_status_message(struct process_id pid)
+{
+ TDB_CONTEXT *tdb;
+ BOOL ret;
+ int n_sent = 0;
+
+ if (!message_init())
+ return False;
+
+ if (procid_to_pid(&pid) != 0) {
+ return NT_STATUS_IS_OK(message_send_pid(pid, MSG_USR_STATS,
+ NULL, 0, False /* duplicates */));
+ }
+
+ tdb = tdb_open_log(lock_path("connections.tdb"), 0,
+ TDB_DEFAULT, O_RDWR, 0);
+ if (!tdb) {
+ fprintf(stderr,"Failed to open connections database"
+ ": %s\n", strerror(errno));
+ return False;
+ }
+
+ ret = message_send_all(tdb, MSG_USR_STATS, NULL, 0,
+ False /* duplicates */, &n_sent);
+ DEBUG(10,("smbcontrol/send_message: broadcast message to "
+ "%d processes\n", n_sent));
+ tdb_close(tdb);
+ return ret;
+}
+static void wait_replies(BOOL multiple_replies)
+{
+ time_t start_time = 0;
+
+ /* Wait around a bit. This is pretty disgusting - we have to
+ busy-wait here as there is no nicer way to do it. */
+
+ do {
+ start_time = time(NULL);
+ message_dispatch();
+ if (num_replies > 0 && !multiple_replies)
+ break;
+ do
+ sleep(1);
+ while ((5 + start_time - time(NULL)) > 0 && num_replies == 0);
+ if (num_replies > 0 && !multiple_replies)
+ break;
+ } while (1);
+}
+
+static void handle_usr_stat_reply(int msg_type, struct process_id pid,
+ void *buf, size_t len, void * UNUSED(context))
+{
+ //DEBUG(10,("handle_usr_stat_reply from %d size %d\n ", pid, len ));
+ d_printf(" %-21qu%-21qu\n", ((u_int64_t*)buf)[0], ((u_int64_t*)buf)[1]);
+ num_replies++;
+}
+
+static void do_collect_usrstat(struct process_id pid)
+{
+ num_replies = 0;
+ if (send_status_message(pid)) {
+ wait_replies(0);
+ }
+}
+
+static int traverse_processes(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct sessionid sessionid;
+ struct process_id pid;
+
+ if (dbuf.dsize != sizeof(sessionid))
+ return 0;
+ memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
+
+ pid = pid_to_procid((pid_t)sessionid.pid);
+ if (!process_exists(pid)) {
+ return 0;
+ }
+ Ucrit_addPid( sessionid.pid );
+ d_printf("%5d %-12s %-12s",
+ (int)sessionid.pid, uidtoname(sessionid.uid), gidtoname(sessionid.gid));
+ do_collect_usrstat(pid);
+ return 0;
+}
+
+static void dump_user_stats(void)
+{
+ TDB_CONTEXT *tdb;
+ int nump = 0;
+ message_register(MSG_USR_STATS, handle_usr_stat_reply, NULL);
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb) {
+ d_printf("\nsessionid.tdb not initialised\n");
+ } else {
+ d_printf("\nPID Username Group OpCount ByteCount \n");
+ d_printf("------------------------------------------------------------------------------\n");
+ nump = tdb_traverse(tdb, traverse_processes, NULL);
+ //DEBUG(10,("Total %d procs traversed\n", nump));
+ tdb_close(tdb);
+ }
+ message_deregister(MSG_USR_STATS);
+}
+
+static void dump_service_stats(void)
+{
+ int is = 0;
+
+ if (service_stats_setup(True) && service_h->count > 0) {
+ d_printf("\n%-15s %-21s%-21s\n", "Share", "OpCount", "ByteCount");
+ d_printf("-------------------------------------------------------------------\n");
+ for (is = 0; is < service_h->count && lp_const_servicename(is); is++)
+ d_printf("%-15s %-21qu %-21qu\n",
+ lp_servicename(is),
+ service_c[is].op_count,
+ service_c[is].byte_count);
+ } else {
+ fprintf(stderr,"\nFailed to initialise service_stats memory\n");
+ }
+}
+#endif /*WITH_DARWIN_STATS*/
+
int main(int argc, char *argv[])
{
@@ -262,6 +387,7 @@ static int traverse_sessionid(TDB_CONTEX
{"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" },
{"byterange", 'B', POPT_ARG_NONE, &show_brl, 'B', "Include byte range locks"},
{"numeric", 'n', POPT_ARG_NONE, &numeric_only, 'n', "Numeric uid/gid"},
+ {"counts", 'C', POPT_ARG_NONE, &show_counts, 'n', "Show all user op/bytes counts"},
POPT_COMMON_SAMBA
POPT_TABLEEND
};
@@ -338,6 +464,14 @@ static int traverse_sessionid(TDB_CONTEX
exit(0);
}
+#if WITH_DARWIN_STATS
+ if ( show_counts) {
+ dump_user_stats();
+ dump_service_stats();
+ exit(0);
+ }
+#endif /*WITH_DARWIN_STATS*/
+
if ( show_shares ) {
tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
if (!tdb) {