00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00023
00024
00025
00026
00027
00028
00029
00030 #include "counters.h"
00031 #include "str_hash.h"
00032 #include "str.h"
00033 #include "compiler_opt.h"
00034 #include "mem/mem.h"
00035 #include "mem/shm_mem.h"
00036
00037
00038 #define CNT_HASH_SIZE 64
00039
00040 #define GRP_HASH_SIZE 16
00041
00042 #define GRP_SORTED_SIZE 16
00043
00044 #define CNT_ID2RECORD_SIZE 64
00045
00046 #define CACHELINE_PAD 128
00047
00048
00049
00050
00051 #define MAX_COUNTER_ID 32767
00052
00053
00054
00055
00056 #define PREINIT_CNTS_VALS_SIZE 128
00057
00058 struct counter_record {
00059 str group;
00060 str name;
00061 counter_handle_t h;
00062 unsigned short flags;
00063 void* cbk_param;
00064 counter_cbk_f cbk;
00065 struct counter_record* grp_next;
00066 str doc;
00067 };
00068
00069
00070 struct grp_record {
00071 str group;
00072 struct counter_record* first;
00073 };
00074
00075
00076
00078 static struct str_hash_table cnts_hash_table;
00080 struct counter_record** cnt_id2record;
00081 static int cnt_id2record_size;
00083 static struct str_hash_table grp_hash_table;
00085 static struct grp_record** grp_sorted;
00086 static int grp_sorted_max_size;
00087 static int grp_sorted_crt_size;
00088 static int grp_no;
00089
00092 counter_array_t* _cnts_vals;
00093 int _cnts_row_len;
00094 static int cnts_no;
00095 static int cnts_max_rows;
00096
00097
00098
00102 int init_counters()
00103 {
00104 if (str_hash_alloc(&cnts_hash_table, CNT_HASH_SIZE) < 0)
00105 goto error;
00106 str_hash_init(&cnts_hash_table);
00107 if (str_hash_alloc(&grp_hash_table, GRP_HASH_SIZE) < 0)
00108 goto error;
00109 str_hash_init(&grp_hash_table);
00110 cnts_no = 1;
00111 cnts_max_rows = 0;
00112
00113 grp_no = 0;
00114 cnt_id2record_size = CNT_ID2RECORD_SIZE;
00115 cnt_id2record = pkg_malloc(sizeof(*cnt_id2record) * cnt_id2record_size);
00116 if (cnt_id2record == 0)
00117 goto error;
00118 memset(cnt_id2record, 0, sizeof(*cnt_id2record) * cnt_id2record_size);
00119 grp_sorted_max_size = GRP_SORTED_SIZE;
00120 grp_sorted_crt_size = 0;
00121 grp_sorted = pkg_malloc(sizeof(*grp_sorted) * grp_sorted_max_size);
00122 if (grp_sorted == 0)
00123 goto error;
00124 memset(grp_sorted, 0, sizeof(*grp_sorted) * grp_sorted_max_size);
00125 return 0;
00126 error:
00127 destroy_counters();
00128 return -1;
00129 }
00130
00131
00132
00133 void destroy_counters()
00134 {
00135 int r;
00136 struct str_hash_entry* e;
00137 struct str_hash_entry* bak;
00138 if (_cnts_vals) {
00139 if (cnts_max_rows)
00140
00141 shm_free(_cnts_vals);
00142 else
00143
00144 pkg_free(_cnts_vals);
00145 _cnts_vals = 0;
00146 }
00147 if (cnts_hash_table.table) {
00148 for (r=0; r< cnts_hash_table.size; r++) {
00149 clist_foreach_safe(&cnts_hash_table.table[r], e, bak, next) {
00150 pkg_free(e);
00151 }
00152 }
00153 pkg_free(cnts_hash_table.table);
00154 }
00155 if (grp_hash_table.table) {
00156 for (r=0; r< grp_hash_table.size; r++) {
00157 clist_foreach_safe(&grp_hash_table.table[r], e, bak, next) {
00158 pkg_free(e);
00159 }
00160 }
00161 pkg_free(grp_hash_table.table);
00162 }
00163 if (cnt_id2record)
00164 pkg_free(cnt_id2record);
00165 if (grp_sorted)
00166 pkg_free(grp_sorted);
00167 cnts_hash_table.table = 0;
00168 cnts_hash_table.size = 0;
00169 cnt_id2record = 0;
00170 grp_sorted = 0;
00171 grp_hash_table.table = 0;
00172 grp_hash_table.size = 0;
00173 grp_sorted_crt_size = 0;
00174 grp_sorted_max_size = 0;
00175 cnts_no = 0;
00176 _cnts_row_len = 0;
00177 cnts_max_rows = 0;
00178 grp_no = 0;
00179 }
00180
00181
00182
00187 int counters_prefork_init(int max_process_no)
00188 {
00189 counter_array_t* old;
00190 int size, row_size;
00191 counter_handle_t h;
00192
00193
00194
00195 row_size = ((sizeof(*_cnts_vals) * cnts_no - 1) / CACHELINE_PAD + 1) *
00196 CACHELINE_PAD;
00197
00198 row_size = ((row_size -1) / sizeof(*_cnts_vals) + 1) *
00199 sizeof(*_cnts_vals);
00200
00201 _cnts_row_len = row_size / sizeof(*_cnts_vals);
00202 size = max_process_no * row_size;
00203
00204
00205 old = _cnts_vals;
00206 _cnts_vals = shm_malloc(size);
00207 if (_cnts_vals == 0)
00208 return -1;
00209 memset(_cnts_vals, 0, size);
00210 cnts_max_rows = max_process_no;
00211
00212 if (old) {
00213 for (h.id = 0; h.id < cnts_no; h.id++)
00214 counter_pprocess_val(process_no, h) = old[h.id].v;
00215 pkg_free(old);
00216 }
00217 return 0;
00218 }
00219
00220
00221
00225 static struct grp_record* grp_hash_add(str* group)
00226 {
00227 struct str_hash_entry* g;
00228 struct grp_record* grp_rec;
00229 struct grp_record** r;
00230
00231
00232 g = pkg_malloc(sizeof(struct str_hash_entry) - sizeof(g->u.data) +
00233 sizeof(*grp_rec) + group->len + 1);
00234 if (g == 0)
00235 goto error;
00236 grp_rec = (struct grp_record*)&g->u.data[0];
00237 grp_rec->group.s = (char*)(grp_rec + 1);
00238 grp_rec->group.len = group->len;
00239 grp_rec->first = 0;
00240 memcpy(grp_rec->group.s, group->s, group->len + 1);
00241 g->key = grp_rec->group;
00242 g->flags = 0;
00243
00244 if (grp_sorted_max_size <= grp_sorted_crt_size) {
00245
00246 r = pkg_realloc(grp_sorted, 2 * grp_sorted_max_size *
00247 sizeof(*grp_sorted));
00248 if (r == 0)
00249 goto error;
00250 grp_sorted= r;
00251 grp_sorted_max_size *= 2;
00252 memset(&grp_sorted[grp_sorted_crt_size], 0,
00253 (grp_sorted_max_size - grp_sorted_crt_size) *
00254 sizeof(*grp_sorted));
00255 }
00256 for (r = grp_sorted; r < (grp_sorted + grp_sorted_crt_size); r++)
00257 if (strcmp(grp_rec->group.s, (*r)->group.s) < 0)
00258 break;
00259 if (r != (grp_sorted + grp_sorted_crt_size))
00260 memmove(r+1, r, (int)(long)((char*)(grp_sorted + grp_sorted_crt_size) -
00261 (char*)r));
00262 grp_sorted_crt_size++;
00263 *r = grp_rec;
00264
00265 str_hash_add(&grp_hash_table, g);
00266 return grp_rec;
00267 error:
00268 if (g)
00269 pkg_free(g);
00270 return 0;
00271 }
00272
00273
00274
00278 static struct grp_record* grp_hash_lookup(str* group)
00279 {
00280 struct str_hash_entry* e;
00281 e = str_hash_get(&grp_hash_table, group->s, group->len);
00282 return e?(struct grp_record*)&e->u.data[0]:0;
00283 }
00284
00285
00286
00291 static struct grp_record* grp_hash_get_create(str* group)
00292 {
00293 struct grp_record* ret;
00294
00295 ret = grp_hash_lookup(group);
00296 if (ret)
00297 return ret;
00298 return grp_hash_add(group);
00299 }
00300
00301
00302
00306 static struct counter_record* cnt_hash_add(
00307 str* group, str* name,
00308 int flags, counter_cbk_f cbk,
00309 void* param, const char* doc)
00310 {
00311 struct str_hash_entry* e;
00312 struct counter_record* cnt_rec;
00313 struct grp_record* grp_rec;
00314 struct counter_record** p;
00315 counter_array_t* v;
00316 int doc_len;
00317 int n;
00318
00319 e = 0;
00320 if (cnts_no >= MAX_COUNTER_ID)
00321
00322 goto error;
00323 grp_rec = grp_hash_get_create(group);
00324 if (grp_rec == 0)
00325
00326 goto error;
00327 doc_len = doc?strlen(doc):0;
00328
00329 e = pkg_malloc(sizeof(struct str_hash_entry) - sizeof(e->u.data) +
00330 sizeof(*cnt_rec) + name->len + 1 + group->len + 1 +
00331 doc_len + 1);
00332 if (e == 0)
00333 goto error;
00334 cnt_rec = (struct counter_record*)&e->u.data[0];
00335 cnt_rec->group.s = (char*)(cnt_rec + 1);
00336 cnt_rec->group.len = group->len;
00337 cnt_rec->name.s = cnt_rec->group.s + group->len + 1;
00338 cnt_rec->name.len = name->len;
00339 cnt_rec->doc.s = cnt_rec->name.s + name->len +1;
00340 cnt_rec->doc.len = doc_len;
00341 cnt_rec->h.id = cnts_no++;
00342 cnt_rec->flags = flags;
00343 cnt_rec->cbk_param = param;
00344 cnt_rec->cbk = cbk;
00345 cnt_rec->grp_next = 0;
00346 memcpy(cnt_rec->group.s, group->s, group->len + 1);
00347 memcpy(cnt_rec->name.s, name->s, name->len + 1);
00348 if (doc)
00349 memcpy(cnt_rec->doc.s, doc, doc_len + 1);
00350 else
00351 cnt_rec->doc.s[0] = 0;
00352 e->key = cnt_rec->name;
00353 e->flags = 0;
00354
00355
00356
00357
00358
00359 if (cnt_rec->h.id >= _cnts_row_len || _cnts_vals == 0) {
00360
00361
00362
00363 n = (cnt_rec->h.id < PREINIT_CNTS_VALS_SIZE) ?
00364 PREINIT_CNTS_VALS_SIZE :
00365 ((2 * (cnt_rec->h.id + (cnt_rec->h.id == 0)) < MAX_COUNTER_ID)?
00366 (2 * (cnt_rec->h.id + (cnt_rec->h.id == 0))) :
00367 MAX_COUNTER_ID + 1);
00368 v = pkg_realloc(_cnts_vals, n * sizeof(*_cnts_vals));
00369 if (v == 0)
00370
00371 goto error;
00372 _cnts_vals = v;
00373
00374 memset(&_cnts_vals[_cnts_row_len], 0,
00375 (n - _cnts_row_len) * sizeof(*_cnts_vals));
00376 _cnts_row_len = n;
00377 }
00378
00379 if (cnt_id2record_size <= cnt_rec->h.id) {
00380
00381 p = pkg_realloc(cnt_id2record,
00382 2 * cnt_id2record_size * sizeof(*cnt_id2record));
00383 if (p == 0)
00384 goto error;
00385 cnt_id2record = p;
00386 cnt_id2record_size *= 2;
00387 memset(&cnt_id2record[cnt_rec->h.id], 0,
00388 (cnt_id2record_size - cnt_rec->h.id) * sizeof(*cnt_id2record));
00389 }
00390 cnt_id2record[cnt_rec->h.id] = cnt_rec;
00391
00392 str_hash_add(&cnts_hash_table, e);
00393
00394 for (p = &grp_rec->first; *p; p = &((*p)->grp_next))
00395 if (strcmp(cnt_rec->name.s, (*p)->name.s) < 0)
00396 break;
00397 cnt_rec->grp_next = *p;
00398 *p = cnt_rec;
00399 return cnt_rec;
00400 error:
00401 if (e)
00402 pkg_free(e);
00403 return 0;
00404 }
00405
00406
00407
00414 static struct counter_record* cnt_hash_lookup(str* group, str* name)
00415 {
00416 struct str_hash_entry* e;
00417 struct str_hash_entry* first;
00418 struct counter_record* cnt_rec;
00419 e = str_hash_get(&cnts_hash_table, name->s, name->len);
00420
00421 if (likely(e)) {
00422 cnt_rec = (struct counter_record*)&e->u.data[0];
00423 if (likely( group->len == 0 ||
00424 (cnt_rec->group.len == group->len &&
00425 memcmp(cnt_rec->group.s, group->s, group->len) == 0)))
00426 return cnt_rec;
00427 } else
00428 return 0;
00429
00430 first = e;
00431 do {
00432 cnt_rec = (struct counter_record*)&e->u.data[0];
00433 if (cnt_rec->group.len == group->len &&
00434 cnt_rec->name.len == name->len &&
00435 memcmp(cnt_rec->group.s, group->s, group->len) == 0 &&
00436 memcmp(cnt_rec->name.s, name->s, name->len) == 0)
00437
00438 return cnt_rec;
00439 e = e->next;
00440 } while(e != first);
00441 return 0;
00442 }
00443
00444
00445
00450 static struct counter_record* cnt_hash_get_create(
00451 str* group, str* name,
00452 int flags,
00453 counter_cbk_f cbk,
00454 void* param, const char* doc)
00455 {
00456 struct counter_record* ret;
00457
00458 ret = cnt_hash_lookup(group, name);
00459 if (ret)
00460 return ret;
00461 return cnt_hash_add(group, name, flags, cbk, param, doc);
00462 }
00463
00464
00465
00483 int counter_register( counter_handle_t* handle, const char* group,
00484 const char* name, int flags,
00485 counter_cbk_f cbk, void* cbk_param,
00486 const char* doc,
00487 int reg_flags)
00488 {
00489 str grp;
00490 str n;
00491 struct counter_record* cnt_rec;
00492
00493 if (unlikely(cnts_max_rows)) {
00494
00495 BUG("late attempt to register counter: %s.%s\n", group, name);
00496 goto error;
00497 }
00498 n.s = (char*)name;
00499 n.len = strlen(name);
00500 if (unlikely(group == 0 || *group == 0)) {
00501 BUG("attempt to register counter %s without a group\n", name);
00502 goto error;
00503 }
00504 grp.s = (char*)group;
00505 grp.len = strlen(group);
00506 cnt_rec = cnt_hash_lookup(&grp, &n);
00507 if (cnt_rec) {
00508 if (reg_flags & 1)
00509 goto found;
00510 else {
00511 if (handle) handle->id = 0;
00512 return -2;
00513 }
00514 } else
00515 cnt_rec = cnt_hash_get_create(&grp, &n, flags, cbk, cbk_param, doc);
00516 if (unlikely(cnt_rec == 0))
00517 goto error;
00518 found:
00519 if (handle) *handle = cnt_rec->h;
00520 return 0;
00521 error:
00522 if (handle) handle->id = 0;
00523 return -1;
00524 }
00525
00526
00527
00536 int counter_lookup_str(counter_handle_t* handle, str* group, str* name)
00537 {
00538 struct counter_record* cnt_rec;
00539
00540 cnt_rec = cnt_hash_lookup(group, name);
00541 if (likely(cnt_rec)) {
00542 *handle = cnt_rec->h;
00543 return 0;
00544 }
00545 handle->id = 0;
00546 return -1;
00547 }
00548
00549
00550
00559 int counter_lookup(counter_handle_t* handle,
00560 const char* group, const char* name)
00561 {
00562 str grp;
00563 str n;
00564
00565 n.s = (char*)name;
00566 n.len = strlen(name);
00567 grp.s = (char*)group;
00568 grp.len = group?strlen(group):0;
00569 return counter_lookup_str(handle, &grp, &n);
00570 }
00571
00572
00573
00579 int counter_register_array(const char* group, counter_def_t* defs)
00580 {
00581 int r;
00582
00583 for (r=0; defs[r].name; r++)
00584 if (counter_register( defs[r].handle,
00585 group, defs[r].name, defs[r].flags,
00586 defs[r].get_cbk, defs[r].get_cbk_param,
00587 defs[r].descr, 0) <0)
00588 return -(r+1);
00589 return 0;
00590 }
00591
00592
00593
00599 counter_val_t counter_get_raw_val(counter_handle_t handle)
00600 {
00601 int r;
00602 counter_val_t ret;
00603
00604 if (unlikely(_cnts_vals == 0)) {
00605
00606 BUG("counters not fully initialized yet\n");
00607 return 0;
00608 }
00609 if (unlikely(handle.id >= cnts_no || (short)handle.id < 0)) {
00610 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00611 return 0;
00612 }
00613 ret = 0;
00614 for (r = 0; r < cnts_max_rows; r++)
00615 ret += counter_pprocess_val(r, handle);
00616 return ret;
00617 }
00618
00619
00620
00625 counter_val_t counter_get_val(counter_handle_t handle)
00626 {
00627 struct counter_record* cnt_rec;
00628
00629 if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00630
00631 BUG("counters not fully initialized yet\n");
00632 return 0;
00633 }
00634 cnt_rec = cnt_id2record[handle.id];
00635 if (unlikely(cnt_rec->cbk))
00636 return cnt_rec->cbk(handle, cnt_rec->cbk_param);
00637 return counter_get_raw_val(handle);
00638 }
00639
00640
00641
00648 void counter_reset(counter_handle_t handle)
00649 {
00650 int r;
00651
00652 if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00653
00654 BUG("counters not fully initialized yet\n");
00655 return;
00656 }
00657 if (unlikely(handle.id >= cnts_no)) {
00658 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00659 return;
00660 }
00661 if (unlikely(cnt_id2record[handle.id]->flags & CNT_F_NO_RESET))
00662 return;
00663 for (r=0; r < cnts_max_rows; r++)
00664 counter_pprocess_val(r, handle) = 0;
00665 return;
00666 }
00667
00668
00669
00675 char* counter_get_name(counter_handle_t handle)
00676 {
00677 if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00678
00679 BUG("counters not fully initialized yet\n");
00680 goto error;
00681 }
00682 if (unlikely(handle.id >= cnts_no)) {
00683 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00684 goto error;
00685 }
00686 return cnt_id2record[handle.id]->name.s;
00687 error:
00688 return 0;
00689 }
00690
00691
00692
00698 char* counter_get_group(counter_handle_t handle)
00699 {
00700 if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00701
00702 BUG("counters not fully initialized yet\n");
00703 goto error;
00704 }
00705 if (unlikely(handle.id >= cnts_no)) {
00706 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00707 goto error;
00708 }
00709 return cnt_id2record[handle.id]->group.s;
00710 error:
00711 return 0;
00712 }
00713
00714
00715
00721 char* counter_get_doc(counter_handle_t handle)
00722 {
00723 if (unlikely(_cnts_vals == 0 || cnt_id2record == 0)) {
00724
00725 BUG("counters not fully initialized yet\n");
00726 goto error;
00727 }
00728 if (unlikely(handle.id >= cnts_no)) {
00729 BUG("invalid counter id %d (max %d)\n", handle.id, cnts_no - 1);
00730 goto error;
00731 }
00732 return cnt_id2record[handle.id]->doc.s;
00733 error:
00734 return 0;
00735 }
00736
00737
00738
00745 void counter_iterate_grp_names(void (*cbk)(void* p, str* grp_name), void* p)
00746 {
00747 int r;
00748
00749 for (r=0; r < grp_sorted_crt_size; r++)
00750 cbk(p, &grp_sorted[r]->group);
00751 }
00752
00753
00754
00762 void counter_iterate_grp_var_names( const char* group,
00763 void (*cbk)(void* p, str* var_name),
00764 void* p)
00765 {
00766 struct counter_record* r;
00767 struct grp_record* g;
00768 str grp;
00769
00770 grp.s = (char*)group;
00771 grp.len = strlen(group);
00772 g = grp_hash_lookup(&grp);
00773 if (g)
00774 for (r = g->first; r; r = r->grp_next)
00775 cbk(p, &r->name);
00776 }
00777
00778
00779
00787 void counter_iterate_grp_vars(const char* group,
00788 void (*cbk)(void* p, str* g, str* n,
00789 counter_handle_t h),
00790 void *p)
00791 {
00792 struct counter_record* r;
00793 struct grp_record* g;
00794 str grp;
00795
00796 grp.s = (char*)group;
00797 grp.len = strlen(group);
00798 g = grp_hash_lookup(&grp);
00799 if (g)
00800 for (r = g->first; r; r = r->grp_next)
00801 cbk(p, &r->group, &r->name, r->h);
00802 }
00803
00804