profile_funclevel.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /////////////////////////////////////////////////////////////////////////EA-V1
  19. // $File: //depot/GeneralsMD/Staging/code/Libraries/Source/profile/profile_funclevel.cpp $
  20. // $Author: mhoffe $
  21. // $Revision: #4 $
  22. // $DateTime: 2003/08/14 13:43:29 $
  23. //
  24. // ©2003 Electronic Arts
  25. //
  26. // Function level profiling
  27. //////////////////////////////////////////////////////////////////////////////
  28. #include "_pch.h"
  29. #include "../debug/debug.h"
  30. #include <new>
  31. #ifdef HAS_PROFILE
  32. // TLS index (-1 if not yet initialized)
  33. static int TLSIndex=-1;
  34. // our own fast critical section
  35. static ProfileFastCS cs;
  36. // Unfortunately VC 6 doesn't support _pleave (or _pexit) so
  37. // we have to come up with our own type of implementation here...
  38. static void __declspec(naked) _pleave(void)
  39. {
  40. ProfileFuncLevelTracer *p;
  41. unsigned curESP,leaveAddr;
  42. _asm
  43. {
  44. push ebp // this will be overwritten down there...
  45. push ebp // setup standard stack frame
  46. push eax
  47. mov ebp,esp
  48. mov eax,esp
  49. sub esp,3*4 // 3 local DWord vars
  50. pushad
  51. mov [curESP],eax
  52. }
  53. curESP+=8;
  54. p=(ProfileFuncLevelTracer *)TlsGetValue(TLSIndex);
  55. leaveAddr=p->Leave(curESP);
  56. *(unsigned *)(curESP)=leaveAddr;
  57. _asm
  58. {
  59. popad
  60. add esp,3*4 // must match sub esp above
  61. pop eax
  62. pop ebp
  63. ret
  64. }
  65. }
  66. extern "C" void __declspec(naked) _cdecl _penter(void)
  67. {
  68. unsigned callerFunc,ESPonReturn,callerRet;
  69. ProfileFuncLevelTracer *p;
  70. _asm
  71. {
  72. push ebp
  73. push eax
  74. mov ebp,esp
  75. mov eax,esp
  76. sub esp,4*4 // 4 local DWord vars
  77. pushad
  78. // calc return address
  79. add eax,4+4 // account for push ebp and push eax
  80. mov ebx,[eax] // grab return address
  81. mov [callerFunc],ebx
  82. // get some more stuff
  83. add eax,4
  84. mov [ESPonReturn],eax
  85. mov ebx,[eax]
  86. mov [callerRet],ebx
  87. // jam in our exit code
  88. mov dword ptr [eax],offset _pleave
  89. }
  90. // do we need a new stack tracer?
  91. if (TLSIndex==-1)
  92. TLSIndex=TlsAlloc();
  93. p=(ProfileFuncLevelTracer *)TlsGetValue(TLSIndex);
  94. if (!p)
  95. {
  96. p=(ProfileFuncLevelTracer *)ProfileAllocMemory(sizeof(ProfileFuncLevelTracer));
  97. new (p) ProfileFuncLevelTracer;
  98. TlsSetValue(TLSIndex,p);
  99. }
  100. // enter function
  101. p->Enter(callerFunc-5,ESPonReturn,callerRet);
  102. // cleanup
  103. _asm
  104. {
  105. popad
  106. add esp,4*4 // must match sub esp above
  107. pop eax
  108. pop ebp
  109. ret
  110. }
  111. }
  112. ProfileFuncLevelTracer *ProfileFuncLevelTracer::head=NULL;
  113. bool ProfileFuncLevelTracer::shuttingDown=false;
  114. int ProfileFuncLevelTracer::curFrame=0;
  115. unsigned ProfileFuncLevelTracer::frameRecordMask;
  116. bool ProfileFuncLevelTracer::recordCaller=false;
  117. ProfileFuncLevelTracer::ProfileFuncLevelTracer(void):
  118. stack(NULL), usedStack(0), totalStack(0), maxDepth(0)
  119. {
  120. ProfileFastCS::Lock lock(cs);
  121. next=head;
  122. head=this;
  123. }
  124. ProfileFuncLevelTracer::~ProfileFuncLevelTracer()
  125. {
  126. // yes, I know we leak...
  127. }
  128. void ProfileFuncLevelTracer::Enter(unsigned addr, unsigned esp, unsigned ret)
  129. {
  130. // must stack grow?
  131. if (usedStack>=totalStack)
  132. stack=(StackEntry *)ProfileReAllocMemory(stack,(totalStack+=100)*sizeof(StackEntry));
  133. // save info
  134. Function *f=func.Find(addr);
  135. if (!f)
  136. {
  137. // new function
  138. f=(Function *)ProfileAllocMemory(sizeof(Function));
  139. new (f) Function(this);
  140. f->addr=addr;
  141. f->glob.callCount=f->glob.tickPure=f->glob.tickTotal=0;
  142. for (int i=0;i<MAX_FRAME_RECORDS;i++)
  143. f->cur[i].callCount=f->cur[i].tickPure=f->cur[i].tickTotal=0;
  144. f->depth=0;
  145. func.Insert(f);
  146. }
  147. StackEntry &s=stack[usedStack++];
  148. s.func=f;
  149. s.esp=esp;
  150. s.retVal=ret;
  151. ProfileGetTime(s.tickEnter);
  152. s.tickSubTime=0;
  153. f->depth++;
  154. // new max depth?
  155. if (usedStack>=maxDepth)
  156. maxDepth=usedStack;
  157. DLOG_GROUP(profile_stack,Debug::RepeatChar(' ',usedStack-1)
  158. << Debug::Hex() << this
  159. << " Enter " << Debug::Width(8) << addr
  160. << " ESP " << Debug::Width(8) << esp
  161. << " return " << Debug::Width(8) << ret
  162. << " level " << Debug::Dec() << usedStack
  163. );
  164. }
  165. unsigned ProfileFuncLevelTracer::Leave(unsigned esp)
  166. {
  167. // get current "time"
  168. __int64 cur;
  169. ProfileGetTime(cur);
  170. while (usedStack>0)
  171. {
  172. // leave current function
  173. usedStack--;
  174. StackEntry &s=stack[usedStack],
  175. &sPrev=stack[usedStack-1];
  176. Function *f=s.func;
  177. // decrease call depth
  178. // note: add global time only if call depth is 0
  179. f->depth--;
  180. // insert caller
  181. if (recordCaller&&usedStack)
  182. f->glob.caller.Insert(sPrev.func->addr,1);
  183. // inc call counter
  184. f->glob.callCount++;
  185. // add total time
  186. __int64 delta=cur-s.tickEnter;
  187. if (!f->depth)
  188. f->glob.tickTotal+=delta;
  189. // add pure time
  190. f->glob.tickPure+=delta-s.tickSubTime;
  191. // add sub time for higher function
  192. if (usedStack)
  193. sPrev.tickSubTime+=delta;
  194. // frame based profiling?
  195. if (frameRecordMask)
  196. {
  197. unsigned mask=frameRecordMask;
  198. for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
  199. {
  200. if (mask&1)
  201. {
  202. if (recordCaller&&usedStack>0)
  203. f->cur[i].caller.Insert(sPrev.func->addr,1);
  204. f->cur[i].callCount++;
  205. if (!f->depth)
  206. f->cur[i].tickTotal+=delta;
  207. f->cur[i].tickPure+=delta-s.tickSubTime;
  208. }
  209. if (!(mask>>=1))
  210. break;
  211. }
  212. }
  213. // exit if address match (somewhat...)
  214. if (s.esp==esp)
  215. break;
  216. // catching those nasty ret<n>...
  217. if (s.esp<esp&&
  218. (esp-s.esp)%4==0&&
  219. (esp-s.esp)<256)
  220. break;
  221. // emit warning
  222. DCRASH("ESP " << Debug::Hex() << esp << " does not match " << stack[usedStack].esp << Debug>>Dec());
  223. }
  224. DLOG_GROUP(profile_stack,Debug::RepeatChar(' ',usedStack-1)
  225. << Debug::Hex() << this
  226. << " Leave " << Debug::Width(8) << ""
  227. << " ESP " << Debug::Width(8) << stack[usedStack].esp
  228. << " return " << Debug::Width(8) << stack[usedStack].retVal
  229. << " level " << Debug::Dec() << usedStack
  230. );
  231. return stack[usedStack].retVal;
  232. }
  233. void ProfileFuncLevelTracer::Shutdown(void)
  234. {
  235. if (frameRecordMask)
  236. {
  237. for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
  238. if (frameRecordMask&(1<<i))
  239. for (ProfileFuncLevelTracer *p=head;p;p=p->next)
  240. p->FrameEnd(i,-1);
  241. }
  242. }
  243. int ProfileFuncLevelTracer::FrameStart(void)
  244. {
  245. ProfileFastCS::Lock lock(cs);
  246. for (unsigned i=0;i<MAX_FRAME_RECORDS;i++)
  247. if (!(frameRecordMask&(1<<i)))
  248. break;
  249. if (i==MAX_FRAME_RECORDS)
  250. return -1;
  251. for (ProfileFuncLevelTracer *p=head;p;p=p->next)
  252. {
  253. Function *f;
  254. for (int k=0;(f=p->func.Enumerate(k))!=NULL;k++)
  255. {
  256. Profile &p=f->cur[i];
  257. p.caller.Clear();
  258. p.callCount=p.tickPure=p.tickTotal=0;
  259. }
  260. }
  261. frameRecordMask|=1<<i;
  262. return i;
  263. }
  264. void ProfileFuncLevelTracer::FrameEnd(int which, int mixIndex)
  265. {
  266. DFAIL_IF(which<0||which>=MAX_FRAME_RECORDS)
  267. return;
  268. DFAIL_IF(!(frameRecordMask&(1<<which)))
  269. return;
  270. DFAIL_IF(mixIndex>=curFrame)
  271. return;
  272. ProfileFastCS::Lock lock(cs);
  273. frameRecordMask^=1<<which;
  274. if (mixIndex<0)
  275. curFrame++;
  276. for (ProfileFuncLevelTracer *p=head;p;p=p->next)
  277. {
  278. Function *f;
  279. for (int k=0;(f=p->func.Enumerate(k))!=NULL;k++)
  280. {
  281. Profile &p=f->cur[which];
  282. if (p.callCount)
  283. {
  284. if (mixIndex<0)
  285. f->frame.Append(curFrame,p);
  286. else
  287. f->frame.MixIn(mixIndex,p);
  288. }
  289. p.caller.Clear();
  290. p.callCount=p.tickPure=p.tickTotal=0;
  291. }
  292. }
  293. }
  294. void ProfileFuncLevelTracer::ClearTotals(void)
  295. {
  296. ProfileFastCS::Lock lock(cs);
  297. for (ProfileFuncLevelTracer *p=head;p;p=p->next)
  298. {
  299. Function *f;
  300. for (int k=0;(f=p->func.Enumerate(k))!=NULL;k++)
  301. {
  302. f->glob.caller.Clear();
  303. f->glob.callCount=0;
  304. f->glob.tickPure=0;
  305. f->glob.tickTotal=0;
  306. }
  307. }
  308. }
  309. ProfileFuncLevelTracer::UnsignedMap::UnsignedMap(void):
  310. e(NULL), alloc(0), used(0), writeLock(false)
  311. {
  312. memset(hash,0,sizeof(hash));
  313. }
  314. ProfileFuncLevelTracer::UnsignedMap::~UnsignedMap()
  315. {
  316. Clear();
  317. }
  318. void ProfileFuncLevelTracer::UnsignedMap::Clear(void)
  319. {
  320. ProfileFreeMemory(e);
  321. e=NULL;
  322. alloc=used=0;
  323. memset(hash,0,sizeof(hash));
  324. }
  325. void ProfileFuncLevelTracer::UnsignedMap::_Insert(unsigned at, unsigned val, int countAdd)
  326. {
  327. DFAIL_IF(writeLock) return;
  328. // realloc list?
  329. if (used==alloc)
  330. {
  331. // must fixup pointers...
  332. unsigned delta=unsigned(e);
  333. e=(Entry *)ProfileReAllocMemory(e,((alloc+=64)*sizeof(Entry)));
  334. delta=unsigned(e)-delta;
  335. if (used&&delta)
  336. {
  337. for (unsigned k=0;k<HASH_SIZE;k++)
  338. if (hash[k])
  339. ((unsigned &)hash[k])+=delta;
  340. for (k=0;k<used;k++)
  341. if (e[k].next)
  342. ((unsigned &)e[k].next)+=delta;
  343. }
  344. }
  345. // add new item
  346. e[used].val=val;
  347. e[used].count=countAdd;
  348. e[used].next=hash[at];
  349. hash[at]=e+used++;
  350. }
  351. unsigned ProfileFuncLevelTracer::UnsignedMap::Enumerate(int index)
  352. {
  353. if (index<0||index>=(int)used)
  354. return 0;
  355. return e[index].val;
  356. }
  357. unsigned ProfileFuncLevelTracer::UnsignedMap::GetCount(int index)
  358. {
  359. if (index<0||index>=(int)used)
  360. return 0;
  361. return e[index].count;
  362. }
  363. void ProfileFuncLevelTracer::UnsignedMap::Copy(const UnsignedMap &src)
  364. {
  365. Clear();
  366. if (src.e)
  367. {
  368. alloc=used=src.used;
  369. e=(Entry *)ProfileAllocMemory(alloc*sizeof(Entry));
  370. memcpy(e,src.e,alloc*sizeof(Entry));
  371. writeLock=true;
  372. }
  373. }
  374. void ProfileFuncLevelTracer::UnsignedMap::MixIn(const UnsignedMap &src)
  375. {
  376. writeLock=false;
  377. for (unsigned k=0;k<src.used;k++)
  378. Insert(src.e[k].val,src.e[k].count);
  379. writeLock=true;
  380. }
  381. ProfileFuncLevelTracer::ProfileMap::ProfileMap(void):
  382. root(NULL), tail(&root)
  383. {
  384. }
  385. ProfileFuncLevelTracer::ProfileMap::~ProfileMap()
  386. {
  387. while (root)
  388. {
  389. List *next=root->next;
  390. root->~List();
  391. ProfileFreeMemory(root);
  392. root=next;
  393. }
  394. }
  395. ProfileFuncLevelTracer::Profile *ProfileFuncLevelTracer::ProfileMap::Find(int frame)
  396. {
  397. for (List *p=root;p&&p->frame<frame;p=p->next);
  398. return p&&p->frame==frame?&p->p:NULL;
  399. }
  400. void ProfileFuncLevelTracer::ProfileMap::Append(int frame, const Profile &p)
  401. {
  402. List *newEntry=(List *)ProfileAllocMemory(sizeof(List));
  403. new (newEntry) List;
  404. newEntry->frame=frame;
  405. newEntry->p.Copy(p);
  406. newEntry->next=NULL;
  407. *tail=newEntry;
  408. tail=&newEntry->next;
  409. }
  410. void ProfileFuncLevelTracer::ProfileMap::MixIn(int frame, const Profile &p)
  411. {
  412. // search correct list entry
  413. for (List *oldEntry=root;oldEntry;oldEntry=oldEntry->next)
  414. if (oldEntry->frame==frame)
  415. break;
  416. if (!oldEntry)
  417. Append(frame,p);
  418. else
  419. oldEntry->p.MixIn(p);
  420. }
  421. ProfileFuncLevelTracer::FunctionMap::FunctionMap(void):
  422. e(NULL), alloc(0), used(0)
  423. {
  424. memset(hash,0,sizeof(hash));
  425. }
  426. ProfileFuncLevelTracer::FunctionMap::~FunctionMap()
  427. {
  428. if (e)
  429. {
  430. for (unsigned k=0;k<used;k++)
  431. {
  432. e[k].funcPtr->~Function();
  433. ProfileFreeMemory(e[k].funcPtr);
  434. }
  435. ProfileFreeMemory(e);
  436. }
  437. }
  438. void ProfileFuncLevelTracer::FunctionMap::Insert(Function *funcPtr)
  439. {
  440. // realloc list?
  441. if (used==alloc)
  442. {
  443. // must fixup pointers...
  444. unsigned delta=unsigned(e);
  445. e=(Entry *)ProfileReAllocMemory(e,(alloc+=1024)*sizeof(Entry));
  446. delta=unsigned(e)-delta;
  447. if (used&&delta)
  448. {
  449. for (unsigned k=0;k<HASH_SIZE;k++)
  450. if (hash[k])
  451. ((unsigned &)hash[k])+=delta;
  452. for (k=0;k<used;k++)
  453. if (e[k].next)
  454. ((unsigned &)e[k].next)+=delta;
  455. }
  456. }
  457. // add to hash
  458. unsigned at=(funcPtr->addr/16)%HASH_SIZE;
  459. e[used].funcPtr=funcPtr;
  460. e[used].next=hash[at];
  461. hash[at]=e+used++;
  462. }
  463. ProfileFuncLevelTracer::Function *ProfileFuncLevelTracer::FunctionMap::Enumerate(int index)
  464. {
  465. if (index<0||index>=(int)used)
  466. return NULL;
  467. return e[index].funcPtr;
  468. }
  469. bool ProfileFuncLevel::IdList::Enum(unsigned index, Id &id, unsigned *countPtr) const
  470. {
  471. if (!m_ptr)
  472. return false;
  473. ProfileFuncLevelTracer::Profile &prof=*(ProfileFuncLevelTracer::Profile *)m_ptr;
  474. unsigned addr;
  475. if ((addr=prof.caller.Enumerate(index)))
  476. {
  477. id.m_funcPtr=prof.tracer->FindFunction(addr);
  478. if (countPtr)
  479. *countPtr=prof.caller.GetCount(index);
  480. return true;
  481. }
  482. else
  483. return false;
  484. }
  485. const char *ProfileFuncLevel::Id::GetSource(void) const
  486. {
  487. if (!m_funcPtr)
  488. return NULL;
  489. ProfileFuncLevelTracer::Function *func=(ProfileFuncLevelTracer::Function *)m_funcPtr;
  490. if (!func->funcSource)
  491. {
  492. char helpFunc[256],helpFile[256];
  493. unsigned ofsFunc;
  494. DebugStackwalk::Signature::GetSymbol(func->addr,
  495. NULL,0,NULL,
  496. helpFunc,sizeof(helpFunc),&ofsFunc,
  497. helpFile,sizeof(helpFile),&func->funcLine,NULL);
  498. char help[300];
  499. wsprintf(help,ofsFunc?"%s+0x%x":"%s",helpFunc,ofsFunc);
  500. func->funcSource=(char *)ProfileAllocMemory(strlen(helpFile)+1);
  501. strcpy(func->funcSource,helpFile);
  502. func->funcName=(char *)ProfileAllocMemory(strlen(help)+1);
  503. strcpy(func->funcName,help);
  504. }
  505. return func->funcSource;
  506. }
  507. const char *ProfileFuncLevel::Id::GetFunction(void) const
  508. {
  509. if (!m_funcPtr)
  510. return NULL;
  511. ProfileFuncLevelTracer::Function *func=(ProfileFuncLevelTracer::Function *)m_funcPtr;
  512. if (!func->funcSource)
  513. GetSource();
  514. return func->funcName;
  515. }
  516. unsigned ProfileFuncLevel::Id::GetAddress(void) const
  517. {
  518. if (!m_funcPtr)
  519. return 0;
  520. ProfileFuncLevelTracer::Function *func=(ProfileFuncLevelTracer::Function *)m_funcPtr;
  521. return func->addr;
  522. }
  523. unsigned ProfileFuncLevel::Id::GetLine(void) const
  524. {
  525. if (!m_funcPtr)
  526. return NULL;
  527. ProfileFuncLevelTracer::Function *func=(ProfileFuncLevelTracer::Function *)m_funcPtr;
  528. if (!func->funcSource)
  529. GetSource();
  530. return func->funcLine;
  531. }
  532. unsigned _int64 ProfileFuncLevel::Id::GetCalls(unsigned frame) const
  533. {
  534. if (!m_funcPtr)
  535. return 0;
  536. ProfileFuncLevelTracer::Function &func=*(ProfileFuncLevelTracer::Function *)m_funcPtr;
  537. switch(frame)
  538. {
  539. case Total:
  540. return func.glob.callCount;
  541. default:
  542. ProfileFuncLevelTracer::Profile *prof=func.frame.Find(frame);
  543. return prof?prof->callCount:0;
  544. }
  545. }
  546. unsigned _int64 ProfileFuncLevel::Id::GetTime(unsigned frame) const
  547. {
  548. if (!m_funcPtr)
  549. return 0;
  550. ProfileFuncLevelTracer::Function &func=*(ProfileFuncLevelTracer::Function *)m_funcPtr;
  551. switch(frame)
  552. {
  553. case Total:
  554. return func.glob.tickTotal;
  555. default:
  556. ProfileFuncLevelTracer::Profile *prof=func.frame.Find(frame);
  557. return prof?prof->tickTotal:0;
  558. }
  559. }
  560. unsigned _int64 ProfileFuncLevel::Id::GetFunctionTime(unsigned frame) const
  561. {
  562. if (!m_funcPtr)
  563. return 0;
  564. ProfileFuncLevelTracer::Function &func=*(ProfileFuncLevelTracer::Function *)m_funcPtr;
  565. switch(frame)
  566. {
  567. case Total:
  568. return func.glob.tickPure;
  569. default:
  570. ProfileFuncLevelTracer::Profile *prof=func.frame.Find(frame);
  571. return prof?prof->tickPure:0;
  572. }
  573. }
  574. ProfileFuncLevel::IdList ProfileFuncLevel::Id::GetCaller(unsigned frame) const
  575. {
  576. if (!m_funcPtr)
  577. return IdList();
  578. ProfileFuncLevelTracer::Function &func=*(ProfileFuncLevelTracer::Function *)m_funcPtr;
  579. IdList ret;
  580. switch(frame)
  581. {
  582. case Total:
  583. ret.m_ptr=&func.glob;
  584. break;
  585. default:
  586. ProfileFuncLevelTracer::Profile *prof=func.frame.Find(frame);
  587. if (prof)
  588. ret.m_ptr=prof;
  589. }
  590. return ret;
  591. }
  592. bool ProfileFuncLevel::Thread::EnumProfile(unsigned index, Id &id) const
  593. {
  594. if (!m_threadID)
  595. return false;
  596. ProfileFastCS::Lock lock(cs);
  597. ProfileFuncLevelTracer::Function *f=m_threadID->EnumFunction(index);
  598. if (f)
  599. {
  600. id.m_funcPtr=f;
  601. return true;
  602. }
  603. else
  604. return false;
  605. }
  606. bool ProfileFuncLevel::EnumThreads(unsigned index, Thread &thread)
  607. {
  608. ProfileFastCS::Lock lock(cs);
  609. for (ProfileFuncLevelTracer *p=ProfileFuncLevelTracer::GetFirst();p;p=p->GetNext())
  610. if (!index--)
  611. break;
  612. if (p)
  613. {
  614. thread.m_threadID=p;
  615. return true;
  616. }
  617. else
  618. return false;
  619. }
  620. ProfileFuncLevel::ProfileFuncLevel(void)
  621. {
  622. }
  623. #else // !defined HAS_PROFILE
  624. bool ProfileFuncLevel::IdList::Enum(unsigned index, Id &id, unsigned *) const
  625. {
  626. return false;
  627. }
  628. const char *ProfileFuncLevel::Id::GetSource(void) const
  629. {
  630. return NULL;
  631. }
  632. const char *ProfileFuncLevel::Id::GetFunction(void) const
  633. {
  634. return NULL;
  635. }
  636. unsigned ProfileFuncLevel::Id::GetAddress(void) const
  637. {
  638. return 0;
  639. }
  640. unsigned ProfileFuncLevel::Id::GetLine(void) const
  641. {
  642. return 0;
  643. }
  644. unsigned _int64 ProfileFuncLevel::Id::GetCalls(unsigned frame) const
  645. {
  646. return 0;
  647. }
  648. unsigned _int64 ProfileFuncLevel::Id::GetTime(unsigned frame) const
  649. {
  650. return 0;
  651. }
  652. unsigned _int64 ProfileFuncLevel::Id::GetFunctionTime(unsigned frame) const
  653. {
  654. return 0;
  655. }
  656. ProfileFuncLevel::IdList ProfileFuncLevel::Id::GetCaller(unsigned frame) const
  657. {
  658. return ProfileFuncLevel::IdList();
  659. }
  660. bool ProfileFuncLevel::Thread::EnumProfile(unsigned index, Id &id) const
  661. {
  662. return false;
  663. }
  664. bool ProfileFuncLevel::EnumThreads(unsigned index, Thread &thread)
  665. {
  666. return false;
  667. }
  668. ProfileFuncLevel::ProfileFuncLevel(void)
  669. {
  670. }
  671. #endif // !defined HAS_PROFILE
  672. ProfileFuncLevel ProfileFuncLevel::Instance;
  673. HANDLE ProfileFastCS::testEvent=::CreateEvent(NULL,FALSE,FALSE,"");