fix papi_perror compile error
[charm.git] / src / ck-tune / trace-autoPerf.C
1 #include "charm++.h"
2 #include "TraceAutoPerf.decl.h"
3 #include "trace-autoPerf.h"
4 #include <algorithm>
5 #include <math.h>
6 #define TRIGGER_PERF_IDLE_PERCENTAGE 0.1 
7
8 #define SMP_ANALYSIS  0 
9 #define DEBUG_LEVEL 0
10 #define   CP_PERIOD  100
11
12 #define TIMESTEP_RATIO_THRESHOLD 0
13
14 #define UTIL_PERCENTAGE   0.95
15
16 #if 0 
17 #define DEBUG_PRINT(x) x  
18 #else
19 #define DEBUG_PRINT(x) 
20 #endif
21
22 // trace functions here
23 #include "trace-perf.C"
24 CkpvDeclare(savedPerfDatabase*, perfDatabase);
25 CkpvExtern(int, availAnalyzeCP);
26 CksvExtern(int, availAnalyzeNodeCP);
27 CkpvExtern(int, hasPendingAnalysis);
28 CkpvExtern(int, currentStep);
29 CkpvExtern(CkCallback, callBackAutoPerfDone);
30 CkGroupID traceAutoPerfGID;
31 CProxy_TraceAutoPerfBOC autoPerfProxy;
32 CProxy_TraceNodeAutoPerfBOC autoPerfNodeProxy;
33 extern void setNoPendingAnalysis();
34 extern void startAnalysisonIdle();
35 extern void autoPerfReset();
36 //-----------------------utility functions ----------------------
37 //Reduce summary data
38 CkReductionMsg *perfDataReduction(int nMsg,CkReductionMsg **msgs){
39     perfData *ret;
40     if(nMsg > 0){
41         ret=(perfData*)msgs[0]->getData();
42     }
43     for (int i=1;i<nMsg;i++) {
44         perfData *m=(perfData*)(msgs[i]->getData());
45         // idle time (min/s$um/max)
46         ret->idleMin = min(ret->idleMin, m->idleMin);
47         ret->idleTotalTime += m->idleTotalTime; 
48         ret->idleMax = max(ret->idleMax, m->idleMax);
49         // overhead time (min/sum/max)
50         ret->overheadMin = min(ret->overheadMin, m->overheadMin);
51         ret->overheadTotalTime += m->overheadTotalTime; 
52         ret->overheadMax = max(ret->overheadMax, m->overheadMax);
53         // util time (min/sum/max)
54         ret->utilMin = min(ret->utilMin, m->utilMin);
55         ret->utilTotalTime += m->utilTotalTime; 
56         ret->utilMax = max(ret->utilMax, m->utilMax);
57         // mem usage (max)
58         ret->mem =max(ret->mem,m->mem);
59         // bytes per invocation for two types of entry methods
60         ret->numMsgs += m->numMsgs; 
61         ret->numBytes += m->numBytes; 
62         ret->commTime += m->commTime; 
63         // Grain size (avg, max)
64         ret->grainsizeAvg += m->grainsizeAvg;
65         ret->grainsizeMax = max(ret->grainsizeMax, m->grainsizeMax);
66         //Total invocations
67         ret->numInvocations += m->numInvocations;
68         ret->objLoadMax = max(ret->objLoadMax, m->objLoadMax);
69     }  
70     CkReductionMsg *msg= CkReductionMsg::buildNew(sizeof(perfData),ret); 
71     return msg;
72 }
73
74 TraceAutoPerfInit::TraceAutoPerfInit(CkArgMsg* args)
75 {
76     traceAutoPerfGID = CProxy_TraceAutoPerfBOC::ckNew();
77     autoPerfProxy = CProxy_TraceAutoPerfBOC::ckNew();
78     autoPerfNodeProxy = CProxy_TraceNodeAutoPerfBOC::ckNew();
79     bool isIdleAnalysis = CmiGetArgFlagDesc(args->argv,"+idleAnalysis","start performance analysis when idle");
80     if(isIdleAnalysis){
81         CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)startAnalysisonIdle, NULL);
82         CcdCallFnAfterOnPE((CcdVoidFn)autoPerfReset, NULL, 10, CmiMyPe());
83     }
84 }
85
86 // set the call back function, which is invoked after auto perf is done
87 void TraceAutoPerfBOC::setAutoPerfDoneCallback(CkCallback cb, bool frameworkShouldAdvancePhase)
88 {
89     CkpvAccess(callBackAutoPerfDone) = cb;
90 }
91
92 //mark time step
93 void TraceNodeAutoPerfBOC::timeStep(int reductionPE)
94 {
95     getPerfData(reductionPE, CkCallback::ignore );
96 }
97
98 CkReduction::reducerType perfDataReductionType;
99 void TraceNodeAutoPerfBOC::getPerfData(int reductionPE, CkCallback cb)
100 {
101 }
102
103 void TraceAutoPerfBOC::timeStep(int reductionPE)
104 {
105     getPerfData(reductionPE, CkCallback::ignore );
106 }
107
108 // Collect local perf data and send results to reductionPE
109 void TraceAutoPerfBOC::getPerfData(int reductionPE, CkCallback cb)
110 {
111     TraceAutoPerf *t = localAutoPerfTracingInstance();
112     t->markStep();
113     perfData * data = t->getSummary();
114     DEBUG_PRINT (
115         t->printSummary();
116         )
117     CkCallback *cb1 = new CkCallback(CkIndex_TraceAutoPerfBOC::globalPerfAnalyze(NULL), thisProxy[reductionPE]);
118     contribute(sizeof(perfData),data,perfDataReductionType, *cb1);
119     t->resetAll();
120     CkpvAccess(hasPendingAnalysis) = 1;
121     CcdCallFnAfterOnPE((CcdVoidFn)setNoPendingAnalysis, NULL, CP_PERIOD, CkMyPe());
122 }
123
124 //check local idle percentage to decide whether trigger global analysis
125 void TraceAutoPerfBOC::localPerfQuery()
126 {
127
128     TraceAutoPerf *t = localAutoPerfTracingInstance();
129     double idlePercent = t->checkIdleRatioDuringIdle();
130     CkpvAccess(currentStep)++;
131     if( idlePercent > TRIGGER_PERF_IDLE_PERCENTAGE ) //TUNABLE  
132     {
133         //CkPrintf("\nTIMER:%f PE:%d idle percentage is HIGH start analysis  %.3f\n", TraceTimer(), CkMyPe(),   idlePercent);
134 #if SMP_ANALYSIS
135         {
136             for(int i=0; i<CkNumNodes(); i++)
137                 autoPerfNodeProxy[i].getPerfData(CkMyNode(), CkCallback::ignore);
138         }
139 #else
140         autoPerfProxy.getPerfData(0, CkCallback::ignore);
141         //autoPerfProxy.getPerfData(CkMyPe(), CkCallback::ignore);
142 #endif
143     }else if(idlePercent < 0)
144     {
145         TraceAutoPerf *t = localAutoPerfTracingInstance();
146         t->markStep();
147         //CkPrintf("%f PE:%d idle percentage is negative %f\n", TraceTimer(), CkMyPe(), idlePercent);
148     } else
149     {
150         //CkPrintf("%f PE:%d idle percentage is okay  %f\n", TraceTimer(), CkMyPe(),idlePercent);
151     }
152 }
153
154 //perf data from all processors are collected on one PE, perform analysis based on global data
155 void TraceAutoPerfBOC::globalPerfAnalyze(CkReductionMsg *msg )
156 {
157     static int counters = 0;
158     int level = 0;
159     //CkPrintf("\n-------------------------global %d  Timer:%f analyzing------- %d \n\n", CkMyPe(), CkWallTimer(), counters++);
160     int size=msg->getSize() / sizeof(double);
161     perfData *data=(perfData*) msg->getData();
162     double totalTime = data->utilTotalTime  + data->idleTotalTime + data->overheadTotalTime ;
163     double idlePercentage = data->idleTotalTime/totalTime;
164     double overheadPercentage = data->overheadTotalTime/totalTime;
165     double utilPercentage = data->utilTotalTime/totalTime;
166     //DEBUG_PRINT ( 
167     CkPrintf("Utilization(%):  \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f\n", data->utilMin*100, data->utilMax*100, utilPercentage*100, data->utilTotalTime);
168     CkPrintf("Idle(%):         \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f \n", data->idleMin*100,  data->idleMax*100, idlePercentage*100, data->idleTotalTime);
169     CkPrintf("Overhead(%):     \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f \n", data->overheadMin*100, data->overheadMax*100, overheadPercentage*100, data->overheadTotalTime);
170     CkPrintf("Grainsize(ms):\t(avg:max)\t: (%.3f:    %.3f) \n", data->utilTotalTime/data->numInvocations*1000, data->grainsizeMax*1000);
171     CkPrintf("Invocations:  \t%lld\n", data->numInvocations);
172     //)
173    
174     // --- time step measurement 
175     double timeElapse = CkWallTimer() - startStepTimer;
176     double avgTimeStep = timeElapse/(CkpvAccess(currentStep) - lastAnalyzeStep);
177     CkpvAccess(perfDatabase)->insert(avgTimeStep, utilPercentage,  idlePercentage, overheadPercentage); 
178     DEBUG_PRINT ( 
179         CkPrintf("-------------- timestep --%d:%d--- \n", CkpvAccess(currentStep),  lastAnalyzeStep);
180         )
181     startStepTimer = CkWallTimer();
182     lastAnalyzeStep = CkpvAccess(currentStep);
183     //check the performance, and decide whether to tune
184     //
185     CkpvAccess(callBackAutoPerfDone).send(); 
186 }
187
188 /*
189  *  based on the history data, (tunnable parameter values, performance metrics)
190  *  generate a performance model using curve fitting.
191  */
192
193 enum  functionType { LINEAR, SECOND_ORDER, THIRD_ORDER };
194
195 void TraceAutoPerfBOC::generatePerfModel()
196 {
197     // a set of performance results is the function value
198     // a set of tunable parameter values  is the function variable
199     // linear,  second degree polynomial , third degree polynomial 
200     // exponential polynomial fit
201     // GNU scientific library has tools to do this
202
203     int modelType;
204     modelType = LINEAR;
205     switch( modelType)
206     {
207         case LINEAR:
208
209             break;
210
211         case SECOND_ORDER:
212             break;
213
214         case THIRD_ORDER:
215             break;
216
217         default:
218             break;
219     }
220 }
221
222 extern "C" void traceAutoPerfExitFunction() {
223     CkPrintf("calling before exiting............................\n");
224     autoPerfProxy.timeStep(CkMyPe());
225     //CkExit();
226 }
227 void _initTraceAutoPerfBOC()
228 {
229     perfDataReductionType=CkReduction::addReducer(perfDataReduction);
230
231     CkpvInitialize(int, currentStep);
232     CkpvAccess(currentStep) = 0;
233     CkpvInitialize(int, hasPendingAnalysis);
234     CkpvAccess(hasPendingAnalysis) = 0;
235     CkpvInitialize(CkCallback, callBackAutoPerfDone);
236     CkpvAccess(callBackAutoPerfDone) = CkCallback::ckExit; 
237     CkpvInitialize(savedPerfDatabase*, perfDatabase);
238     CkpvAccess(perfDatabase) = new savedPerfDatabase();
239 #ifdef __BIGSIM__
240     if (BgNodeRank()==0) {
241 #else               
242     if (CkMyRank() == 0) {
243 #endif
244             registerExitFn(traceAutoPerfExitFunction);
245         }
246 }
247
248 void _initTraceNodeAutoPerfBOC()
249 {
250     CksvInitialize(int, availAnalyzeNodeCP);
251     CksvAccess(availAnalyzeNodeCP) = 1;
252 }
253 #include "TraceAutoPerf.def.h"