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
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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 "../../mi/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 bm_mycfg = (bm_cfg_t*)shm_malloc(sizeof(bm_cfg_t));
00186 memset(bm_mycfg, 0, sizeof(bm_cfg_t));
00187 bm_mycfg->enable_global = bm_enable_global;
00188 bm_mycfg->granularity = bm_granularity;
00189 bm_mycfg->loglevel = bm_loglevel;
00190
00191 return 0;
00192 }
00193
00194
00195
00196
00197
00198
00199 static void destroy(void)
00200 {
00201 benchmark_timer_t *bmt = 0;
00202 benchmark_timer_t *bmp = 0;
00203
00204 if(bm_mycfg!=NULL)
00205 {
00206
00207 bmt = bm_mycfg->timers;
00208 while(bmt)
00209 {
00210 bmp = bmt;
00211 bmt = bmt->next;
00212 shm_free(bmp);
00213 }
00214 if(bm_mycfg->tindex) shm_free(bm_mycfg->tindex);
00215 shm_free(bm_mycfg);
00216 }
00217 }
00218
00219 void bm_reset_timer(int i)
00220 {
00221 if(bm_mycfg==NULL || bm_mycfg->tindex[i]==NULL)
00222 return;
00223 bm_mycfg->tindex[i]->calls = 0;
00224 bm_mycfg->tindex[i]->sum = 0;
00225 bm_mycfg->tindex[i]->last_max = 0;
00226 bm_mycfg->tindex[i]->last_min = 0xffffffff;
00227 bm_mycfg->tindex[i]->last_sum = 0;
00228 bm_mycfg->tindex[i]->global_max = 0;
00229 bm_mycfg->tindex[i]->global_min = 0xffffffff;
00230 }
00231
00232 void reset_timers(void)
00233 {
00234 int i;
00235 if(bm_mycfg==NULL)
00236 return;
00237
00238 for (i = 0; i < bm_mycfg->nrtimers; i++)
00239 bm_reset_timer(i);
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 inline int timer_active(unsigned int id)
00252 {
00253 if (bm_mycfg->enable_global > 0 || bm_mycfg->timers[id].enabled > 0)
00254 return 1;
00255 else
00256 return 0;
00257 }
00258
00259
00260
00261
00262
00263
00264 int _bm_start_timer(unsigned int id)
00265 {
00266 if (timer_active(id))
00267 {
00268 if(bm_get_time(bm_mycfg->tindex[id]->start)!=0)
00269 {
00270 LM_ERR("error getting current time\n");
00271 return -1;
00272 }
00273 }
00274
00275 return 1;
00276 }
00277
00278 int bm_start_timer(struct sip_msg* _msg, char* timer, char *foobar)
00279 {
00280 return _bm_start_timer((unsigned int)(unsigned long)timer);
00281 }
00282
00283
00284
00285
00286
00287
00288 int _bm_log_timer(unsigned int id)
00289 {
00290
00291 bm_timeval_t now;
00292 unsigned long long tdiff;
00293
00294 if (!timer_active(id))
00295 return 1;
00296
00297 if(bm_get_time(&now)<0)
00298 {
00299 LM_ERR("error getting current time\n");
00300 return -1;
00301 }
00302
00303 tdiff = bm_diff_time(bm_mycfg->tindex[id]->start, &now);
00304 _bm_last_time_diff = (int)tdiff;
00305
00306
00307
00308
00309
00310
00311 bm_mycfg->tindex[id]->sum += tdiff;
00312 bm_mycfg->tindex[id]->last_sum += tdiff;
00313 bm_mycfg->tindex[id]->calls++;
00314
00315 if (tdiff < bm_mycfg->tindex[id]->last_min)
00316 bm_mycfg->tindex[id]->last_min = tdiff;
00317
00318 if (tdiff > bm_mycfg->tindex[id]->last_max)
00319 bm_mycfg->tindex[id]->last_max = tdiff;
00320
00321 if (tdiff < bm_mycfg->tindex[id]->global_min)
00322 bm_mycfg->tindex[id]->global_min = tdiff;
00323
00324 if (tdiff > bm_mycfg->tindex[id]->global_max)
00325 bm_mycfg->tindex[id]->global_max = tdiff;
00326
00327
00328 if ((bm_mycfg->tindex[id]->calls % bm_mycfg->granularity) == 0)
00329 {
00330 LM_GEN1(bm_mycfg->loglevel, "benchmark (timer %s [%d]): %llu ["
00331 " msgs/total/min/max/avg - LR:"
00332 " %i/%lld/%lld/%lld/%f | GB: %lld/%lld/%lld/%lld/%f]\n",
00333 bm_mycfg->tindex[id]->name,
00334 id,
00335 tdiff,
00336 bm_mycfg->granularity,
00337 bm_mycfg->tindex[id]->last_sum,
00338 bm_mycfg->tindex[id]->last_min,
00339 bm_mycfg->tindex[id]->last_max,
00340 ((double)bm_mycfg->tindex[id]->last_sum)/bm_mycfg->granularity,
00341 bm_mycfg->tindex[id]->calls,
00342 bm_mycfg->tindex[id]->sum,
00343 bm_mycfg->tindex[id]->global_min,
00344 bm_mycfg->tindex[id]->global_max,
00345 ((double)bm_mycfg->tindex[id]->sum)/bm_mycfg->tindex[id]->calls);
00346
00347 bm_mycfg->tindex[id]->last_sum = 0;
00348 bm_mycfg->tindex[id]->last_max = 0;
00349 bm_mycfg->tindex[id]->last_min = 0xffffffff;
00350 }
00351
00352 return 1;
00353 }
00354
00355 int bm_log_timer(struct sip_msg* _msg, char* timer, char* mystr)
00356 {
00357 return _bm_log_timer((unsigned int)(unsigned long)timer);
00358 }
00359
00360 int _bm_register_timer(char *tname, int mode, unsigned int *id)
00361 {
00362 benchmark_timer_t *bmt = 0;
00363 benchmark_timer_t **tidx = 0;
00364
00365 if(tname==NULL || id==NULL || bm_mycfg==NULL || strlen(tname)==0
00366 || strlen(tname)>BM_NAME_LEN-1)
00367 return -1;
00368
00369 bmt = bm_mycfg->timers;
00370 while(bmt)
00371 {
00372 if(strcmp(bmt->name, tname)==0)
00373 {
00374 *id = bmt->id;
00375 return 0;
00376 }
00377 bmt = bmt->next;
00378 }
00379 if(mode==0)
00380 return -1;
00381
00382 bmt = (benchmark_timer_t*)shm_malloc(sizeof(benchmark_timer_t));
00383
00384 if(bmt==0)
00385 {
00386 LM_ERR("no more shm\n");
00387 return -1;
00388 }
00389 memset(bmt, 0, sizeof(benchmark_timer_t));
00390
00391
00392 bmt->start = (bm_timeval_t*)pkg_malloc(sizeof(bm_timeval_t));
00393 if(bmt->start == NULL)
00394 {
00395 shm_free(bmt);
00396 LM_ERR("no more pkg\n");
00397 return -1;
00398 }
00399 memset(bmt->start, 0, sizeof(bm_timeval_t));
00400
00401 strcpy(bmt->name, tname);
00402 if(bm_mycfg->timers==0)
00403 {
00404 bmt->id = 0;
00405 bm_mycfg->timers = bmt;
00406 } else {
00407 bmt->id = bm_mycfg->timers->id+1;
00408 bmt->next = bm_mycfg->timers;
00409 bm_mycfg->timers = bmt;
00410 }
00411
00412
00413 if(bmt->id%10==0)
00414 {
00415 if(bm_mycfg->tindex!=NULL)
00416 tidx = bm_mycfg->tindex;
00417 bm_mycfg->tindex = (benchmark_timer_t**)shm_malloc((10+bmt->id)*
00418 sizeof(benchmark_timer_t*));
00419 if(bm_mycfg->tindex==0)
00420 {
00421 LM_ERR("no more share memory\n");
00422 if(tidx!=0)
00423 shm_free(tidx);
00424 return -1;
00425 }
00426 memset(bm_mycfg->tindex, 0, (10+bmt->id)*sizeof(benchmark_timer_t*));
00427 if(tidx!=0)
00428 {
00429 memcpy(bm_mycfg->tindex, tidx, bmt->id*sizeof(benchmark_timer_t*));
00430 shm_free(tidx);
00431 }
00432 }
00433 bm_mycfg->tindex[bmt->id] = bmt;
00434 bm_mycfg->nrtimers = bmt->id + 1;
00435 bm_reset_timer(bmt->id);
00436 *id = bmt->id;
00437 LM_DBG("timer [%s] added with index <%u>\n", bmt->name, bmt->id);
00438
00439 return 0;
00440 }
00441
00442
00443 int load_bm( struct bm_binds *bmb)
00444 {
00445 if(bmb==NULL)
00446 return -1;
00447
00448 bmb->bm_register = _bm_register_timer;
00449 bmb->bm_start = _bm_start_timer;
00450 bmb->bm_log = _bm_log_timer;
00451
00452 return 1;
00453 }
00454
00455
00456 static inline char * pkg_strndup( char* _p, int _len)
00457 {
00458 char *s;
00459
00460 s = (char*)pkg_malloc(_len+1);
00461 if (s==NULL)
00462 return NULL;
00463 memcpy(s,_p,_len);
00464 s[_len] = 0;
00465 return s;
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475 struct mi_root* mi_bm_enable_global(struct mi_root *cmd, void *param)
00476 {
00477 struct mi_node *node;
00478
00479 char *p1, *e1;
00480 long int v1;
00481
00482 node = cmd->node.kids;
00483
00484 if ((node == NULL) || (node->next != NULL))
00485 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00486
00487 p1 = pkg_strndup(node->value.s, node->value.len);
00488
00489 v1 = strtol(p1, &e1, 0);
00490
00491 if ((*e1 != '\0') || (*p1 == '\0')) {
00492 pkg_free(p1);
00493 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00494 }
00495
00496 if ((v1 < -1) || (v1 > 1)) {
00497 pkg_free(p1);
00498 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00499 }
00500
00501 bm_mycfg->enable_global = v1;
00502
00503 pkg_free(p1);
00504 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00505 }
00506
00507 struct mi_root* mi_bm_enable_timer(struct mi_root *cmd, void *param)
00508 {
00509 struct mi_node *node;
00510
00511 char *p1, *p2, *e2;
00512 long int v2;
00513 unsigned int id;
00514
00515 node = cmd->node.kids;
00516
00517 if ((node == NULL) || (node->next == NULL) || (node->next->next != NULL))
00518 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00519
00520 p1 = pkg_strndup(node->value.s, node->value.len);
00521
00522 if(_bm_register_timer(p1, 0, &id)!=0)
00523 {
00524 pkg_free(p1);
00525 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00526 }
00527 p2 = pkg_strndup(node->next->value.s, node->next->value.len);
00528 v2 = strtol(p2, &e2, 0);
00529
00530 pkg_free(p1);
00531 pkg_free(p2);
00532
00533 if (*e2 != '\0' || *p2 == '\0')
00534 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00535
00536 if ((v2 < 0) || (v2 > 1))
00537 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00538
00539 bm_mycfg->timers[id].enabled = v2;
00540
00541 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00542 }
00543
00544 struct mi_root* mi_bm_granularity(struct mi_root *cmd, void *param)
00545 {
00546 struct mi_node *node;
00547
00548 char *p1, *e1;
00549 long int v1;
00550
00551 node = cmd->node.kids;
00552
00553 if ((node == NULL) || (node->next != NULL))
00554 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00555
00556 p1 = pkg_strndup(node->value.s, node->value.len);
00557
00558 v1 = strtol(p1, &e1, 0);
00559
00560 pkg_free(p1);
00561
00562 if ((*e1 != '\0') || (*p1 == '\0'))
00563 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00564
00565 if (v1 < 1)
00566 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00567
00568 bm_mycfg->granularity = v1;
00569
00570 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00571 }
00572
00573 struct mi_root* mi_bm_loglevel(struct mi_root *cmd, void *param)
00574 {
00575 struct mi_node *node;
00576
00577 char *p1, *e1;
00578 long int v1;
00579
00580 node = cmd->node.kids;
00581
00582 if ((node == NULL) || (node->next != NULL))
00583 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00584
00585 p1 = pkg_strndup(node->value.s, node->value.len);
00586
00587 v1 = strtol(p1, &e1, 0);
00588
00589 pkg_free(p1);
00590
00591 if ((*e1 != '\0') || (*p1 == '\0'))
00592 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00593
00594 if ((v1 < -3) || (v1 > 4))
00595 return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
00596
00597 bm_mycfg->enable_global = v1;
00598
00599 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00600 }
00601
00602
00603
00604 static int bm_get_time_diff(struct sip_msg *msg, pv_param_t *param,
00605 pv_value_t *res)
00606 {
00607 if(msg==NULL)
00608 return -1;
00609 return pv_get_sintval(msg, param, res, _bm_last_time_diff);
00610 }
00611
00612
00613 static inline int fixup_bm_timer(void** param, int param_no)
00614 {
00615 unsigned int tid = 0;
00616 if (param_no == 1)
00617 {
00618 if((_bm_register_timer((char*)(*param), 1, &tid))!=0)
00619 {
00620 LM_ERR("cannot register timer [%s]\n", (char*)(*param));
00621 return E_UNSPEC;
00622 }
00623 pkg_free(*param);
00624 *param = (void*)(unsigned long)tid;
00625 }
00626 return 0;
00627 }
00628
00629