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);
183 SAFE_FREE(head
->prev
);
190 static void perfcount_test_start(struct smb_perfcount_data
*pcd
)
192 struct perfcount_test_context
*ctxt
;
193 struct perfcount_test_counter
*ctr
;
195 * there shouldn't already be a context here - if so,
196 * there's an unbalanced call to start / end.
199 DEBUG(0,("perfcount_test_start - starting "
200 "initialized context - %p\n", pcd
));
204 ctxt
= SMB_MALLOC_P(struct perfcount_test_context
);
210 /* create 'default' context */
211 ctr
= SMB_MALLOC_P(struct perfcount_test_counter
);
218 ctr
->op
= ctr
->sub_op
= ctr
->ioctl
= -1;
219 DLIST_ADD(ctxt
->ops
, ctr
);
221 pcd
->context
= (void*)ctxt
;
224 static void perfcount_test_add(struct smb_perfcount_data
*pcd
)
226 struct perfcount_test_context
*ctxt
=
227 (struct perfcount_test_context
*)pcd
->context
;
228 struct perfcount_test_counter
*ctr
;
230 if (pcd
->context
== NULL
)
233 ctr
= SMB_MALLOC_P(struct perfcount_test_counter
);
238 DLIST_ADD(ctxt
->ops
, ctr
);
242 static void perfcount_test_set_op(struct smb_perfcount_data
*pcd
, int op
)
244 struct perfcount_test_context
*ctxt
=
245 (struct perfcount_test_context
*)pcd
->context
;
247 if (pcd
->context
== NULL
)
253 static void perfcount_test_set_subop(struct smb_perfcount_data
*pcd
, int sub_op
)
255 struct perfcount_test_context
*ctxt
=
256 (struct perfcount_test_context
*)pcd
->context
;
258 if (pcd
->context
== NULL
)
261 ctxt
->ops
->sub_op
= sub_op
;
264 static void perfcount_test_set_ioctl(struct smb_perfcount_data
*pcd
, int io_ctl
)
266 struct perfcount_test_context
*ctxt
=
267 (struct perfcount_test_context
*)pcd
->context
;
268 if (pcd
->context
== NULL
)
271 ctxt
->ops
->ioctl
= io_ctl
;
274 static void perfcount_test_set_msglen_in(struct smb_perfcount_data
*pcd
,
277 struct perfcount_test_context
*ctxt
=
278 (struct perfcount_test_context
*)pcd
->context
;
279 if (pcd
->context
== NULL
)
282 ctxt
->ops
->bytes_in
= bytes_in
;
285 static void perfcount_test_set_msglen_out(struct smb_perfcount_data
*pcd
,
288 struct perfcount_test_context
*ctxt
=
289 (struct perfcount_test_context
*)pcd
->context
;
291 if (pcd
->context
== NULL
)
294 ctxt
->ops
->bytes_out
= bytes_out
;
297 static void perfcount_test_copy_context(struct smb_perfcount_data
*pcd
,
298 struct smb_perfcount_data
*new_pcd
)
300 struct perfcount_test_context
*ctxt
=
301 (struct perfcount_test_context
*)pcd
->context
;
302 struct perfcount_test_context
*new_ctxt
;
304 struct perfcount_test_counter
*ctr
;
305 struct perfcount_test_counter
*new_ctr
;
307 if (pcd
->context
== NULL
)
310 new_ctxt
= SMB_MALLOC_P(struct perfcount_test_context
);
315 memcpy(new_ctxt
, ctxt
, sizeof(struct perfcount_test_context
));
317 for (ctr
= ctxt
->ops
; ctr
!= NULL
; ctr
= ctr
->next
) {
318 new_ctr
= SMB_MALLOC_P(struct perfcount_test_counter
);
323 memcpy(new_ctr
, ctr
, sizeof(struct perfcount_test_counter
));
324 new_ctr
->next
= NULL
;
325 new_ctr
->prev
= NULL
;
326 DLIST_ADD(new_ctxt
->ops
, new_ctr
);
329 new_pcd
->context
= new_ctxt
;
334 for (ctr
= new_ctxt
->ops
; ctr
!= NULL
; ) {
344 * For perf reasons, its best to use some global state
345 * when an operation is deferred, we need to alloc a copy.
347 static void perfcount_test_defer_op(struct smb_perfcount_data
*pcd
,
348 struct smb_perfcount_data
*def_pcd
)
350 /* we don't do anything special to deferred ops */
354 static void perfcount_test_set_client(struct smb_perfcount_data
*pcd
,
355 uid_t uid
, const char *user
,
362 static void perfcount_test_end(struct smb_perfcount_data
*pcd
)
364 struct perfcount_test_context
*ctxt
=
365 (struct perfcount_test_context
*)pcd
->context
;
366 if (pcd
->context
== NULL
)
369 /* @bug - we don't store outbytes right for chained cmds */
370 perfcount_test_add_counters(ctxt
);
371 perfcount_test_dump_counters();
377 static struct smb_perfcount_handlers perfcount_test_handlers
= {
378 perfcount_test_start
,
380 perfcount_test_set_op
,
381 perfcount_test_set_subop
,
382 perfcount_test_set_ioctl
,
383 perfcount_test_set_msglen_in
,
384 perfcount_test_set_msglen_out
,
385 perfcount_test_set_client
,
386 perfcount_test_copy_context
,
387 perfcount_test_defer_op
,
391 NTSTATUS
perfcount_test_init(void)
393 return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION
,
394 "pc_test", &perfcount_test_handlers
);