lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[nivanova/samba-autobuild/.git] / source3 / modules / perfcount_test.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Test module for perfcounters
4  *
5  * Copyright (C) Todd Stecher 2008
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include "includes.h"
22 #include "smbd/smbd.h"
23
24 #define PARM_PC_TEST_TYPE               "pc_test"
25 #define PARM_DUMPON_COUNT               "count"
26 #define PARM_DUMPON_COUNT_DEFAULT       50
27
28 struct perfcount_test_identity {
29         uid_t uid;
30         char *user;
31         char *domain;
32 };
33
34 struct perfcount_test_counter {
35         int op;
36         int sub_op;
37         int ioctl;
38         uint64_t bytes_in;
39         uint64_t bytes_out;
40         int count;
41
42         struct perfcount_test_counter *next;
43         struct perfcount_test_counter *prev;
44 };
45
46 struct perfcount_test_context {
47
48         /* wip:  identity */
49         struct perfcount_test_identity *id;
50         struct perfcount_test_counter *ops;
51 };
52
53 #define MAX_OP 256
54 struct perfcount_test_counter *g_list[MAX_OP];
55
56 int count;
57
58 /* determine frequency of dumping results */
59 int count_mod = 1;
60
61 static void perfcount_test_add_counters(struct perfcount_test_context *ctxt)
62 {
63         struct perfcount_test_counter *head;
64         struct perfcount_test_counter *ptc;
65         struct perfcount_test_counter *tmp;
66         bool found;
67
68         for (ptc = ctxt->ops; ptc != NULL; ) {
69
70                 found = false;
71
72                 if (ptc->op >= MAX_OP)
73                         continue;
74
75                 for (head = g_list[ptc->op]; head != NULL; head = head->next) {
76                         if ((ptc->sub_op == head->sub_op) &&
77                             (ptc->ioctl == head->ioctl)) {
78                                 head->bytes_in += ptc->bytes_in;
79                                 head->bytes_out += ptc->bytes_out;
80                                 head->count++;
81                                 tmp = ptc->next;
82                                 DLIST_REMOVE(ctxt->ops, ptc);
83                                 SAFE_FREE(ptc);
84                                 ptc = tmp;
85                                 found = true;
86                                 break;
87                         }
88                 }
89
90                 /* not in global tracking list - add it */
91                 if (!found) {
92                         tmp = ptc->next;
93                         DLIST_REMOVE(ctxt->ops, ptc);
94                         ptc->count = 1;
95                         DLIST_ADD(g_list[ptc->op], ptc);
96                         ptc = tmp;
97                 }
98         }
99
100 }
101
102 #if 0
103
104 static void perfcount_test_dump_id(struct perfcount_test_identity *id, int lvl)
105 {
106         if (!id)
107                 return;
108
109         DEBUG(lvl,("uid - %d\n", id->uid));
110         DEBUG(lvl,("user - %s\n", id->user));
111         DEBUG(lvl,("domain - %s\n", id->domain));
112 }
113
114 #endif
115
116 static const char *trans_subop_table[] = {
117         "unknown", "trans:create", "trans:ioctl", "trans:set sd",
118         "trans:change notify", "trans: rename", "trans:get sd",
119         "trans:get quota", "trans:set quota"
120 };
121
122 static const char *trans2_subop_table[] = {
123         "trans2:open", "trans2:find first", "trans2:find next",
124         "trans2:q fsinfo", "trans2:set fsinfo", "trans2:q path info",
125         "trans2:set pathinfo", "trans2:fs ctl", "trans2: io ctl",
126         "trans2:find notify first", "trans2:find notify next",
127         "trans2:mkdir", "trans2:sess setup", "trans2:get dfs referral",
128         "trans2:report dfs inconsistent"
129 };
130
131 static const char *smb_subop_name(int op, int subop)
132 {
133         /* trans */
134         if (op == 0x25) {
135                 if (subop >= sizeof(trans_subop_table) /
136                     sizeof(trans_subop_table[0])) {
137                         return "unknown";
138                 }
139                 return trans_subop_table[subop];
140         } else if (op == 0x32) {
141                 if (subop >= sizeof(trans2_subop_table) /
142                     sizeof(trans2_subop_table[0])) {
143                         return "unknown";
144                 }
145                 return trans2_subop_table[subop];
146         }
147
148         return "unknown";
149 }
150
151 static void perfcount_test_dump_counter(struct perfcount_test_counter *ptc,
152                                         int lvl)
153 {
154         DEBUG(lvl, ("OP: %s\n", smb_fn_name(ptc->op)));
155         if (ptc->sub_op > 0) {
156                 DEBUG(lvl, ("SUBOP: %s\n",
157                         smb_subop_name(ptc->op, ptc->sub_op)));
158         }
159
160         if (ptc->ioctl > 0) {
161                 DEBUG(lvl, ("IOCTL: %d\n", ptc->ioctl));
162         }
163
164         DEBUG(lvl, ("Count: %d\n\n", ptc->count));
165 }
166
167 static void perfcount_test_dump_counters(void)
168 {
169         int i;
170         struct perfcount_test_counter *head;
171
172         count_mod = lp_parm_int(0, PARM_PC_TEST_TYPE, PARM_DUMPON_COUNT,
173             PARM_DUMPON_COUNT_DEFAULT);
174
175         if (count_mod == 0) {
176                 return;
177         }
178
179         if ((count++ % count_mod) != 0)
180                 return;
181
182         DEBUG(0,("#####  Dumping Performance Counters #####\n"));
183
184         for (i=0; i < MAX_OP; i++) {
185                 struct perfcount_test_counter *next;
186                 for (head = g_list[i]; head != NULL; head = next) {
187                         next = head->next;
188                         perfcount_test_dump_counter(head, 0);
189                         SAFE_FREE(head);
190                 }
191                 g_list[i] = NULL;
192         }
193 }
194
195 /*  operations */
196 static void perfcount_test_start(struct smb_perfcount_data *pcd)
197 {
198         struct perfcount_test_context *ctxt;
199         struct perfcount_test_counter *ctr;
200         /*
201          * there shouldn't already be a context here - if so,
202          * there's an unbalanced call to start / end.
203          */
204         if (pcd->context) {
205                 DEBUG(0,("perfcount_test_start - starting "
206                          "initialized context - %p\n", pcd));
207                 return;
208         }
209
210         ctxt = SMB_MALLOC_P(struct perfcount_test_context);
211         if (!ctxt)
212                 return;
213
214         ZERO_STRUCTP(ctxt);
215
216         /* create 'default' context */
217         ctr = SMB_MALLOC_P(struct perfcount_test_counter);
218         if (!ctr) {
219                 SAFE_FREE(ctxt);
220                 return;
221         }
222
223         ZERO_STRUCTP(ctr);
224         ctr->op = ctr->sub_op = ctr->ioctl = -1;
225         DLIST_ADD(ctxt->ops, ctr);
226
227         pcd->context = (void*)ctxt;
228 }
229
230 static void perfcount_test_add(struct smb_perfcount_data *pcd)
231 {
232         struct perfcount_test_context *ctxt =
233                 (struct perfcount_test_context *)pcd->context;
234         struct perfcount_test_counter *ctr;
235
236         if (pcd->context == NULL)
237                 return;
238
239         ctr = SMB_MALLOC_P(struct perfcount_test_counter);
240         if (!ctr) {
241                 return;
242         }
243
244         DLIST_ADD(ctxt->ops, ctr);
245
246 }
247
248 static void perfcount_test_set_op(struct smb_perfcount_data *pcd, int op)
249 {
250         struct perfcount_test_context *ctxt =
251                 (struct perfcount_test_context *)pcd->context;
252
253         if (pcd->context == NULL)
254                 return;
255
256         ctxt->ops->op = op;
257 }
258
259 static void perfcount_test_set_subop(struct smb_perfcount_data *pcd, int sub_op)
260 {
261         struct perfcount_test_context *ctxt =
262                 (struct perfcount_test_context *)pcd->context;
263
264         if (pcd->context == NULL)
265                 return;
266
267         ctxt->ops->sub_op = sub_op;
268 }
269
270 static void perfcount_test_set_ioctl(struct smb_perfcount_data *pcd, int io_ctl)
271 {
272         struct perfcount_test_context *ctxt =
273                 (struct perfcount_test_context *)pcd->context;
274         if (pcd->context == NULL)
275                 return;
276
277         ctxt->ops->ioctl = io_ctl;
278 }
279
280 static void perfcount_test_set_msglen_in(struct smb_perfcount_data *pcd,
281                                          uint64_t bytes_in)
282 {
283         struct perfcount_test_context *ctxt =
284                 (struct perfcount_test_context *)pcd->context;
285         if (pcd->context == NULL)
286                 return;
287
288         ctxt->ops->bytes_in = bytes_in;
289 }
290
291 static void perfcount_test_set_msglen_out(struct smb_perfcount_data *pcd,
292                                           uint64_t bytes_out)
293 {
294         struct perfcount_test_context *ctxt =
295                 (struct perfcount_test_context *)pcd->context;
296
297         if (pcd->context == NULL)
298                 return;
299
300         ctxt->ops->bytes_out = bytes_out;
301 }
302
303 static void perfcount_test_copy_context(struct smb_perfcount_data *pcd,
304                                         struct smb_perfcount_data *new_pcd)
305 {
306         struct perfcount_test_context *ctxt =
307                 (struct perfcount_test_context *)pcd->context;
308         struct perfcount_test_context *new_ctxt;
309
310         struct perfcount_test_counter *ctr;
311         struct perfcount_test_counter *new_ctr;
312
313         if (pcd->context == NULL)
314                 return;
315
316         new_ctxt = SMB_MALLOC_P(struct perfcount_test_context);
317         if (!new_ctxt) {
318                 return;
319         }
320
321         memcpy(new_ctxt, ctxt, sizeof(struct perfcount_test_context));
322
323         for (ctr = ctxt->ops; ctr != NULL; ctr = ctr->next) {
324                 new_ctr = SMB_MALLOC_P(struct perfcount_test_counter);
325                 if (!new_ctr) {
326                         goto error;
327                 }
328
329                 memcpy(new_ctr, ctr, sizeof(struct perfcount_test_counter));
330                 new_ctr->next = NULL;
331                 new_ctr->prev = NULL;
332                 DLIST_ADD(new_ctxt->ops, new_ctr);
333         }
334
335         new_pcd->context = new_ctxt;
336         return;
337
338 error:
339
340         for (ctr = new_ctxt->ops; ctr != NULL; ) {
341                 new_ctr = ctr->next;
342                 SAFE_FREE(ctr);
343                 ctr = new_ctr;
344         }
345
346         SAFE_FREE(new_ctxt);
347 }
348
349 /*
350  * For perf reasons, its best to use some global state
351  * when an operation is deferred, we need to alloc a copy.
352  */
353 static void perfcount_test_defer_op(struct smb_perfcount_data *pcd,
354                                     struct smb_perfcount_data *def_pcd)
355 {
356         /* we don't do anything special to deferred ops */
357         return;
358 }
359
360 static void perfcount_test_end(struct smb_perfcount_data *pcd)
361 {
362         struct perfcount_test_context *ctxt =
363                 (struct perfcount_test_context *)pcd->context;
364         if (pcd->context == NULL)
365                 return;
366
367         /* @bug - we don't store outbytes right for chained cmds */
368         perfcount_test_add_counters(ctxt);
369         perfcount_test_dump_counters();
370         pcd->context = NULL;
371         SAFE_FREE(ctxt);
372 }
373
374
375 static struct smb_perfcount_handlers perfcount_test_handlers = {
376         perfcount_test_start,
377         perfcount_test_add,
378         perfcount_test_set_op,
379         perfcount_test_set_subop,
380         perfcount_test_set_ioctl,
381         perfcount_test_set_msglen_in,
382         perfcount_test_set_msglen_out,
383         perfcount_test_copy_context,
384         perfcount_test_defer_op,
385         perfcount_test_end
386 };
387
388 static_decl_perfcount;
389 NTSTATUS perfcount_test_init(TALLOC_CTX *ctx)
390 {
391         return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
392                                         "pc_test", &perfcount_test_handlers);
393 }