Profiler.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Profiler.cpp
  3. * ------------
  4. * Purpose: Performance measuring
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Profiler.h"
  11. OPENMPT_NAMESPACE_BEGIN
  12. #ifdef USE_PROFILER
  13. class Statistics
  14. {
  15. public:
  16. Profile &profile;
  17. Profile::Data data;
  18. double usage;
  19. Statistics(Profile &p) : profile(p)
  20. {
  21. usage = 0.0;
  22. Update();
  23. }
  24. void Update()
  25. {
  26. data = profile.GetAndResetData();
  27. uint64 now = profile.GetTime();
  28. uint64 timewindow = now - data.Start;
  29. if(data.Calls > 0 && timewindow > 0)
  30. {
  31. usage = (double)data.Sum / (double)timewindow;
  32. } else
  33. {
  34. usage = 0.0;
  35. }
  36. }
  37. };
  38. struct ProfileBlock
  39. {
  40. class Profile * profile;
  41. const char * name;
  42. class Statistics * stats;
  43. };
  44. static constexpr std::size_t MAX_PROFILES = 1024;
  45. static ProfileBlock Profiles[ MAX_PROFILES ];
  46. static std::size_t NextProfile = 0;
  47. static void RegisterProfile(Profile *newprofile)
  48. {
  49. if(NextProfile < MAX_PROFILES)
  50. {
  51. Profiles[NextProfile].profile = newprofile;
  52. Profiles[NextProfile].stats = 0;
  53. NextProfile++;
  54. }
  55. }
  56. static void UnregisterProfile(Profile *oldprofile)
  57. {
  58. for(std::size_t i=0; i<NextProfile; i++) {
  59. if(Profiles[i].profile == oldprofile) {
  60. Profiles[i].profile = 0;
  61. delete Profiles[i].stats;
  62. Profiles[i].stats = 0;
  63. }
  64. }
  65. }
  66. void Profiler::Update()
  67. {
  68. for(std::size_t i=0; i<NextProfile; i++)
  69. {
  70. if(!Profiles[i].stats)
  71. {
  72. Profiles[i].stats = new Statistics(*Profiles[i].profile);
  73. } else
  74. {
  75. Profiles[i].stats->Update();
  76. }
  77. }
  78. }
  79. std::string Profiler::DumpProfiles()
  80. {
  81. std::string ret;
  82. for(std::size_t i=0; i<NextProfile; i++)
  83. {
  84. if(Profiles[i].stats)
  85. {
  86. Statistics &stats = *Profiles[i].stats;
  87. std::string cat;
  88. switch(stats.profile.Category)
  89. {
  90. case Profiler::GUI: cat = "GUI"; break;
  91. case Profiler::Audio: cat = "Audio"; break;
  92. case Profiler::Notify: cat = "Notify"; break;
  93. }
  94. ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::afmt::right(6, mpt::afmt::fix(stats.usage * 100.0, 3)) + "%\r\n";
  95. }
  96. }
  97. ret += "\r\n";
  98. return ret;
  99. }
  100. std::vector<double> Profiler::DumpCategories()
  101. {
  102. std::vector<double> ret;
  103. ret.resize(Profiler::CategoriesCount);
  104. for(std::size_t i=0; i<NextProfile; i++)
  105. {
  106. if(Profiles[i].stats)
  107. {
  108. ret[Profiles[i].profile->Category] += Profiles[i].stats->usage;
  109. }
  110. }
  111. return ret;
  112. }
  113. uint64 Profile::GetTime() const
  114. {
  115. LARGE_INTEGER ret;
  116. ret.QuadPart = 0;
  117. QueryPerformanceCounter(&ret);
  118. return ret.QuadPart;
  119. }
  120. uint64 Profile::GetFrequency() const
  121. {
  122. LARGE_INTEGER ret;
  123. ret.QuadPart = 0;
  124. QueryPerformanceFrequency(&ret);
  125. return ret.QuadPart;
  126. }
  127. Profile::Profile(Profiler::Category category, const char *name) : Category(category), Name(name)
  128. {
  129. data.Calls = 0;
  130. data.Sum = 0;
  131. data.Overhead = 0;
  132. data.Start = GetTime();
  133. EnterTime = 0;
  134. RegisterProfile(this);
  135. }
  136. Profile::~Profile()
  137. {
  138. UnregisterProfile(this);
  139. }
  140. Profile::Data Profile::GetAndResetData()
  141. {
  142. Profile::Data ret;
  143. datamutex.lock();
  144. ret = data;
  145. data.Calls = 0;
  146. data.Sum = 0;
  147. data.Overhead = 0;
  148. data.Start = GetTime();
  149. datamutex.unlock();
  150. return ret;
  151. }
  152. void Profile::Reset()
  153. {
  154. datamutex.lock();
  155. data.Calls = 0;
  156. data.Sum = 0;
  157. data.Overhead = 0;
  158. data.Start = GetTime();
  159. datamutex.unlock();
  160. }
  161. void Profile::Enter()
  162. {
  163. EnterTime = GetTime();
  164. }
  165. void Profile::Leave()
  166. {
  167. uint64 LeaveTime = GetTime();
  168. datamutex.lock();
  169. data.Calls += 1;
  170. data.Sum += LeaveTime - EnterTime;
  171. datamutex.unlock();
  172. }
  173. #else // !USE_PROFILER
  174. MPT_MSVC_WORKAROUND_LNK4221(Profiler)
  175. #endif // USE_PROFILER
  176. OPENMPT_NAMESPACE_END