profile_cmd.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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_cmd.cpp $
  20. // $Author: mhoffe $
  21. // $Revision: #2 $
  22. // $DateTime: 2003/08/12 15:05:00 $
  23. //
  24. // ©2003 Electronic Arts
  25. //
  26. // Profile module command interface
  27. //////////////////////////////////////////////////////////////////////////////
  28. #include "_pch.h"
  29. unsigned ProfileCmdInterface::numResIf;
  30. ProfileCmdInterface::Factory *ProfileCmdInterface::resIf;
  31. void ProfileCmdInterface::AddResultFunction(ProfileResultInterface* (*func)(int, const char * const *),
  32. const char *name, const char *arg)
  33. {
  34. DFAIL_IF(!func) return;
  35. DFAIL_IF(!name) return;
  36. for (unsigned k=0;k<numResIf;k++)
  37. if (!strcmp(resIf[k].name,name))
  38. return;
  39. ++numResIf;
  40. resIf=(Factory *)ProfileReAllocMemory(resIf,numResIf*sizeof(Factory));
  41. resIf[numResIf-1].func=func;
  42. resIf[numResIf-1].name=name;
  43. resIf[numResIf-1].arg=arg;
  44. }
  45. void ProfileCmdInterface::RunResultFunctions(void)
  46. {
  47. // no result functions registered?
  48. if (!numResFunc)
  49. Debug::Command("profile.result file_csv");
  50. // process result interfaces
  51. for (unsigned k=0;k<numResFunc;k++)
  52. {
  53. resFunc[k]->WriteResults();
  54. resFunc[k]->Delete();
  55. }
  56. }
  57. bool ProfileCmdInterface::Execute(class Debug& dbg, const char *cmd, CommandMode cmdmode,
  58. unsigned argn, const char * const * argv)
  59. {
  60. // just for convenience...
  61. bool normalMode=cmdmode==CommandMode::Normal;
  62. if (!strcmp(cmd,"help"))
  63. {
  64. if (!normalMode)
  65. return true;
  66. if (!argn)
  67. {
  68. dbg << "profile group help:\n"
  69. " result, caller, clear, add, view\n";
  70. return true;
  71. }
  72. else if (!strcmp(argv[0],"result"))
  73. {
  74. dbg << "result\n\n"
  75. "Shows the list of available result functions and their\n"
  76. "optional parameters.\n"
  77. "\n"
  78. "result <res_func_name> [ <arg1> .. <argN> ]\n\n"
  79. "Adds the given result function to be executed on program\n"
  80. "exit.\n";
  81. }
  82. else if (!strcmp(argv[0],"caller"))
  83. {
  84. dbg << "caller [ (+|-) ]\n\n"
  85. "Enables/disables recording of caller information while\n"
  86. "performing function level profiling. Turned off by default\n"
  87. "since CPU hit is non-zero.\n";
  88. }
  89. else if (!strcmp(argv[0],"clear"))
  90. {
  91. dbg << "clear\n\n"
  92. "Clears the profile inclusion/exclusion list.\n";
  93. return true;
  94. }
  95. else if (!strcmp(argv[0],"add"))
  96. {
  97. dbg << "add (+|-) <pattern>\n"
  98. "\n"
  99. "Adds a pattern to the profile list. By default all\n"
  100. "profile ranges are disabled. Each new range is then checked\n"
  101. "against all pattern in this list. If a match is found the\n"
  102. "active/inactive state is modified accordingly (+ for active,\n"
  103. "- for inactive). The final state is always the last match.";
  104. return true;
  105. }
  106. else if (!strcmp(argv[0],"view"))
  107. {
  108. dbg << "view\n\n"
  109. "Shows the active pattern list.\n";
  110. return true;
  111. }
  112. return false;
  113. }
  114. // command: result
  115. if (!strcmp(cmd,"result"))
  116. {
  117. if (!argn)
  118. {
  119. for (unsigned k=0;k<numResIf;k++)
  120. {
  121. dbg << resIf[k].name;
  122. if ((resIf[k].arg&&*resIf[k].arg)||!normalMode)
  123. dbg << "\n " << resIf[k].arg;
  124. dbg << "\n";
  125. }
  126. }
  127. else
  128. {
  129. for (unsigned k=0;k<numResIf;k++)
  130. if (!strcmp(argv[0],resIf[k].name))
  131. break;
  132. if (k==numResIf)
  133. {
  134. dbg << "Unknown result function\n";
  135. return true;
  136. }
  137. ProfileResultInterface *newIf=resIf[k].func(argn-1,argv+1);
  138. if (!newIf)
  139. {
  140. dbg << "Could not add result function\n";
  141. return true;
  142. }
  143. ++numResFunc;
  144. resFunc=(ProfileResultInterface **)ProfileReAllocMemory(resFunc,numResFunc*sizeof(ProfileResultInterface *));
  145. resFunc[numResFunc-1]=newIf;
  146. if (normalMode)
  147. dbg << "Result function " << argv[0] << " added\n";
  148. }
  149. return true;
  150. }
  151. // command: caller
  152. if (!strcmp(cmd,"caller"))
  153. {
  154. #ifdef HAS_PROFILE
  155. if (argn)
  156. {
  157. if (*argv[0]=='+')
  158. ProfileFuncLevelTracer::recordCaller=true;
  159. if (*argv[0]=='-')
  160. ProfileFuncLevelTracer::recordCaller=false;
  161. }
  162. if (normalMode)
  163. dbg << "Record caller: " << (ProfileFuncLevelTracer::recordCaller?"on":"off");
  164. else
  165. dbg << (ProfileFuncLevelTracer::recordCaller?"1":"0");
  166. #endif
  167. return true;
  168. }
  169. // command: clear
  170. if (!strcmp(cmd,"clear"))
  171. {
  172. // remove some (or all) pattern
  173. const char *pattern=argn<1?"*":argv[0];
  174. for (Profile::PatternListEntry **entryPtr=&Profile::firstPatternEntry;*entryPtr;)
  175. {
  176. if (Profile::SimpleMatch((*entryPtr)->pattern,pattern))
  177. {
  178. // remove this entry
  179. Profile::PatternListEntry *cur=*entryPtr;
  180. *entryPtr=cur->next;
  181. ProfileFreeMemory(cur->pattern);
  182. ProfileFreeMemory(cur);
  183. }
  184. else
  185. entryPtr=&((*entryPtr)->next);
  186. }
  187. // must fixup lastPatternEntry now
  188. if (Profile::firstPatternEntry)
  189. {
  190. for (Profile::PatternListEntry *cur=Profile::firstPatternEntry;cur->next;cur=cur->next);
  191. Profile::lastPatternEntry=cur;
  192. }
  193. else
  194. Profile::lastPatternEntry=NULL;
  195. return true;
  196. }
  197. // command: add
  198. if (!strcmp(cmd,"add"))
  199. {
  200. // add a pattern
  201. if (argn<2)
  202. dbg << "Please specify mode and pattern";
  203. else
  204. {
  205. // alloc new pattern entry
  206. Profile::PatternListEntry *cur=(Profile::PatternListEntry *)
  207. ProfileAllocMemory(sizeof(Profile::PatternListEntry));
  208. // init
  209. cur->next=NULL;
  210. cur->isActive=*argv[0]=='+';
  211. cur->pattern=(char *)ProfileAllocMemory(strlen(argv[1])+1);
  212. strcpy(cur->pattern,argv[1]);
  213. // add to list
  214. if (Profile::lastPatternEntry)
  215. Profile::lastPatternEntry->next=cur;
  216. else
  217. Profile::firstPatternEntry=cur;
  218. Profile::lastPatternEntry=cur;
  219. }
  220. return true;
  221. }
  222. // command: view
  223. if (!strcmp(cmd,"view"))
  224. {
  225. // show list of defined patterns
  226. for (Profile::PatternListEntry *cur=Profile::firstPatternEntry;cur;cur=cur->next)
  227. dbg << (cur->isActive?"+ ":"- ") << cur->pattern << "\n";
  228. return true;
  229. }
  230. // unknown command
  231. return false;
  232. }