00001 #include "lugre_prefix.h"
00002 #include "lugre_profile.h"
00003 #include <vector>
00004 #include <map>
00005 #include <set>
00006
00007 #include "lugre_shell.h"
00008
00009 namespace Lugre {
00010
00011 std::vector<void*> gCallStack;
00012 std::vector<void*> gHistory;
00013 bool gDoInit = true;
00014
00015 #define GET_TIMESTAMP ((unsigned int)(cShell::GetTicks()))
00016
00017
00018
00019
00020
00021 #ifdef PROFILE_CALLTIME
00022 #define CALLSTACK_ELEM_SIZE 4
00023 #else
00024 #define CALLSTACK_ELEM_SIZE 3
00025 #endif
00026
00027
00028
00029 #ifdef PROFILE_CALLCOUNT
00030 class cCallCountProfileIndex { public:
00031 const char* a;
00032 const int b;
00033 const char* c;
00034 cCallCountProfileIndex (const char* a,const int b,const char* c) : a(a), b(b), c(c) {}
00035 };
00036 struct cCallCountProfileMapCmpSimple {
00037 inline bool operator() (const cCallCountProfileIndex x, const cCallCountProfileIndex y) const {
00038
00039 return (x.a < y.a) ||
00040 (x.a == y.a && x.b < y.b) ||
00041 (x.a == y.a && x.b == y.b && x.c < y.c);
00042 }
00043 };
00044 struct cCallCountProfileSetCmp {
00045 inline bool operator() (const std::pair<cCallCountProfileIndex,int>& x,const std::pair<cCallCountProfileIndex,int>& y) const {
00046 return x.second > y.second;
00047 }
00048 };
00049 std::map<cCallCountProfileIndex,int,cCallCountProfileMapCmpSimple> gmCallCountProfileMap;
00050 typedef std::map<cCallCountProfileIndex,int,cCallCountProfileMapCmpSimple>::iterator tCallCountProfileMapItor;
00051 #endif
00052
00053 #ifdef ENABLE_PROFILING
00054 cProfiler::cProfiler(const char* sFile,const int iLine,const char* sFunc) {
00055 if (!Lugre_IsMainThread()) return;
00056 if (gDoInit) {
00057 gCallStack.reserve(1024*4*sizeof(void*));
00058 #ifdef KEEP_HISTORY
00059 gHistory.reserve(1024*1024*4*sizeof(void*));
00060 #endif
00061 gDoInit = false;
00062 }
00063 gCallStack.push_back((void*)sFile);
00064 gCallStack.push_back(reinterpret_cast<void*>((long)iLine));
00065 gCallStack.push_back((void*)sFunc);
00066 #ifdef PROFILE_CALLTIME
00067 gCallStack.push_back((void*)GET_TIMESTAMP);
00068 #endif
00069 #ifdef MEGALOGPATH
00070 FILE* fp = fopen(MEGALOGPATH,"a");
00071 int i = gCallStack.size()-CALLSTACK_ELEM_SIZE;
00072 for (int j=0;j<i/CALLSTACK_ELEM_SIZE;++j) fprintf(fp," ");
00073 fprintf(fp,"START %s:%ld:%s\n", (const char*) gCallStack[i],
00074 static_cast<long>(gCallStack[i+1]),
00075 (const char*) gCallStack[i+2]);
00076 fclose(fp);
00077 #endif
00078 #ifdef PROFILE_CALLCOUNT
00079 ++gmCallCountProfileMap[cCallCountProfileIndex(sFile,iLine,sFunc)];
00080 #endif
00081 }
00082
00083 cProfiler::~cProfiler() {
00084 if (!Lugre_IsMainThread()) return;
00085 #ifdef MEGALOGPATH
00086 FILE* fp = fopen(MEGALOGPATH,"a");
00087 int i = gCallStack.size()-CALLSTACK_ELEM_SIZE;
00088 for (int j=0;j<i/CALLSTACK_ELEM_SIZE;++j) fprintf(fp," ");
00089 fprintf(fp,"END %s:%ld:%s\n", (const char*) gCallStack[i],
00090 static_cast<long>(gCallStack[i+1]),
00091 (const char*) gCallStack[i+2]);
00092 fclose(fp);
00093 #endif
00094 #ifdef KEEP_HISTORY
00095 gHistory.push_back(gCallStack[0+gCallStack.size()-CALLSTACK_ELEM_SIZE]);
00096 gHistory.push_back(gCallStack[1+gCallStack.size()-CALLSTACK_ELEM_SIZE]);
00097 gHistory.push_back(gCallStack[2+gCallStack.size()-CALLSTACK_ELEM_SIZE]);
00098 #ifdef PROFILE_CALLTIME
00099 gHistory.push_back(GET_TIMESTAMP - gCallStack.back());
00100 #endif
00101 #endif
00102 gCallStack.pop_back();
00103 gCallStack.pop_back();
00104 gCallStack.pop_back();
00105 #ifdef PROFILE_CALLTIME
00106 gCallStack.pop_back();
00107 #endif
00108 }
00109
00110 void cProfiler::PrintStackTrace () {
00111 if (!Lugre_IsMainThread()) { printf("cProfiler::PrintStackTrace() called from non-main-thread!\n"); return; }
00112 for (int i=0;i<gCallStack.size();i+=CALLSTACK_ELEM_SIZE) {
00113 for (int j=0;j<i/CALLSTACK_ELEM_SIZE;++j) printf(" ");
00114 printf("%s:%ld:%s\n", (const char*) gCallStack[i],
00115 reinterpret_cast<long>(gCallStack[i+1]),
00116 (const char*) gCallStack[i+2]);
00117 }
00118 }
00119
00120 void cProfiler::PrintStackTrace (const char *filename) {
00121 FILE *f = fopen(filename,"a");
00122 if(f){
00123 if (!Lugre_IsMainThread()) {
00124 fprintf(f,"cProfiler::PrintStackTrace(filename) called from non-main-thread!\n");
00125 } else {
00126 for (int i=0;i<gCallStack.size();i+=CALLSTACK_ELEM_SIZE) {
00127 for (int j=0;j<i/CALLSTACK_ELEM_SIZE;++j) fprintf(f," ");
00128 fprintf(f,"%s:%ld:%s\n",(const char*) gCallStack[i],
00129 reinterpret_cast<long>(gCallStack[i+1]),
00130 (const char*) gCallStack[i+2]);
00131 }
00132 }
00133 fclose(f);
00134 }
00135 }
00136
00137
00138 #endif
00139
00140 void ProfileDumpCallCount () {
00141 #ifdef PROFILE_CALLCOUNT
00142 if (!Lugre_IsMainThread()) return;
00143 std::multiset<std::pair<cCallCountProfileIndex,int>,cCallCountProfileSetCmp> myCallCountProfileSet;
00144 typedef std::multiset<std::pair<cCallCountProfileIndex,int>,cCallCountProfileSetCmp>::iterator tCallCountProfileSetItor;
00145 { for (tCallCountProfileMapItor itor=gmCallCountProfileMap.begin();itor != gmCallCountProfileMap.end();++itor)
00146 myCallCountProfileSet.insert(std::make_pair((*itor).first,(*itor).second));
00147 }
00148
00149 int i=0;
00150 for (tCallCountProfileSetItor itor=myCallCountProfileSet.begin();itor != myCallCountProfileSet.end();++itor) {
00151
00152 const cCallCountProfileIndex& myIdx = (*itor).first;
00153 printf("CallCount %16d %s:%d %s()\n",(*itor).second,myIdx.a,myIdx.b,myIdx.c);
00154 }
00155 #endif
00156 }
00157
00158
00159 };