1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-24 21:34:56 +03:00
samba-mirror/source3/modules/perfcount_test.c

394 lines
9.0 KiB
C
Raw Normal View History

/*
* 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"
#include "smbd/smbd.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_mod == 0) {
return;
}
if ((count++ % count_mod) != 0)
return;
DEBUG(0,("##### Dumping Performance Counters #####\n"));
for (i=0; i < MAX_OP; i++) {
struct perfcount_test_counter *next;
for (head = g_list[i]; head != NULL; head = next) {
next = head->next;
perfcount_test_dump_counter(head, 0);
SAFE_FREE(head);
}
g_list[i] = NULL;
}
}
/* 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)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
struct perfcount_test_counter *ctr;
if (pcd->context == NULL)
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)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
ctxt->ops->op = op;
}
static void perfcount_test_set_subop(struct smb_perfcount_data *pcd, int sub_op)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
ctxt->ops->sub_op = sub_op;
}
static void perfcount_test_set_ioctl(struct smb_perfcount_data *pcd, int io_ctl)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
ctxt->ops->ioctl = io_ctl;
}
static void perfcount_test_set_msglen_in(struct smb_perfcount_data *pcd,
uint64_t bytes_in)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
ctxt->ops->bytes_in = bytes_in;
}
static void perfcount_test_set_msglen_out(struct smb_perfcount_data *pcd,
uint64_t bytes_out)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
ctxt->ops->bytes_out = bytes_out;
}
static void perfcount_test_copy_context(struct smb_perfcount_data *pcd,
struct smb_perfcount_data *new_pcd)
{
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
struct perfcount_test_context *new_ctxt;
struct perfcount_test_counter *ctr;
struct perfcount_test_counter *new_ctr;
if (pcd->context == NULL)
return;
new_ctxt = SMB_MALLOC_P(struct perfcount_test_context);
if (!new_ctxt) {
return;
}
memcpy(new_ctxt, ctxt, sizeof(struct perfcount_test_context));
for (ctr = ctxt->ops; ctr != NULL; ctr = ctr->next) {
new_ctr = SMB_MALLOC_P(struct perfcount_test_counter);
if (!new_ctr) {
goto error;
}
memcpy(new_ctr, ctr, sizeof(struct perfcount_test_counter));
new_ctr->next = NULL;
new_ctr->prev = NULL;
DLIST_ADD(new_ctxt->ops, new_ctr);
}
new_pcd->context = new_ctxt;
return;
error:
for (ctr = new_ctxt->ops; ctr != NULL; ) {
new_ctr = ctr->next;
SAFE_FREE(ctr);
ctr = new_ctr;
}
SAFE_FREE(new_ctxt);
}
/*
* 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 */
return;
}
static void perfcount_test_end(struct smb_perfcount_data *pcd)
{
2009-02-14 20:10:20 +03:00
struct perfcount_test_context *ctxt =
(struct perfcount_test_context *)pcd->context;
if (pcd->context == NULL)
return;
/* @bug - we don't store outbytes right for chained cmds */
perfcount_test_add_counters(ctxt);
perfcount_test_dump_counters();
pcd->context = NULL;
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_copy_context,
perfcount_test_defer_op,
perfcount_test_end
};
static_decl_perfcount;
NTSTATUS perfcount_test_init(TALLOC_CTX *ctx)
{
return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
"pc_test", &perfcount_test_handlers);
}