Me@50: /* Me@50: * Copyright 2010 OpenSourceStewardshipFoundation Me@50: * Me@50: * Licensed under BSD Me@50: */ Me@50: Me@50: #include Me@50: #include Me@50: #include Me@50: #include Me@52: #include Me@50: Me@50: #include "VMS.h" Me@50: #include "Queue_impl/BlockingQueue.h" Me@50: #include "Histogram/Histogram.h" Me@50: Me@50: Me@50: //================================ STATS ==================================== Me@50: Me@50: inline TSCount getTSCount() Me@50: { unsigned int low, high; Me@50: TSCount out; Me@50: Me@50: saveTimeStampCountInto( low, high ); Me@50: out = high; Me@50: out = (out << 32) + low; Me@50: return out; Me@50: } Me@50: Me@50: Me@50: Me@50: //==================== Probes ================= Me@50: #ifdef STATS__USE_TSC_PROBES Me@50: Me@50: int32 Me@50: VMS__create_histogram_probe( int32 numBins, float32 startValue, Me@50: float32 binWidth, char *nameStr ) Me@50: { IntervalProbe *newProbe; Me@50: int32 idx; Me@50: FloatHist *hist; Me@50: Me@50: idx = VMS__create_single_interval_probe( nameStr ); Me@50: newProbe = _VMSMasterEnv->intervalProbes[ idx ]; Me@50: Me@50: hist = makeFloatHistogram( numBins, startValue, binWidth ); Me@50: newProbe->hist = hist; Me@50: return idx; Me@50: } Me@50: Me@50: void Me@50: VMS_impl__record_interval_start_in_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: probe->startStamp = getTSCount(); Me@50: } Me@50: Me@50: void Me@50: VMS_impl__record_interval_end_in_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: TSCount endStamp; Me@50: Me@50: endStamp = getTSCount(); Me@50: Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: probe->endStamp = endStamp; Me@50: Me@50: if( probe->hist != NULL ) Me@50: { TSCount interval = probe->endStamp - probe->startStamp; Me@50: //if the interval is sane, then add to histogram Me@50: if( interval < probe->hist->endOfRange * 10 ) Me@50: addToFloatHist( interval, probe->hist ); Me@50: } Me@50: } Me@50: Me@50: void Me@50: VMS_impl__print_stats_of_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: Me@50: if( probe->hist == NULL ) Me@50: { Me@50: printf("probe: %s, interval: %.6lf\n", probe->nameStr,probe->interval); Me@50: } Me@50: Me@50: else Me@50: { Me@50: printf( "probe: %s\n", probe->nameStr ); Me@50: printFloatHist( probe->hist ); Me@50: } Me@50: } Me@50: #else Me@50: Me@50: /* Me@50: * In practice, probe operations are called from the app, from inside slaves Me@50: * -- so have to be sure each probe is single-VP owned, and be sure that Me@50: * any place common structures are modified it's done inside the master. Me@50: * So -- the only place common structures are modified is during creation. Me@50: * after that, all mods are to individual instances. Me@50: * Me@50: * Thniking perhaps should change the semantics to be that probes are Me@50: * attached to the virtual processor -- and then everything is guaranteed Me@50: * to be isolated -- except then can't take any intervals that span VPs, Me@50: * and would have to transfer the probes to Master env when VP dissipates.. Me@50: * gets messy.. Me@50: * Me@50: * For now, just making so that probe creation causes a suspend, so that Me@50: * the dynamic array in the master env is only modified from the master Me@50: * Me@50: */ Me@50: IntervalProbe * Me@50: create_generic_probe( char *nameStr, VirtProcr *animPr ) Me@50: { IntervalProbe *newProbe; Me@50: VMSSemReq reqData; Me@50: Me@50: reqData.reqType = createProbe; Me@50: reqData.nameStr = nameStr; Me@50: Me@52: VMS__send_VMSSem_request( &reqData, animPr ); Me@50: Me@53: return animPr->dataRetFromReq; Me@50: } Me@50: Me@52: /*Use this version from outside VMS -- it uses external malloc, and modifies Me@52: * dynamic array, so can't be animated in a slave VP Me@52: */ Me@52: IntervalProbe * Me@52: ext__create_generic_probe( char *nameStr ) Me@52: { IntervalProbe *newProbe; Me@52: int32 nameLen; Me@52: Me@52: newProbe = malloc( sizeof(IntervalProbe) ); Me@52: nameLen = strlen( nameStr ); Me@52: newProbe->nameStr = malloc( nameLen ); Me@52: memcpy( newProbe->nameStr, nameStr, nameLen ); Me@52: newProbe->hist = NULL; Me@52: newProbe->schedChoiceWasRecorded = FALSE; Me@52: newProbe->probeID = Me@52: addToDynArray( newProbe, _VMSMasterEnv->dynIntervalProbesInfo ); Me@52: Me@52: return newProbe; Me@52: } Me@52: Me@53: Me@53: /*Only call from inside master or main startup/shutdown thread Me@53: */ Me@53: void Me@53: VMS_impl__free_probe( IntervalProbe *probe ) Me@53: { if( probe->hist != NULL ) freeDblHist( probe->hist ); Me@53: if( probe->nameStr != NULL) VMS__free( probe->nameStr ); Me@53: VMS__free( probe ); Me@53: } Me@53: Me@53: Me@50: int32 Me@53: VMS_impl__record_time_point_into_new_probe( char *nameStr, VirtProcr *animPr) Me@50: { IntervalProbe *newProbe; Me@50: struct timeval *startStamp; Me@50: float64 startSecs; Me@50: Me@50: newProbe = create_generic_probe( nameStr, animPr ); Me@50: newProbe->endSecs = 0; Me@50: Me@50: gettimeofday( &(newProbe->startStamp), NULL); Me@50: Me@50: //turn into a double Me@50: startStamp = &(newProbe->startStamp); Me@50: startSecs = startStamp->tv_sec + ( startStamp->tv_usec / 1000000.0 ); Me@50: newProbe->startSecs = startSecs; Me@50: Me@50: return newProbe->probeID; Me@50: } Me@50: Me@50: int32 Me@52: VMS_ext_impl__record_time_point_into_new_probe( char *nameStr ) Me@52: { IntervalProbe *newProbe; Me@52: struct timeval *startStamp; Me@52: float64 startSecs; Me@52: Me@52: newProbe = ext__create_generic_probe( nameStr ); Me@52: newProbe->endSecs = 0; Me@52: Me@52: gettimeofday( &(newProbe->startStamp), NULL); Me@52: Me@52: //turn into a double Me@52: startStamp = &(newProbe->startStamp); Me@52: startSecs = startStamp->tv_sec + ( startStamp->tv_usec / 1000000.0 ); Me@52: newProbe->startSecs = startSecs; Me@52: Me@52: return newProbe->probeID; Me@52: } Me@52: Me@52: int32 Me@50: VMS_impl__create_single_interval_probe( char *nameStr, VirtProcr *animPr ) Me@50: { IntervalProbe *newProbe; Me@50: Me@50: newProbe = create_generic_probe( nameStr, animPr ); Me@50: Me@50: return newProbe->probeID; Me@50: } Me@50: Me@50: int32 Me@50: VMS_impl__create_histogram_probe( int32 numBins, float64 startValue, Me@50: float64 binWidth, char *nameStr, VirtProcr *animPr ) Me@50: { IntervalProbe *newProbe; Me@50: DblHist *hist; Me@50: Me@50: newProbe = create_generic_probe( nameStr, animPr ); Me@50: Me@50: hist = makeDblHistogram( numBins, startValue, binWidth ); Me@50: newProbe->hist = hist; Me@50: return newProbe->probeID; Me@50: } Me@50: Me@50: void Me@50: VMS_impl__index_probe_by_its_name( int32 probeID, VirtProcr *animPr ) Me@50: { IntervalProbe *probe; Me@50: Me@50: //TODO: fix this To be in Master -- race condition Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: Me@50: addValueIntoTable(probe->nameStr, probe, _VMSMasterEnv->probeNameHashTbl); Me@50: } Me@50: Me@50: IntervalProbe * Me@50: VMS_impl__get_probe_by_name( char *probeName, VirtProcr *animPr ) Me@50: { Me@50: //TODO: fix this To be in Master -- race condition Me@50: return getValueFromTable( probeName, _VMSMasterEnv->probeNameHashTbl ); Me@50: } Me@50: Me@50: Me@50: /*Everything is local to the animating procr, so no need for request, do Me@50: * work locally, in the anim Pr Me@50: */ Me@50: void Me@50: VMS_impl__record_sched_choice_into_probe( int32 probeID, VirtProcr *animatingPr ) Me@50: { IntervalProbe *probe; Me@50: Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: probe->schedChoiceWasRecorded = TRUE; Me@50: probe->coreNum = animatingPr->coreAnimatedBy; Me@50: probe->procrID = animatingPr->procrID; Me@53: probe->procrCreateSecs = animatingPr->createPtInSecs; Me@50: } Me@50: Me@50: /*Everything is local to the animating procr, so no need for request, do Me@50: * work locally, in the anim Pr Me@50: */ Me@50: void Me@50: VMS_impl__record_interval_start_in_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: Me@55: DEBUG( dbgProbes, "record start of interval\n" ) Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: gettimeofday( &(probe->startStamp), NULL ); Me@50: } Me@50: Me@50: Me@50: /*Everything is local to the animating procr, so no need for request, do Me@50: * work locally, in the anim Pr Me@50: */ Me@50: void Me@50: VMS_impl__record_interval_end_in_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: struct timeval *endStamp, *startStamp; Me@54: float64 startSecs, endSecs; Me@50: Me@55: DEBUG( dbgProbes, "record end of interval\n" ) Me@50: //possible seg-fault if array resized by diff core right after this Me@50: // one gets probe..? Something like that? Might be safe.. don't care Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: gettimeofday( &(probe->endStamp), NULL); Me@50: Me@50: //now turn into an interval held in a double Me@50: startStamp = &(probe->startStamp); Me@50: endStamp = &(probe->endStamp); Me@50: Me@50: startSecs = startStamp->tv_sec + ( startStamp->tv_usec / 1000000.0 ); Me@50: endSecs = endStamp->tv_sec + ( endStamp->tv_usec / 1000000.0 ); Me@50: Me@50: probe->interval = endSecs - startSecs; Me@50: probe->startSecs = startSecs; Me@50: probe->endSecs = endSecs; Me@50: Me@50: if( probe->hist != NULL ) Me@50: { Me@50: //if the interval is sane, then add to histogram Me@50: if( probe->interval < probe->hist->endOfRange * 10 ) Me@50: addToDblHist( probe->interval, probe->hist ); Me@50: } Me@50: } Me@50: Me@50: void Me@50: print_probe_helper( IntervalProbe *probe ) Me@50: { Me@50: printf( "\nprobe: %s, ", probe->nameStr ); Me@50: Me@50: if( probe->schedChoiceWasRecorded ) Me@50: { printf( "coreNum: %d, procrID: %d, procrCreated: %.6lf | ", Me@50: probe->coreNum, probe->procrID, probe->procrCreateSecs ); Me@50: } Me@50: Me@50: if( probe->endSecs == 0 ) //just a single point in time Me@50: { Me@50: printf( " time point: %.6lf\n", Me@50: probe->startSecs - _VMSMasterEnv->createPtInSecs ); Me@50: } Me@50: else if( probe->hist == NULL ) //just an interval Me@50: { Me@50: printf( " startSecs: %.6lf, interval: %.6lf\n", Me@50: probe->startSecs - _VMSMasterEnv->createPtInSecs, probe->interval); Me@50: } Me@50: else //a full histogram of intervals Me@50: { Me@50: printDblHist( probe->hist ); Me@50: } Me@50: } Me@50: Me@50: //TODO: change so pass around pointer to probe instead of its array-index.. Me@50: // will eliminate chance for timing of resize to cause problems with the Me@50: // lookup -- even though don't think it actually can cause problems.. Me@50: // there's no need to pass index around -- have hash table for names, and Me@50: // only need it once, then have ptr to probe.. the thing about enum the Me@50: // index and use that as name is clunky in practice -- just hash. Me@50: void Me@50: VMS_impl__print_stats_of_probe( int32 probeID ) Me@50: { IntervalProbe *probe; Me@50: Me@50: probe = _VMSMasterEnv->intervalProbes[ probeID ]; Me@50: Me@50: print_probe_helper( probe ); Me@50: } Me@50: Me@50: Me@50: Me@50: void Me@50: generic_print_probe( void *_probe ) Me@50: { IntervalProbe *probe; Me@50: Me@50: probe = (IntervalProbe *)_probe; Me@50: print_probe_helper( probe ); Me@50: } Me@50: Me@50: void Me@50: VMS_impl__print_stats_of_all_probes() Me@50: { IntervalProbe *probe; Me@50: Me@50: forAllInDynArrayDo( _VMSMasterEnv->dynIntervalProbesInfo, Me@50: &generic_print_probe ); Me@50: fflush( stdout ); Me@50: } Me@50: #endif