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