s3: Test module for perfcount system
authortodd stecher <todd.stecher@gmail.com>
Thu, 12 Feb 2009 06:28:20 +0000 (22:28 -0800)
committerTim Prouty <tprouty@samba.org>
Fri, 13 Feb 2009 20:59:30 +0000 (12:59 -0800)
Add 'perfcount module = pc_test' to exercise this module. Results are
logged into smb.log every 50 operations (configurable via smb.conf).

source3/Makefile.in
source3/configure.in
source3/modules/perfcount_test.c [new file with mode: 0644]

index 144c81a46795ec2a8d69dbd05de1f26728c57f0b..9bac7191fa65875d73d6d1d3e5c0a45e1ba6427c 100644 (file)
@@ -668,6 +668,7 @@ VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \
                modules/onefs_open.o modules/onefs_streams.o modules/onefs_dir.c \
                modules/onefs_cbrl.o
 PERFCOUNT_ONEFS_OBJ = modules/perfcount_onefs.o
+PERFCOUNT_TEST_OBJ = modules/perfcount_test.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -2562,6 +2563,10 @@ bin/pc_onefs.@SHLIBEXT@: $(BINARY_PREREQS) $(PERFCOUNT_ONEFS_OBJ)
        @echo "Building plugin $@"
        @$(SHLD_MODULE) $(PERFCOUNT_ONEFS_OBJ)
 
+bin/pc_test.@SHLIBEXT@: $(BINARY_PREREQS) $(PERFCOUNT_TEST_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD_MODULE) $(PERFCOUNT_TEST_OBJ)
+
 bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) libgpo/gpext/registry.o
index 4ff4c7ba01a8cfa4dccad6d87e173ceefe1ca224..97f35113e1c60717b73c8dc741458ba43b88c66e 100644 (file)
@@ -421,7 +421,7 @@ default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_
 
 if test "x$developer" = xyes; then
    default_static_modules="$default_static_modules rpc_rpcecho"
-   default_shared_modules="$default_shared_modules charset_weird"
+   default_shared_modules="$default_shared_modules charset_weird perfcount_test"
 fi
 
 #
@@ -6137,6 +6137,7 @@ SMB_MODULE(vfs_onefs, \$(VFS_ONEFS), "bin/onefs.$SHLIBEXT", VFS)
 SMB_SUBSYSTEM(VFS,smbd/vfs.o)
 
 SMB_MODULE(perfcount_onefs, \$(PERFCOUNT_ONEFS), "bin/pc_onefs.$SHLIBEXT", PERFCOUNT)
+SMB_MODULE(perfcount_test, \$(PERFCOUNT_TEST), "bin/pc_test.$SHLIBEXT", PERFCOUNT)
 SMB_SUBSYSTEM(PERFCOUNT,smbd/perfcount.o)
 
 SMB_MODULE(gpext_registry, libgpo/gpext/registry.o, "bin/registry.$SHLIBEXT", GPEXT)
