1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00
samba-mirror/source3/modules/perfcount_test.c
Jelmer Vernooij 05bc4de083 Revert making public of the samba-module library.
This library was tiny - containing just two public functions than were
themselves trivial. The amount of overhead this causes isn't really worth the
benefits of sharing the code with other projects like OpenChange. In addition, this code
isn't really generically useful anyway, as it can only load from the module path
set for Samba at configure time.

Adding a new library was breaking the API/ABI anyway, so OpenChange had to be
updated to cope with the new situation one way or another. I've added a simpler
(compatible) routine for loading modules to OpenChange, which is less than 100 lines of code.

Autobuild-User: Jelmer Vernooij <jelmer@samba.org>
Autobuild-Date: Sat Dec  3 08:36:33 CET 2011 on sn-devel-104
2011-12-03 08:36:30 +01:00

389 lines
8.9 KiB
C

/*
* 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++ % 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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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
};
NTSTATUS samba_init_module(void)
{
return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
"pc_test", &perfcount_test_handlers);
}