diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/perfcount_test.c | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/source3/modules/perfcount_test.c b/source3/modules/perfcount_test.c new file mode 100644 index 0000000000..e0954bf9d7 --- /dev/null +++ b/source3/modules/perfcount_test.c @@ -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); +} |