00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014 #include <float.h>
00015
00016 #include "histogram.h"
00017
00018
00019 CLASS* histogram::oclass = NULL;
00020 CLASS* histogram::pclass = NULL;
00021 histogram *histogram::defaults = NULL;
00022
00024
00026
00027 void new_histogram(MODULE *mod){
00028 new histogram(mod);
00029 }
00030
00031 histogram::histogram(MODULE *mod)
00032 {
00033 if(oclass == NULL)
00034 {
00035 #ifdef _DEBUG
00036 gl_debug("construction histogram class");
00037 #endif
00038 oclass = gl_register_class(mod,"histogram",sizeof(histogram), PC_PRETOPDOWN);
00039 if(oclass == NULL)
00040 GL_THROW("unable to register object class implemented by %s",__FILE__);
00041
00042 if(gl_publish_variable(oclass,
00043 PT_char1024, "filename", PADDR(filename),
00044 PT_char1024, "group", PADDR(group),
00045 PT_char1024, "bins", PADDR(bins),
00046 PT_char32, "property", PADDR(property),
00047 PT_double, "min", PADDR(min),
00048 PT_double, "max", PADDR(max),
00049 PT_double, "samplerate[s]", PADDR(sampling_interval),
00050 PT_double, "countrate[s]", PADDR(counting_interval),
00051 PT_int32, "bin_count", PADDR(bin_count),
00052 PT_int32, "limit", PADDR(limit),
00053 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00054 defaults = this;
00055 memset(filename, 0, 1025);
00056 memset(group, 0, 1025);
00057 memset(bins, 0, 1025);
00058 memset(property, 0, 33);
00059 min = 0;
00060 max = -1;
00061 bin_count = -1;
00062 sampling_interval = -1.0;
00063 counting_interval = -1.0;
00064 limit = 0;
00065 bin_list = NULL;
00066 group_list = NULL;
00067 binctr = NULL;
00068 prop_ptr = NULL;
00069 next_count = t_count = next_sample = t_sample = TS_ZERO;
00070 flags[0]='w';
00071 }
00072 }
00073
00074 int histogram::create()
00075 {
00076 memcpy(this, defaults, sizeof(histogram));
00077 return 1;
00078 }
00079
00080
00081
00082 void eat_white(char **pos){
00083 while(**pos == ' ' || **pos == '\t')
00084 ++(*pos);
00085 }
00086
00091 int parse_bin_val(char *tok, BIN *bin){
00092 char *pos = tok;
00093 int low_set = 0, high_set = 0;
00094
00095 eat_white(&pos);
00096
00097
00098 if(pos[0] == '['){
00099 ++pos;
00100 bin->low_inc = 1;
00101 } else if (pos[0] == '('){
00102 ++pos;
00103 bin->low_inc = 0;
00104 } else {
00105 bin->low_inc = 1;
00106 }
00107
00108
00109 eat_white(&pos);
00110
00111
00112 if(isdigit(*pos)){
00113 bin->low_val = strtod(pos, &pos);
00114 low_set = 1;
00115 } else if(*pos == '.' && pos[1] == '.'){
00116 bin->low_val = -DBL_MAX;
00117 bin->low_inc = 0;
00118 } else if(*pos == '-') {
00119 bin->low_val = -DBL_MAX;
00120 bin->low_inc = 0;
00121
00122 }
00123
00124 eat_white(&pos);
00125
00126 if(*pos == '.' && pos[1] == '.'){
00127 pos+=2;
00128 } else if (*pos == '-'){
00129 ++pos;
00130 } else {
00131 gl_error("parse_bin failure");
00132 return 0;
00133 }
00134
00135 eat_white(&pos);
00136
00137 if(isdigit(*pos)){
00138 bin->high_val = strtod(pos, &pos);
00139 high_set = 1;
00140 if(low_set == 0)
00141 bin->high_inc = 1;
00142 } else {
00143 bin->high_val = DBL_MAX;
00144 }
00145
00146 if(*pos == 0 || *pos == '\n' || *pos == ','){
00147 return 1;
00148 } else if (*pos == ')'){
00149 bin->high_inc = 0;
00150 return 1;
00151 } else if (*pos == ']'){
00152 bin->high_inc = 1;
00153 return 1;
00154 }
00155 return 0;
00156 }
00157
00158 int parse_bin_enum(char *cptr, BIN *bin, PROPERTY *prop){
00159
00160 char *pos = cptr;
00161 KEYWORD *kw = NULL;
00162
00163 if(prop->keywords == NULL){
00164 gl_error("parse_bin_enum error: property has no keywords");
00165 return 0;
00166 }
00167
00168 eat_white(&pos);
00169
00170 for(kw = prop->keywords; kw != NULL; kw = kw->next){
00171 if(strcmp(kw->name, pos) == 0){
00172 bin->low_inc = bin->high_inc = 1;
00173 bin->low_val = bin->high_val = kw->value;
00174 return 1;
00175 }
00176 }
00177
00178 gl_error("parse_bin_enum error: unable to find property \'%s\'", pos);
00179 return 0;
00180 }
00181
00188 void histogram::test_for_complex(char *tprop, char *tpart){
00189 if(sscanf(property, "%[^.\0\t\n].%s", tprop, tpart) == 2){
00190 if(0 == memcmp(tpart, "real", 4)){comp_part = REAL;}
00191 else if(0 == memcmp(tpart, "imag", 3)){comp_part = IMAG;}
00192 else if(0 == memcmp(tpart, "mag", 3)){comp_part = MAG;}
00193 else if(0 == memcmp(tpart, "ang", 3)){comp_part = ANG;}
00194 else {
00195 comp_part = NONE;
00196 throw("Unable to resolve complex part for \'%s\'", property);
00197 return;
00198 }
00199 strtok(property, ".");
00200 }
00201 }
00202
00209 int histogram::init(OBJECT *parent)
00210 {
00211 PROPERTY *prop = NULL;
00212 OBJECT *obj = OBJECTHDR(this);
00213 char tprop[64], tpart[8];
00214 int e = 0;
00215 tprop[0]=0;
00216 tpart[0] = 0;
00217
00218 if(parent == NULL)
00219 {
00220 OBJECT *group_obj = NULL;
00221 CLASS *oclass = NULL;
00222 if(group[0] == 0){
00223 throw("Histogram has no parent and no group");
00224 return 0;
00225 }
00226 group_list = gl_find_objects(FL_GROUP,group);
00227 if(group_list == NULL){
00228 throw("Histogram group could not be parsed");
00229 return 0;
00230 }
00231 if(group_list->hit_count < 1){
00232 throw("Histogram group is an empty set");
00233 return 0;
00234 }
00235
00236
00237
00238 test_for_complex(tprop, tpart);
00239
00240 while(group_obj = gl_find_next(group_list, group_obj)){
00241 prop = gl_find_property(group_obj->oclass, property);
00242 if(prop == NULL){
00243 throw("Histogram group is unable to find prop '%s' in class '%d' for group '%s'", property, group_obj->oclass->name, group);
00244 return 0;
00245 }
00246
00247 if (oclass == NULL){
00248 oclass = group_obj->oclass;
00249 prop_ptr = prop;
00250 }
00251 if(oclass != group_obj->oclass){
00252 prop_ptr = NULL;
00253 }
00254
00255 }
00256 } else {
00257 test_for_complex(tprop, tpart);
00258
00259 prop = gl_find_property(parent->oclass, property);
00260
00261 if(prop == NULL){
00262 throw("Histogram parent '%s' of class '%s' does not contain property '%s'", parent->name ? parent->name : "(anon)", parent->oclass->name, property);
00263 return 0;
00264 } else {
00265 prop_ptr = prop;
00266 }
00267 }
00268
00269
00270
00271 if((bin_count > 0) && (min < max))
00272 {
00273 int i=0;
00274 double range = max - min;
00275 double step = range/bin_count;
00276
00277 bin_list = (BIN *)gl_malloc(sizeof(BIN) * bin_count);
00278 if(bin_list == NULL){
00279 throw("Histogram malloc error: unable to alloc %i * %i bytes for %s", bin_count, sizeof(BIN), obj->name ? obj->name : "(anon. histogram)");
00280 return 0;
00281 }
00282 memset(bin_list, 0, sizeof(BIN) * bin_count);
00283 for(i = 0; i < bin_count; i++){
00284 bin_list[i].low_val = min + i * step;
00285 bin_list[i].high_val = bin_list[i].low_val + step;
00286 bin_list[i].low_inc = 1;
00287 bin_list[i].high_inc = 0;
00288 }
00289 bin_list[i-1].high_inc = 1;
00290 binctr = (int *)gl_malloc(sizeof(int) * bin_count);
00291 memset(binctr, 0, sizeof(int) * bin_count);
00292 }
00293 else if (bins[0] != 0)
00294
00295
00296
00297
00298 {
00299 char *cptr = bins;
00300 char1024 bincpy;
00301 int i = 0;
00302 bin_count = 1;
00303
00304
00305 for(cptr = bins; *cptr != 0; ++cptr){
00306 if(*cptr == ',' && cptr[1] != 0){
00307 ++bin_count;
00308 }
00309
00310 }
00311 bin_list = (BIN *)gl_malloc(sizeof(BIN) * bin_count);
00312 if(bin_list == NULL){
00313 throw("Histogram malloc error: unable to alloc %i * %i bytes for %s", bin_count, sizeof(BIN), obj->name ? obj->name : "(anon. histogram)");
00314 return 0;
00315 }
00316 memset(bin_list, 0, sizeof(BIN) * bin_count);
00317 memcpy(bincpy, bins, 1024);
00318 cptr = strtok(bincpy, ",\t\r\n\0");
00319 if(prop->ptype == PT_complex || prop->ptype == PT_double || prop->ptype == PT_int16 || prop->ptype == PT_int32 || prop->ptype == PT_int64 || prop->ptype == PT_float || prop->ptype == PT_real){
00320 for(i = 0; i < bin_count && cptr != NULL; ++i){
00321 if(parse_bin_val(cptr, bin_list+i) == 0){
00322 throw("Histogram unable to parse \'%s\' in %s", cptr, obj->name ? obj->name : "(unnamed histogram)");
00323 }
00324 cptr = strtok(NULL, ",\t\r\n\0");
00325 }
00326 } else if (prop->ptype == PT_enumeration || prop->ptype == PT_set){
00327 for(i = 0; i < bin_count && cptr != NULL; ++i){
00328 if(parse_bin_enum(cptr, bin_list+i, prop) == 0){
00329 throw("Histogram unable to parse \'%s\' in %s", cptr, obj->name ? obj->name : "(unnamed histogram)");
00330 }
00331 cptr = strtok(NULL, ",\t\r\n\0");
00332 }
00333 }
00334
00335 if(i < bin_count){
00336 throw("Histrogram encountered a problem parsing bins for %s", obj->name ? obj->name : "(unnamed histogram)");
00337 }
00338 binctr = (int *)malloc(sizeof(int) * bin_count);
00339 memset(binctr, 0, sizeof(int) * bin_count);
00340 } else {
00341 gl_error("Histogram has neither bins or a bin range to work with");
00342 return 0;
00343 }
00344
00345
00346
00347 if (sscanf(filename,"%32[^:]:%1024[^:]:%[^:]",ftype,fname,flags)==1)
00348 {
00349
00350 strcpy(fname,filename);
00351 strcpy(ftype,"file");
00352 }
00353
00354
00355 if (strcmp(fname,"")==0)
00356
00357
00358 sprintf(fname,"%s-%d.%s",obj->parent->oclass->name,obj->parent->id, ftype);
00359
00360
00361 ops = get_ftable(ftype)->histogram;
00362 if(ops == NULL)
00363 return 0;
00364 return ops->open(this, fname, flags);
00365 }
00366
00367 int histogram::feed_bins(OBJECT *obj){
00368 double value = 0.0;
00369 complex cval = 0.0;
00370 int64 ival = 0;
00371 int i = 0;
00372
00373 switch(prop_ptr->ptype){
00374 case PT_complex:
00375 cval = (prop_ptr ? *gl_get_complex(obj, prop_ptr) : *gl_get_complex_by_name(obj, property) );
00376 switch(this->comp_part){
00377 case REAL:
00378 value = cval.Re();
00379 break;
00380 case IMAG:
00381 value = cval.Im();
00382 break;
00383 case MAG:
00384 value = cval.Mag();
00385 break;
00386 case ANG:
00387 value = cval.Arg();
00388 break;
00389 default:
00390 gl_error("Complex property with no part defined in %s", (obj->name ? obj->name : "(unnamed)"));
00391 }
00392 ival = 1;
00393
00394 case PT_double:
00395 if(ival == 0)
00396 value = (prop_ptr ? *gl_get_double(obj, prop_ptr) : *gl_get_double_by_name(obj, property) );
00397 for(i = 0; i < bin_count; ++i){
00398 if(value > bin_list[i].low_val && value < bin_list[i].high_val){
00399 ++binctr[i];
00400 } else if(bin_list[i].low_inc && bin_list[i].low_val == value){
00401 ++binctr[i];
00402 } else if(bin_list[i].high_inc && bin_list[i].high_val == value){
00403 ++binctr[i];
00404 }
00405 }
00406 break;
00407 case PT_int16:
00408 ival = (prop_ptr ? *gl_get_int16(obj, prop_ptr) : *gl_get_int16_by_name(obj, property) );
00409 value = 1.0;
00410 case PT_int32:
00411 if(value == 0.0){
00412 ival = (prop_ptr ? *gl_get_int32(obj, prop_ptr) : *gl_get_int32_by_name(obj, property) );
00413 value = 1.0;
00414 }
00415 case PT_int64:
00416 if(value == 0.0){
00417 ival = (prop_ptr ? *gl_get_int64(obj, prop_ptr) : *gl_get_int64_by_name(obj, property) );
00418 value = 1.0;
00419 }
00420 case PT_enumeration:
00421 if(value == 0.0){
00422 ival = (prop_ptr ? *gl_get_int64(obj, prop_ptr) : *gl_get_int64_by_name(obj, property) );
00423 value = 1.0;
00424 }
00425 case PT_set:
00426 if(value == 0.0){
00427 ival = (prop_ptr ? *gl_get_int64(obj, prop_ptr) : *gl_get_int64_by_name(obj, property) );
00428 value = 1.0;
00429 }
00430
00431
00432 for(i = 0; i < bin_count; ++i){
00433 if(ival > bin_list[i].low_val && ival < bin_list[i].high_val){
00434 ++binctr[i];
00435 } else if(bin_list[i].low_inc && bin_list[i].low_val == ival){
00436 ++binctr[i];
00437 } else if(bin_list[i].high_inc && bin_list[i].high_val == ival){
00438 ++binctr[i];
00439 }
00440 }
00441 break;
00442 }
00443
00444 return 0;
00445 }
00446
00447 TIMESTAMP histogram::sync(TIMESTAMP t0, TIMESTAMP t1)
00448 {
00449 int i = 0;
00450 double value = 0.0;
00451 OBJECT *obj = OBJECTHDR(this);
00452
00453 if((sampling_interval == -1.0 && t_count > t1) ||
00454 sampling_interval == 0.0 ||
00455 (sampling_interval > 0.0 && t1 >= next_sample))
00456 {
00457 if(group_list == NULL){
00458 feed_bins(obj->parent);
00459 } else {
00460 OBJECT *obj = gl_find_next(group_list, NULL);
00461 for(; obj != NULL; obj = gl_find_next(group_list, obj)){
00462 feed_bins(obj);
00463 }
00464 }
00465 t_sample = t1;
00466 if(sampling_interval > 0.0){
00467 next_sample = t1 + (int64)(sampling_interval/TS_SECOND);
00468 } else {
00469 next_sample = TS_NEVER;
00470 }
00471 }
00472
00473 if((counting_interval == -1.0 && t_count > t1) ||
00474 counting_interval == 0.0 ||
00475 (counting_interval > 0.0 && t1 >= next_count))
00476 {
00477 char1024 line;
00478 char ts[64];
00479 int off=0, i=0;
00480 DATETIME dt;
00481
00482
00483 gl_localtime(t1,&dt);
00484 gl_strtime(&dt,ts,64);
00485
00486
00487 for(i = 0; i < bin_count; ++i){
00488 off += sprintf(line+off, "%i", binctr[i]);
00489 if(i != bin_count){
00490 off += sprintf(line+off, ",");
00491 }
00492 }
00493
00494
00495 ops->write(this, ts, line);
00496
00497
00498 for(i = 0; i < bin_count; ++i){
00499 binctr[i] = 0;
00500 }
00501 t_count = t1;
00502 if(counting_interval > 0){
00503 next_count = t_count + (int64)(counting_interval/TS_SECOND);
00504 } else {
00505 next_count = TS_NEVER;
00506 }
00507
00508
00509 if(--limit < 1){
00510 ops->close(this);
00511 next_count = TS_NEVER;
00512 next_sample = TS_NEVER;
00513 }
00514 }
00515 return ( next_count < next_sample ? next_count : next_sample );
00516 }
00517
00518 int histogram::isa(char *classname)
00519 {
00520 return strcmp(classname,"histogram")==0;
00521 }
00522
00523
00525
00527
00535 EXPORT int create_histogram(OBJECT **obj, OBJECT *parent)
00536 {
00537 try
00538 {
00539 *obj = gl_create_object(histogram::oclass);
00540 if (*obj!=NULL)
00541 {
00542 histogram *my = OBJECTDATA(*obj,histogram);
00543 gl_set_parent(*obj,parent);
00544 return my->create();
00545 }
00546 }
00547 catch (char *msg)
00548 {
00549 gl_error("create_histogram: %s", msg);
00550 }
00551 return 0;
00552 }
00553
00554 EXPORT int init_histogram(OBJECT *obj)
00555 {
00556 histogram *my = OBJECTDATA(obj,histogram);
00557 try {
00558 return my->init(obj->parent);
00559 }
00560 catch (char *msg)
00561 {
00562 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, msg);
00563 return 0;
00564 }
00565 }
00566
00567 EXPORT TIMESTAMP sync_histogram(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00568 {
00569 histogram *pObj = OBJECTDATA(obj,histogram);
00570 try {
00571 if (pass == PC_PRETOPDOWN)
00572 return pObj->sync(obj->clock, t0);
00573 } catch (const char *error) {
00574 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, error);
00575 return 0;
00576 } catch (...) {
00577 GL_THROW("%s (histogram:%d): %s", (obj->name ? obj->name : "(unnamed)"), obj->id, "unknown exception");
00578 return 0;
00579 }
00580 return TS_NEVER;
00581 }
00582
00591 EXPORT int isa_histogram(OBJECT *obj, char *classname)
00592 {
00593 return OBJECTDATA(obj,histogram)->isa(classname);
00594 }
00595