59f6eb67cbf35de890fc0cc5ff5fdb55b5e1dd72
[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 #if CMK_HAS_COUNTER_PAPI
70         for(int i=0; i<NUMPAPIEVENTS; i++)
71         {
72             ret->papiValues[i] += m->papiValues[i]; 
73         }
74 #endif
75     }  
76     CkReductionMsg *msg= CkReductionMsg::buildNew(sizeof(perfData),ret); 
77     return msg;
78 }
79
80 TraceAutoPerfInit::TraceAutoPerfInit(CkArgMsg* args)
81 {
82     traceAutoPerfGID = CProxy_TraceAutoPerfBOC::ckNew();
83     autoPerfProxy = CProxy_TraceAutoPerfBOC::ckNew();
84     autoPerfNodeProxy = CProxy_TraceNodeAutoPerfBOC::ckNew();
85     bool isIdleAnalysis = CmiGetArgFlagDesc(args->argv,"+idleAnalysis","start performance analysis when idle");
86     if(isIdleAnalysis){
87         CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,(CcdVoidFn)startAnalysisonIdle, NULL);
88         CcdCallFnAfterOnPE((CcdVoidFn)autoPerfReset, NULL, 10, CmiMyPe());
89     }
90 }
91
92 // set the call back function, which is invoked after auto perf is done
93 void TraceAutoPerfBOC::setAutoPerfDoneCallback(CkCallback cb, bool frameworkShouldAdvancePhase)
94 {
95     CkpvAccess(callBackAutoPerfDone) = cb;
96 }
97
98 //mark time step
99 void TraceNodeAutoPerfBOC::timeStep(int reductionPE)
100 {
101     getPerfData(reductionPE, CkCallback::ignore );
102 }
103
104 CkReduction::reducerType perfDataReductionType;
105 void TraceNodeAutoPerfBOC::getPerfData(int reductionPE, CkCallback cb)
106 {
107 }
108
109 void TraceAutoPerfBOC::timeStep(int reductionPE)
110 {
111     getPerfData(reductionPE, CkCallback::ignore );
112 }
113
114 // Collect local perf data and send results to reductionPE
115 void TraceAutoPerfBOC::getPerfData(int reductionPE, CkCallback cb)
116 {
117     TraceAutoPerf *t = localAutoPerfTracingInstance();
118     t->markStep();
119     perfData * data = t->getSummary();
120     DEBUG_PRINT (
121         t->printSummary();
122         )
123     CkCallback *cb1 = new CkCallback(CkIndex_TraceAutoPerfBOC::globalPerfAnalyze(NULL), thisProxy[reductionPE]);
124     contribute(sizeof(perfData),data,perfDataReductionType, *cb1);
125     t->resetAll();
126     CkpvAccess(hasPendingAnalysis) = 1;
127     CcdCallFnAfterOnPE((CcdVoidFn)setNoPendingAnalysis, NULL, CP_PERIOD, CkMyPe());
128 }
129
130 //check local idle percentage to decide whether trigger global analysis
131 void TraceAutoPerfBOC::localPerfQuery()
132 {
133
134     TraceAutoPerf *t = localAutoPerfTracingInstance();
135     double idlePercent = t->checkIdleRatioDuringIdle();
136     CkpvAccess(currentStep)++;
137     if( idlePercent > TRIGGER_PERF_IDLE_PERCENTAGE ) //TUNABLE  
138     {
139         //CkPrintf("\nTIMER:%f PE:%d idle percentage is HIGH start analysis  %.3f\n", TraceTimer(), CkMyPe(),   idlePercent);
140 #if SMP_ANALYSIS
141         {
142             for(int i=0; i<CkNumNodes(); i++)
143                 autoPerfNodeProxy[i].getPerfData(CkMyNode(), CkCallback::ignore);
144         }
145 #else
146         autoPerfProxy.getPerfData(0, CkCallback::ignore);
147         //autoPerfProxy.getPerfData(CkMyPe(), CkCallback::ignore);
148 #endif
149     }else if(idlePercent < 0)
150     {
151         TraceAutoPerf *t = localAutoPerfTracingInstance();
152         t->markStep();
153         //CkPrintf("%f PE:%d idle percentage is negative %f\n", TraceTimer(), CkMyPe(), idlePercent);
154     } else
155     {
156         //CkPrintf("%f PE:%d idle percentage is okay  %f\n", TraceTimer(), CkMyPe(),idlePercent);
157     }
158 }
159
160 //perf data from all processors are collected on one PE, perform analysis based on global data
161 void TraceAutoPerfBOC::globalPerfAnalyze(CkReductionMsg *msg )
162 {
163     static int counters = 0;
164     int level = 0;
165     //CkPrintf("\n-------------------------global %d  Timer:%f analyzing------- %d \n\n", CkMyPe(), CkWallTimer(), counters++);
166     int size=msg->getSize() / sizeof(double);
167     perfData *data=(perfData*) msg->getData();
168     double totalTime = data->utilTotalTime  + data->idleTotalTime + data->overheadTotalTime ;
169     double idlePercentage = data->idleTotalTime/totalTime;
170     double overheadPercentage = data->overheadTotalTime/totalTime;
171     double utilPercentage = data->utilTotalTime/totalTime;
172     //DEBUG_PRINT ( 
173     CkPrintf("Utilization(%):  \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f\n", data->utilMin*100, data->utilMax*100, utilPercentage*100, data->utilTotalTime);
174     CkPrintf("Idle(%):         \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f \n", data->idleMin*100,  data->idleMax*100, idlePercentage*100, data->idleTotalTime);
175     CkPrintf("Overhead(%):     \t(min:max:avg):(%.1f:\t  %.1f:\t  %.1f) time:%f \n", data->overheadMin*100, data->overheadMax*100, overheadPercentage*100, data->overheadTotalTime);
176     CkPrintf("Grainsize(ms):\t(avg:max)\t: (%.3f:    %.3f) \n", data->utilTotalTime/data->numInvocations*1000, data->grainsizeMax*1000);
177     CkPrintf("Invocations:  \t%lld\n", data->numInvocations);
178 #if CMK_HAS_COUNTER_PAPI
179     char eventName[PAPI_MAX_STR_LEN];
180     for (int i=0;i<NUMPAPIEVENTS;i++) {
181         PAPI_event_code_to_name(papiEvents[i], eventName);
182         CkPrintf(" EVENT  %s   counter   %lld \n", eventName, data->papiValues[i]);
183     }
184 #endif
185     //)
186    
187     // --- time step measurement 
188     double timeElapse = CkWallTimer() - startStepTimer;
189     double avgTimeStep = timeElapse/(CkpvAccess(currentStep) - lastAnalyzeStep);
190     CkpvAccess(perfDatabase)->insert(avgTimeStep, utilPercentage,  idlePercentage, overheadPercentage); 
191     DEBUG_PRINT ( 
192         CkPrintf("-------------- timestep --%d:%d--- \n", CkpvAccess(currentStep),  lastAnalyzeStep);
193         )
194     startStepTimer = CkWallTimer();
195     lastAnalyzeStep = CkpvAccess(currentStep);
196     //check the performance, and decide whether to tune
197     //
198     CkpvAccess(callBackAutoPerfDone).send(); 
199 }
200
201 /*
202  *  based on the history data, (tunnable parameter values, performance metrics)
203  *  generate a performance model using curve fitting.
204  */
205
206 enum  functionType { LINEAR, SECOND_ORDER, THIRD_ORDER };
207
208 void TraceAutoPerfBOC::generatePerfModel()
209 {
210     // a set of performance results is the function value
211     // a set of tunable parameter values  is the function variable
212     // linear,  second degree polynomial , third degree polynomial 
213     // exponential polynomial fit
214     // GNU scientific library has tools to do this
215
216     int modelType;
217     modelType = LINEAR;
218     switch( modelType)
219     {
220         case LINEAR:
221
222             break;
223
224         case SECOND_ORDER:
225             break;
226
227         case THIRD_ORDER:
228             break;
229
230         default:
231             break;
232     }
233 }
234
235 extern "C" void traceAutoPerfExitFunction() {
236     CkPrintf("calling before exiting............................\n");
237     autoPerfProxy.timeStep(CkMyPe());
238     //CkExit();
239 }
240 void _initTraceAutoPerfBOC()
241 {
242     perfDataReductionType=CkReduction::addReducer(perfDataReduction);
243
244     CkpvInitialize(int, currentStep);
245     CkpvAccess(currentStep) = 0;
246     CkpvInitialize(int, hasPendingAnalysis);
247     CkpvAccess(hasPendingAnalysis) = 0;
248     CkpvInitialize(CkCallback, callBackAutoPerfDone);
249     CkpvAccess(callBackAutoPerfDone) = CkCallback::ckExit; 
250     CkpvInitialize(savedPerfDatabase*, perfDatabase);
251     CkpvAccess(perfDatabase) = new savedPerfDatabase();
252 #ifdef __BIGSIM__
253     if (BgNodeRank()==0) {
254 #else               
255     if (CkMyRank() == 0) {
256 #endif
257             registerExitFn(traceAutoPerfExitFunction);
258         }
259 }
260
261 void _initTraceNodeAutoPerfBOC()
262 {
263     CksvInitialize(int, availAnalyzeNodeCP);
264     CksvAccess(availAnalyzeNodeCP) = 1;
265 }
266 #include "TraceAutoPerf.def.h"