2 * Unix SMB/CIFS implementation.
3 * Test module for perfcounters
5 * Copyright (C) Todd Stecher 2008
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
23 #define PARM_PC_TEST_TYPE "pc_test"
24 #define PARM_DUMPON_COUNT "count"
25 #define PARM_DUMPON_COUNT_DEFAULT 50
27 struct perfcount_test_identity {
33 struct perfcount_test_counter {
41 struct perfcount_test_counter *next;
42 struct perfcount_test_counter *prev;
45 struct perfcount_test_context {
48 struct perfcount_test_identity *id;
49 struct perfcount_test_counter *ops;
53 struct perfcount_test_counter *g_list[MAX_OP];
57 /* determine frequency of dumping results */
60 static void perfcount_test_add_counters(struct perfcount_test_context *ctxt)
62 struct perfcount_test_counter *head;
63 struct perfcount_test_counter *ptc;
64 struct perfcount_test_counter *tmp;
67 for (ptc = ctxt->ops; ptc != NULL; ) {
74 for (head = g_list[ptc->op]; head != NULL; head = head->next) {
75 if ((ptc->sub_op == head->sub_op) &&
76 (ptc->ioctl == head->ioctl)) {
77 head->bytes_in += ptc->bytes_in;
78 head->bytes_out += ptc->bytes_out;
81 DLIST_REMOVE(ctxt->ops, ptc);
89 /* not in global tracking list - add it */
92 DLIST_REMOVE(ctxt->ops, ptc);
94 DLIST_ADD(g_list[ptc->op], ptc);
103 static void perfcount_test_dump_id(struct perfcount_test_identity *id, int lvl)
108 DEBUG(lvl,("uid - %d\n", id->uid));
109 DEBUG(lvl,("user - %s\n", id->user));
110 DEBUG(lvl,("domain - %s\n", id->domain));
115 static const char *trans_subop_table[] = {
116 "unknown", "trans:create", "trans:ioctl", "trans:set sd",
117 "trans:change notify", "trans: rename", "trans:get sd",
118 "trans:get quota", "trans:set quota"
121 static const char *trans2_subop_table[] = {
122 "trans2:open", "trans2:find first", "trans2:find next",
123 "trans2:q fsinfo", "trans2:set fsinfo", "trans2:q path info",
124 "trans2:set pathinfo", "trans2:fs ctl", "trans2: io ctl",
125 "trans2:find notify first", "trans2:find notify next",
126 "trans2:mkdir", "trans2:sess setup", "trans2:get dfs referral",
127 "trans2:report dfs inconsistent"
130 static const char *smb_subop_name(int op, int subop)
134 if (subop > sizeof(trans_subop_table) /
135 sizeof(trans_subop_table[0])) {
138 return trans_subop_table[subop];
139 } else if (op == 0x32) {
140 if (subop > sizeof(trans2_subop_table) /
141 sizeof(trans2_subop_table[0])) {
144 return trans2_subop_table[subop];
150 static void perfcount_test_dump_counter(struct perfcount_test_counter *ptc,
153 DEBUG(lvl, ("OP: %s\n", smb_fn_name(ptc->op)));
154 if (ptc->sub_op > 0) {
155 DEBUG(lvl, ("SUBOP: %s\n",
156 smb_subop_name(ptc->op, ptc->sub_op)));
159 if (ptc->ioctl > 0) {
160 DEBUG(lvl, ("IOCTL: %d\n", ptc->ioctl));
163 DEBUG(lvl, ("Count: %d\n\n", ptc->count));
166 static void perfcount_test_dump_counters(void)
169 struct perfcount_test_counter *head;
171 count_mod = lp_parm_int(0, PARM_PC_TEST_TYPE, PARM_DUMPON_COUNT,
172 PARM_DUMPON_COUNT_DEFAULT);
174 if ((count++ % count_mod) != 0)
177 DEBUG(0,("##### Dumping Performance Counters #####\n"));
179 for (i=0; i < 256; i++) {
180 for (head = g_list[i]; head != NULL; head = head->next) {
181 perfcount_test_dump_counter(head, 0);
182 SAFE_FREE(DLIST_PREV(head));
189 static void perfcount_test_start(struct smb_perfcount_data *pcd)
191 struct perfcount_test_context *ctxt;
192 struct perfcount_test_counter *ctr;
194 * there shouldn't already be a context here - if so,
195 * there's an unbalanced call to start / end.
198 DEBUG(0,("perfcount_test_start - starting "
199 "initialized context - %p\n", pcd));
203 ctxt = SMB_MALLOC_P(struct perfcount_test_context);
209 /* create 'default' context */
210 ctr = SMB_MALLOC_P(struct perfcount_test_counter);
217 ctr->op = ctr->sub_op = ctr->ioctl = -1;
218 DLIST_ADD(ctxt->ops, ctr);
220 pcd->context = (void*)ctxt;
223 static void perfcount_test_add(struct smb_perfcount_data *pcd)
225 struct perfcount_test_context *ctxt =
226 (struct perfcount_test_context *)pcd->context;
227 struct perfcount_test_counter *ctr;
229 if (pcd->context == NULL)
232 ctr = SMB_MALLOC_P(struct perfcount_test_counter);
237 DLIST_ADD(ctxt->ops, ctr);
241 static void perfcount_test_set_op(struct smb_perfcount_data *pcd, int op)
243 struct perfcount_test_context *ctxt =
244 (struct perfcount_test_context *)pcd->context;
246 if (pcd->context == NULL)
252 static void perfcount_test_set_subop(struct smb_perfcount_data *pcd, int sub_op)
254 struct perfcount_test_context *ctxt =
255 (struct perfcount_test_context *)pcd->context;
257 if (pcd->context == NULL)
260 ctxt->ops->sub_op = sub_op;
263 static void perfcount_test_set_ioctl(struct smb_perfcount_data *pcd, int io_ctl)
265 struct perfcount_test_context *ctxt =
266 (struct perfcount_test_context *)pcd->context;
267 if (pcd->context == NULL)
270 ctxt->ops->ioctl = io_ctl;
273 static void perfcount_test_set_msglen_in(struct smb_perfcount_data *pcd,
276 struct perfcount_test_context *ctxt =
277 (struct perfcount_test_context *)pcd->context;
278 if (pcd->context == NULL)
281 ctxt->ops->bytes_in = bytes_in;
284 static void perfcount_test_set_msglen_out(struct smb_perfcount_data *pcd,
287 struct perfcount_test_context *ctxt =
288 (struct perfcount_test_context *)pcd->context;
290 if (pcd->context == NULL)
293 ctxt->ops->bytes_out = bytes_out;
296 static void perfcount_test_copy_context(struct smb_perfcount_data *pcd,
297 struct smb_perfcount_data *new_pcd)
299 struct perfcount_test_context *ctxt =
300 (struct perfcount_test_context *)pcd->context;
301 struct perfcount_test_context *new_ctxt;
303 struct perfcount_test_counter *ctr;
304 struct perfcount_test_counter *new_ctr;
306 if (pcd->context == NULL)
309 new_ctxt = SMB_MALLOC_P(struct perfcount_test_context);
314 memcpy(new_ctxt, ctxt, sizeof(struct perfcount_test_context));
316 for (ctr = ctxt->ops; ctr != NULL; ctr = ctr->next) {
317 new_ctr = SMB_MALLOC_P(struct perfcount_test_counter);
322 memcpy(new_ctr, ctr, sizeof(struct perfcount_test_counter));
323 new_ctr->next = NULL;
324 new_ctr->prev = NULL;
325 DLIST_ADD(new_ctxt->ops, new_ctr);
328 new_pcd->context = new_ctxt;
333 for (ctr = new_ctxt->ops; ctr != NULL; ) {
343 * For perf reasons, its best to use some global state
344 * when an operation is deferred, we need to alloc a copy.
346 static void perfcount_test_defer_op(struct smb_perfcount_data *pcd,
347 struct smb_perfcount_data *def_pcd)
349 /* we don't do anything special to deferred ops */
353 static void perfcount_test_end(struct smb_perfcount_data *pcd)
355 struct perfcount_test_context *ctxt =
356 (struct perfcount_test_context *)pcd->context;
357 if (pcd->context == NULL)
360 /* @bug - we don't store outbytes right for chained cmds */
361 perfcount_test_add_counters(ctxt);
362 perfcount_test_dump_counters();
368 static struct smb_perfcount_handlers perfcount_test_handlers = {
369 perfcount_test_start,
371 perfcount_test_set_op,
372 perfcount_test_set_subop,
373 perfcount_test_set_ioctl,
374 perfcount_test_set_msglen_in,
375 perfcount_test_set_msglen_out,
376 perfcount_test_copy_context,
377 perfcount_test_defer_op,
381 NTSTATUS perfcount_test_init(void)
383 return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
384 "pc_test", &perfcount_test_handlers);