diff --git a/source3/modules/perfcount_test.c b/source3/modules/perfcount_test.c
new file mode 100644 (file)
index 0000000..e0954bf
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Test module for perfcounters
+ *
+ * Copyright (C) Todd Stecher 2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#define PARM_PC_TEST_TYPE              "pc_test"
+#define PARM_DUMPON_COUNT              "count"
+#define PARM_DUMPON_COUNT_DEFAULT      50
+
+struct perfcount_test_identity {
+       uid_t uid;
+       char *user;
+       char *domain;
+};
+
+struct perfcount_test_counter {
+       int op;
+       int sub_op;
+       int ioctl;
+       uint64_t bytes_in;
+       uint64_t bytes_out;
+       int count;
+
+       struct perfcount_test_counter *next;
+       struct perfcount_test_counter *prev;
+};
+
+struct perfcount_test_context {
+
+       /* wip:  identity */
+       struct perfcount_test_identity *id;
+       struct perfcount_test_counter *ops;
+};
+
+#define MAX_OP 256
+struct perfcount_test_counter *g_list[MAX_OP];
+
+int count;
+
+/* determine frequency of dumping results */
+int count_mod = 1;
+
+static void perfcount_test_add_counters(struct perfcount_test_context *ctxt)
+{
+       struct perfcount_test_counter *head;
+       struct perfcount_test_counter *ptc;
+       struct perfcount_test_counter *tmp;
+       bool found;
+
+       for (ptc = ctxt->ops; ptc != NULL; ) {
+
+               found = false;
+
+               if (ptc->op > MAX_OP)
+                       continue;
+
+               for (head = g_list[ptc->op]; head != NULL; head = head->next) {
+                       if ((ptc->sub_op == head->sub_op) &&
+                           (ptc->ioctl == head->ioctl)) {
+                               head->bytes_in += ptc->bytes_in;
+                               head->bytes_out += ptc->bytes_out;
+                               head->count++;
+                               tmp = ptc->next;
+                               DLIST_REMOVE(ctxt->ops, ptc);
+                               SAFE_FREE(ptc);
+                               ptc = tmp;
+                               found = true;
+                               break;
+                       }
+               }
+
+               /* not in global tracking list - add it */
+               if (!found) {
+                       tmp = ptc->next;
+                       DLIST_REMOVE(ctxt->ops, ptc);
+                       ptc->count = 1;
+                       DLIST_ADD(g_list[ptc->op], ptc);
+                       ptc = tmp;
+               }
+       }
+
+}
+
+#if 0
+
+static void perfcount_test_dump_id(struct perfcount_test_identity *id, int lvl)
+{
+       if (!id)
+               return;
+
+       DEBUG(lvl,("uid - %d\n", id->uid));
+       DEBUG(lvl,("user - %s\n", id->user));
+       DEBUG(lvl,("domain - %s\n", id->domain));
+}
+
+#endif
+
+static const char *trans_subop_table[] = {
+       "unknown", "trans:create", "trans:ioctl", "trans:set sd",
+       "trans:change notify", "trans: rename", "trans:get sd",
+       "trans:get quota", "trans:set quota"
+};
+
+static const char *trans2_subop_table[] = {
+       "trans2:open", "trans2:find first", "trans2:find next",
+       "trans2:q fsinfo", "trans2:set fsinfo", "trans2:q path info",
+       "trans2:set pathinfo", "trans2:fs ctl", "trans2: io ctl",
+       "trans2:find notify first", "trans2:find notify next",
+       "trans2:mkdir", "trans2:sess setup", "trans2:get dfs referral",
+       "trans2:report dfs inconsistent"
+};
+
+static const char *smb_subop_name(int op, int subop)
+{
+       /* trans */
+       if (op == 0x25) {
+               if (subop > sizeof(trans_subop_table) /
+                   sizeof(trans_subop_table[0])) {
+                       return "unknown";
+               }
+               return trans_subop_table[subop];
+       } else if (op == 0x32) {
+               if (subop > sizeof(trans2_subop_table) /
+                   sizeof(trans2_subop_table[0])) {
+                       return "unknown";
+               }
+               return trans2_subop_table[subop];
+       }
+
+       return "unknown";
+}
+
+static void perfcount_test_dump_counter(struct perfcount_test_counter *ptc,
+                                       int lvl)
+{
+       DEBUG(lvl, ("OP: %s\n", smb_fn_name(ptc->op)));
+       if (ptc->sub_op > 0) {
+               DEBUG(lvl, ("SUBOP: %s\n",
+                       smb_subop_name(ptc->op, ptc->sub_op)));
+       }
+
+       if (ptc->ioctl > 0) {
+               DEBUG(lvl, ("IOCTL: %d\n", ptc->ioctl));
+       }
+
+       DEBUG(lvl, ("Count: %d\n\n", ptc->count));
+}
+
+static void perfcount_test_dump_counters(void)
+{
+       int i;
+       struct perfcount_test_counter *head;
+
+       count_mod = lp_parm_int(0, PARM_PC_TEST_TYPE, PARM_DUMPON_COUNT,
+           PARM_DUMPON_COUNT_DEFAULT);
+
+       if ((count++ % count_mod) != 0)
+               return;
+
+       DEBUG(0,("#####  Dumping Performance Counters #####\n"));
+
+       for (i=0; i < 256; i++) {
+              for (head = g_list[i]; head != NULL; head = head->next) {
+                      perfcount_test_dump_counter(head, 0);
+                      head->prev = NULL;
+                      SAFE_FREE(head->prev);
+              }
+              SAFE_FREE(head);
+       }
+}
+
+/*  operations */
+static void perfcount_test_start(struct smb_perfcount_data *pcd)
+{
+       struct perfcount_test_context *ctxt;
+       struct perfcount_test_counter *ctr;
+       /*
+        * there shouldn't already be a context here - if so,
+        * there's an unbalanced call to start / end.
+        */
+       if (pcd->context) {
+               DEBUG(0,("perfcount_test_start - starting "
+                        "initialized context - %p\n", pcd));
+               return;
+       }
+
+       ctxt = SMB_MALLOC_P(struct perfcount_test_context);
+       if (!ctxt)
+               return;
+
+       ZERO_STRUCTP(ctxt);
+
+       /* create 'default' context */
+       ctr = SMB_MALLOC_P(struct perfcount_test_counter);
+       if (!ctr) {
+               SAFE_FREE(ctxt);
+               return;
+       }
+
+       ZERO_STRUCTP(ctr);
+       ctr->op = ctr->sub_op = ctr->ioctl = -1;
+       DLIST_ADD(ctxt->ops, ctr);
+
+       pcd->context = (void*)ctxt;
+}
+
+static void perfcount_test_add(struct smb_perfcount_data *pcd)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+       struct perfcount_test_counter *ctr;
+
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_add - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+
+       ctr = SMB_MALLOC_P(struct perfcount_test_counter);
+       if (!ctr) {
+               return;
+       }
+
+       DLIST_ADD(ctxt->ops, ctr);
+
+}
+
+static void perfcount_test_set_op(struct smb_perfcount_data *pcd, int op)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_op - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+
+       ctxt->ops->op = op;
+}
+
+static void perfcount_test_set_subop(struct smb_perfcount_data *pcd, int sub_op)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_sub_op - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+
+       ctxt->ops->sub_op = sub_op;
+}
+
+static void perfcount_test_set_ioctl(struct smb_perfcount_data *pcd, int io_ctl)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_ioctl - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+       ctxt->ops->ioctl = io_ctl;
+}
+
+static void perfcount_test_set_msglen_in(struct smb_perfcount_data *pcd,
+                                        uint64_t bytes_in)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_msglen_in - "
+                       "uninitialized perfcount context - %p\n", pcd));
+                return;
+       }
+       ctxt->ops->bytes_in = bytes_in;
+}
+
+static void perfcount_test_set_msglen_out(struct smb_perfcount_data *pcd,
+                                         uint64_t bytes_out)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_msglen_out - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+
+       ctxt->ops->bytes_out = bytes_out;
+}
+
+/*
+ * For perf reasons, its best to use some global state
+ * when an operation is deferred, we need to alloc a copy.
+ */
+static void perfcount_test_defer_op(struct smb_perfcount_data *pcd,
+                                   struct smb_perfcount_data *def_pcd)
+{
+       /* we don't do anything special to deferred ops */
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_set_msglen_out - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+}
+
+static void perfcount_test_set_client(struct smb_perfcount_data *pcd,
+                                           uid_t uid, const char *user,
+                                           const char *domain)
+{
+       // WIP
+       return;
+}
+
+static void perfcount_test_end(struct smb_perfcount_data *pcd)
+{
+       struct perfcount_test_context *ctxt = pcd->context;
+        if (pcd->context == NULL) {
+               DEBUG(0,("perfcount_test_end - uninitialized "
+                       "perfcount context - %p\n", pcd));
+                return;
+       }
+
+       /* @bug - we don't store outbytes right for chained cmds */
+       perfcount_test_add_counters(ctxt);
+       perfcount_test_dump_counters();
+       SAFE_FREE(ctxt);
+}
+
+
+static struct smb_perfcount_handlers perfcount_test_handlers = {
+       perfcount_test_start,
+       perfcount_test_add,
+       perfcount_test_set_op,
+       perfcount_test_set_subop,
+       perfcount_test_set_ioctl,
+       perfcount_test_set_msglen_in,
+       perfcount_test_set_msglen_out,
+       perfcount_test_set_client,
+       perfcount_test_defer_op,
+       perfcount_test_end
+};
+
+NTSTATUS perfcount_test_init(void)
+{
+       return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
+                                       "pc_test", &perfcount_test_handlers);
+}