00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00043 #define _GNU_SOURCE
00044 #include <string.h>
00045 #include <sys/time.h>
00046 #include <stdlib.h>
00047
00048 #include "../../sr_module.h"
00049 #include "../../lib/kmi/mi.h"
00050 #include "../../mem/mem.h"
00051 #include "../../ut.h"
00052
00053 #include "benchmark.h"
00054
00055 #include "../../mem/shm_mem.h"
00056
00057
00058 MODULE_VERSION
00059
00060
00061 int bm_start_timer(struct sip_msg* _msg, char* timer, char *foobar);
00062 int bm_log_timer(struct sip_msg* _msg, char* timer, char* mystr);
00063
00064
00065
00066
00067 static void destroy(void);
00068
00069
00070
00071
00072
00073 static int mod_init(void);
00074
00075
00076
00077
00078
00079
00080 static int bm_enable_global = 0;
00081 static int bm_granularity = 1;
00082 static int bm_loglevel = L_INFO;
00083
00084 static int _bm_last_time_diff = 0;
00085
00086
00087
00088
00089
00090 typedef struct bm_cfg {
00091 int enable_global;
00092 int granularity;
00093 int loglevel;
00094
00095 int nrtimers;
00096 benchmark_timer_t *timers;
00097 benchmark_timer_t **tindex;
00098 } bm_cfg_t;
00099
00100
00101
00102
00103
00104
00105 bm_cfg_t *bm_mycfg = 0;
00106
00107 static inline int fixup_bm_timer(void** param, int param_no);
00108
00109
00110
00111
00112 static cmd_export_t cmds[] = {
00113 { "bm_start_timer", (cmd_function)bm_start_timer, 1, fixup_bm_timer, 0,
00114 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
00115 { "bm_log_timer", (cmd_function)bm_log_timer, 1, fixup_bm_timer, 0,
00116 REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE },
00117 {"load_bm", (cmd_function)load_bm, 0, 0, 0, 0},
00118 { 0, 0, 0, 0, 0, 0 }
00119 };
00120
00121
00122
00123
00124
00125 static param_export_t params[] = {
00126 {"enable", INT_PARAM, &bm_enable_global},
00127 {"granularity", INT_PARAM, &bm_granularity},
00128 {"loglevel", INT_PARAM, &bm_loglevel},
00129 { 0, 0, 0 }
00130 };
00131
00132
00133
00134
00135
00136 struct mi_root* mi_bm_enable_global(struct mi_root *cmd, void *param);
00137 struct mi_root* mi_bm_enable_timer(struct mi_root *cmd, void *param);
00138 struct mi_root* mi_bm_granularity(struct mi_root *cmd, void *param);
00139 struct mi_root* mi_bm_loglevel(struct mi_root *cmd, void *param);
00140
00141 static mi_export_t mi_cmds[] = {
00142 { "bm_enable_global", mi_bm_enable_global, 0, 0, 0 },
00143 { "bm_enable_timer", mi_bm_enable_timer, 0, 0, 0 },
00144 { "bm_granularity", mi_bm_granularity, 0, 0, 0 },
00145 { "bm_loglevel", mi_bm_loglevel, 0, 0, 0 },
00146 { 0, 0, 0, 0, 0}
00147 };
00148
00149 static int bm_get_time_diff(struct sip_msg *msg, pv_param_t *param,
00150 pv_value_t *res);
00151
00152 static pv_export_t mod_items[] = {
00153 { {"BM_time_diff", sizeof("BM_time_diff")-1}, PVT_OTHER, bm_get_time_diff, 0,
00154 0, 0, 0, 0 },
00155 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00156 };
00157
00158
00159
00160
00161 struct module_exports exports = {
00162 "benchmark",
00163 DEFAULT_DLFLAGS,
00164 cmds,
00165 params,
00166 0,
00167 mi_cmds,
00168 mod_items,
00169 0,
00170 mod_init,
00171 0,
00172 destroy,
00173 0
00174 };
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 static int mod_init(void) {
00185 if(register_mi_mod(exports.name, mi_cmds)!=0)
00186 {
00187 LM_ERR("failed to register MI commands\n");
00188 return -1;
00189 }
00190
00191 bm_mycfg = (bm_cfg_t*)shm_malloc(sizeof(bm_cfg_t));
00192 memset(bm_mycfg, 0, sizeof(bm_cfg_t));
00193 bm_mycfg->enable_global = bm_enable_global;
00194 bm_mycfg->granularity = bm_granularity;
00195 bm_mycfg->loglevel = bm_loglevel;
00196
00197 return 0;
00198 }
00199
00200
00201
00202
00203
00204
00205 static void destroy(void)
00206 {
00207 benchmark_timer_t *bmt = 0;
00208 benchmark_timer_t *bmp = 0;
00209
00210 if(bm_mycfg!=NULL)
00211 {
00212
00213 bmt = bm_mycfg->timers;
00214 while(bmt)
00215 {
00216 bmp = bmt;
00217 bmt = bmt->next;
00218 shm_free(bmp);
00219 }
00220 if(bm_mycfg->tindex) shm_free(bm_mycfg->tindex);
00221 shm_free(bm_mycfg);
00222 }
00223 }
00224
00225 void bm_reset_timer(int i)
00226 {
00227 if(bm_mycfg==NULL || bm_mycfg->tindex[i]==NULL)
00228 return;
00229 bm_mycfg->tindex[i]->calls = 0;
00230 bm_mycfg->tindex[i]->sum = 0;
00231 bm_mycfg->tindex[i]->last_max = 0;
00232 bm_mycfg->tindex[i]->last_min = 0xffffffff;
00233 bm_mycfg->tindex[i]->last_sum = 0;
00234 bm_mycfg->tindex[i]->global_max = 0;
00235 bm_mycfg->tindex[i]->global_min = 0xffffffff;
00236 }
00237
00238 void reset_timers(void)
00239 {
00240 int i;
00241 if(bm_mycfg==NULL)
00242 return;
00243
00244 for (i = 0; i < bm_mycfg->nrtimers; i++)
00245 bm_reset_timer(i);
00246 }
00247
00257 inline int timer_active(unsigned int id)
00258 {
00259 if (bm_mycfg->enable_global > 0 || bm_mycfg->timers[id].enabled > 0)
00260 return 1;
00261 else
00262 return 0;
00263 }
00264
00265
00270 int _bm_start_timer(unsigned int id)
00271 {
00272 if (timer_active(id))
00273 {
00274 if(bm_get_time(bm_mycfg->tindex[id]->start)!=0)
00275 {
00276 LM_ERR("error getting current time\n");
00277 return -1;
00278 }
00279 }
00280
00281 return 1;
00282 }
00283
00284 int bm_start_timer(struct sip_msg* _msg, char* timer, char *foobar)
00285 {
00286 return _bm_start_timer((unsigned int)(unsigned long)timer);
00287 }
00288
00289
00294 int _bm_log_timer(unsigned int id)
00295 {
00296
00297 bm_timeval_t now;
00298 unsigned long long tdiff;
00299
00300 if (!timer_active(id))
00301 return 1;
00302
00303 if(bm_get_time(&now)<0)
00304 {
00305 LM_ERR("error getting current time\n");
00306 return -1;
00307 }
00308
00309 tdiff = bm_diff_time(bm_mycfg->tindex[id]->start, &now);
00310 _bm_last_time_diff = (int)tdiff;
00311
00312
00313
00314
00315
00316
00317 bm_mycfg->tindex[id]->sum += tdiff;
00318 bm_mycfg->tindex[id]->last_sum += tdiff;
00319 bm_mycfg->tindex[id]->calls++;
00320
00321 if (tdiff < bm_mycfg->tindex[id]->last_min)
00322 bm_mycfg->tindex[id]->last_min = tdiff;
00323
00324 if (tdiff > bm_mycfg->tindex[id]->last_max)
00325 bm_mycfg->tindex[id]->last_max = tdiff;
00326
00327 if (tdiff < bm_mycfg->tindex[id]->global_min)
00328 bm_mycfg->tindex[id]->global_min = tdiff;
00329
00330 if (tdiff > bm_mycfg->tindex[id]->global_max)
00331 bm_mycfg->tindex[id]->global_max = tdiff;
00332
00333
00334 if ((bm_mycfg->tindex[id]->calls % bm_mycfg->granularity) == 0)
00335 {
00336 LM_GEN1(bm_mycfg->loglevel, "benchmark (timer %s [%d]): %llu ["
00337 " msgs/total/min/max/avg - LR:"
00338 " %i/%llu/%llu/%llu/%f | GB: %llu/%llu/%llu/%llu/%f]\n",
00339 bm_mycfg->tindex[id]->name,
00340 id,
00341 tdiff,
00342 bm_mycfg->granularity,
00343 bm_mycfg->tindex[id]->last_sum,
00344 bm_mycfg->tindex[id]->last_min,
00345 bm_mycfg->tindex[id]->last_max,
00346 ((double)bm_mycfg->tindex[id]->last_sum)/bm_mycfg->granularity,
00347 bm_mycfg->tindex[id]->calls,
00348 bm_mycfg->tindex[id]->sum,
00349 bm_mycfg->tindex[id]->global_min,
00350 bm_mycfg->tindex[id]->global_max,
00351 ((double)bm_mycfg->tindex[id]->sum)/bm_mycfg->tindex[id]->calls);
00352
00353 bm_mycfg->tindex[id]->last_sum = 0;
00354 bm_mycfg->tindex[id]->last_max = 0;
00355 bm_mycfg->tindex[id]->last_min = 0xffffffff;
00356 }
00357
00358 return 1;
00359 }
00360
00361 int bm_log_timer(struct sip_msg* _msg, char* timer, char* mystr)
00362 {
00363 return _bm_log_timer((unsigned int)(unsigned long)timer);
00364 }
00365
00366 int _bm_register_timer(char *tname, int mode, unsigned int *id)
00367 {
00368 benchmark_timer_t *bmt = 0;
00369 benchmark_timer_t **tidx = 0;
00370
00371 if(tname==NULL || id==NULL || bm_mycfg==NULL || strlen(tname)==0
00372 || strlen(tname)>BM_NAME_LEN-1)
00373 return -1;
00374
00375 bmt = bm_mycfg->timers;
00376 while(bmt)
00377 {
00378 if(strcmp(bmt->name, tname)==0)
00379 {
00380 *id = bmt->id;
00381 return 0;
00382 }
00383 bmt = bmt->next;
00384 }
00385 if(mode==0)
00386 return -1;
00387
00388 bmt = (benchmark_timer_t*)shm_malloc(sizeof(benchmark_timer_t));
00389
00390 if(bmt==0)
00391 {
00392 LM_ERR("no more shm\n");
00393 return -1;
00394 }
00395 memset(bmt, 0, sizeof(benchmark_timer_t));
00396
00397
00398 bmt->start = (bm_timeval_t*)pkg_malloc(sizeof(bm_timeval_t));
00399 if(bmt->start == NULL)
00400 {
00401 shm_free(bmt);
00402 LM_ERR("no more pkg\n");
00403 return -1;
00404 }
00405 memset(bmt->start, 0, sizeof(bm_timeval_t));
00406
00407 strcpy(bmt->name, tname);
00408 if(bm_mycfg->timers==0)
00409 {
00410 bmt->id = 0;
00411 bm_mycfg->timers = bmt;
00412 } else {
00413 bmt->id = bm_mycfg->timers->id+1;
00414 bmt->next = bm_mycfg->timers;
00415 bm_mycfg->timers = bmt;
00416 }
00417
00418
00419 if(bmt->id%10==0)
00420 {
00421 if(bm_mycfg->tindex!=NULL)
00422 tidx = bm_mycfg->tindex;
00423 bm_mycfg->tindex = (benchmark_timer_t**)shm_malloc((10+bmt->id)*
00424 sizeof(benchmark_timer_t*));
00425 if(bm_mycfg->tindex==0)
00426 {
00427 LM_ERR("no more share memory\n");
00428 if(tidx!=0)
00429 shm_free(tidx);
00430 return -1;
00431 }
00432 memset(bm_mycfg->tindex, 0, (10+bmt->id)*sizeof(benchmark_timer_t*));
00433 if(tidx!=0)
00434 {
00435 memcpy(bm_mycfg->tindex, tidx, bmt->id*sizeof(benchmark_timer_t*));
00436 shm_free(tidx);
00437 }
00438 }
00439 bm_mycfg->tindex[bmt->id] = bmt;
00440 bm_mycfg->nrtimers = bmt->id + 1;
00441 bm_reset_timer(bmt->id);
00442 *id = bmt->id;
00443 LM_DBG("timer [%s] added with index <%u>\n", bmt->name, bmt->id);
00444
00445 return 0;
00446 }
00447
00449 int load_bm( struct bm_binds *bmb)
00450 {
00451 if(bmb==NULL)
00452 return -1;
00453
00454 bmb->bm_register = _bm_register_timer;
00455 bmb->bm_start = _bm_start_timer;
00456 bmb->bm_log = _bm_log_timer;
00457
00458 return 1;
00459 }
00460
00461
00462 static inline char * pkg_strndup( char* _p, int _len)
00463 {
00464 char *s;
00465
00466 s = (char*)pkg_malloc(_len+1);
00467 if (s==NULL)
00468 return NULL;
00469 memcpy(s,_p,_len);
00470 s[_len] = 0;
00471 return s;
00472 }
00473
00474
00476
00481 struct mi_root* mi_bm_enable_global(struct mi_root *cmd, void *param)
00482 {
00483 struct mi_node *node;
00484
00485 char *p1, *e1;
00486 long int v1;
00487
00488 node = cmd->node.kids;
00489
00490 if ((node == NULL) || (node->next != NULL))
00491 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00492
00493 p1 = pkg_strndup(node->value.s, node->value.len);
00494
00495 v1 = strtol(p1, &e1, 0);
00496
00497 if ((*e1 != '\0') || (*p1 == '\0')) {
00498 pkg_free(p1);
00499 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00500 }
00501
00502 if ((v1 < -1) || (v1 > 1)) {
00503 pkg_free(p1);
00504 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00505 }
00506
00507 bm_mycfg->enable_global = v1;
00508
00509 pkg_free(p1);
00510 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00511 }
00512
00513 struct mi_root* mi_bm_enable_timer(struct mi_root *cmd, void *param)
00514 {
00515 struct mi_node *node;
00516
00517 char *p1, *p2, *e2;
00518 long int v2;
00519 unsigned int id;
00520
00521 node = cmd->node.kids;
00522
00523 if ((node == NULL) || (node->next == NULL) || (node->next->next != NULL))
00524 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00525
00526 p1 = pkg_strndup(node->value.s, node->value.len);
00527
00528 if(_bm_register_timer(p1, 0, &id)!=0)
00529 {
00530 pkg_free(p1);
00531 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00532 }
00533 p2 = pkg_strndup(node->next->value.s, node->next->value.len);
00534 v2 = strtol(p2, &e2, 0);
00535
00536 pkg_free(p1);
00537 pkg_free(p2);
00538
00539 if (*e2 != '\0' || *p2 == '\0')
00540 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00541
00542 if ((v2 < 0) || (v2 > 1))
00543 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00544
00545 bm_mycfg->timers[id].enabled = v2;
00546
00547 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00548 }
00549
00550 struct mi_root* mi_bm_granularity(struct mi_root *cmd, void *param)
00551 {
00552 struct mi_node *node;
00553
00554 char *p1, *e1;
00555 long int v1;
00556
00557 node = cmd->node.kids;
00558
00559 if ((node == NULL) || (node->next != NULL))
00560 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00561
00562 p1 = pkg_strndup(node->value.s, node->value.len);
00563
00564 v1 = strtol(p1, &e1, 0);
00565
00566 pkg_free(p1);
00567
00568 if ((*e1 != '\0') || (*p1 == '\0'))
00569 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00570
00571 if (v1 < 1)
00572 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00573
00574 bm_mycfg->granularity = v1;
00575
00576 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00577 }
00578
00579 struct mi_root* mi_bm_loglevel(struct mi_root *cmd, void *param)
00580 {
00581 struct mi_node *node;
00582
00583 char *p1, *e1;
00584 long int v1;
00585
00586 node = cmd->node.kids;
00587
00588 if ((node == NULL) || (node->next != NULL))
00589 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00590
00591 p1 = pkg_strndup(node->value.s, node->value.len);
00592
00593 v1 = strtol(p1, &e1, 0);
00594
00595 pkg_free(p1);
00596
00597 if ((*e1 != '\0') || (*p1 == '\0'))
00598 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00599
00600 if ((v1 < -3) || (v1 > 4))
00601 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00602
00603 bm_mycfg->enable_global = v1;
00604
00605 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00606 }
00610 static int bm_get_time_diff(struct sip_msg *msg, pv_param_t *param,
00611 pv_value_t *res)
00612 {
00613 if(msg==NULL)
00614 return -1;
00615 return pv_get_sintval(msg, param, res, _bm_last_time_diff);
00616 }
00617
00618
00619 static inline int fixup_bm_timer(void** param, int param_no)
00620 {
00621 unsigned int tid = 0;
00622 if (param_no == 1)
00623 {
00624 if((_bm_register_timer((char*)(*param), 1, &tid))!=0)
00625 {
00626 LM_ERR("cannot register timer [%s]\n", (char*)(*param));
00627 return E_UNSPEC;
00628 }
00629 pkg_free(*param);
00630 *param = (void*)(unsigned long)tid;
00631 }
00632 return 0;
00633 }
00634
00635