Main Page Modules Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

# deProfile.hpp

Go to the documentation of this file.

    00001 ///////////////////////////////////////////////////////////////////////////////
    00002 /// @file deProfile.hpp
    00003 ///
    00004 /// @brief Real-time profiling class and manager
    00005 ///
    00006 /// @author Assassin
    00007 ///
    00008 /// This file is the intellectual property of Novus Delta, LLC.. Usage of the
    00009 /// contents of this file is subject to the Destiny3D Member License which
    00010 /// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
    00011 ///
    00012 /// This file is distributed "AS IS" without warranty of any kind.  Novus
    00013 /// Delta, LLC. does not guarantee the fitness of the contents of this file
    00014 /// for any particular purpose.
    00015 ///
    00016 /// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
    00017 ///
    00018 /// <hr>
    00019 ///                                 Change History
    00020 /// <hr>
    00021 ///
    00022 /// @date Sept 2002
    00023 /// @author Assassin
    00024 /// @remarks Creation
    00025 ///
    00026 /// @date May 2003
    00027 /// @author Assassin
    00028 /// @remarks Updates for enhanced feedback
    00029 ///
    00030 ///////////////////////////////////////////////////////////////////////////////
    00031
    00032 #ifndef DEPROFILE_HPP
    00033 #define DEPROFILE_HPP
    00034
    00035 #include "deGlobalTypes.hpp"
    00036
    00037 #if defined(DEUTIL_DLL_EXPORTS) || defined(DESTINY3D_EXPORT_ALL)
    00038 #   define DEPROFILE_API extern "C" DEDLL_EXPORT
    00039 #elif defined(DESTINY3D_STATIC_LINK)
    00040 #   define DEPROFILE_API extern "C"
    00041 #else
    00042 #   define DEPROFILE_API extern "C" DEDLL_IMPORT
    00043 #endif
    00044
    00045 #ifdef USING_DESTINY3D
    00046 #ifdef _DEBUG
    00047 #   ifdef DESTINY3D_STATIC_LINK
    00048 #       pragma comment(lib, "deUtil_sd")
    00049 #   else
    00050 #       pragma comment(lib, "deUtild")
    00051 #   endif //DESTINY3D_STATIC_LINK
    00052 #else
    00053 #   ifdef DESTINY3D_STATIC_LINK
    00054 #       pragma comment(lib, "deUtil_s")
    00055 #   else
    00056 #       pragma comment(lib, "deUtil")
    00057 #   endif //DESTINY3D_STATIC_LINK
    00058 #endif //_DEBUG
    00059 #endif //USING_DESTINY3D
    00060
    00061 static inline void GrabTSC(u64 * Clock)
    00062 {
    00063 #ifdef __GNUC__
    00064     __asm__ __volatile__ ( \
    00065                 "rdtsc\n\t"    \
    00066                 : "=A" (Clock));
    00067 #else
    00068     _asm
    00069     {
    00070         RDTSC
    00071         mov  ecx,   Clock
    00072         mov [ecx],  eax
    00073         mov [ecx+4],edx
    00074     }
    00075 #endif
    00076 }
    00077
    00078 class deProfile;
    00079 class IdeProfileManager;
    00080
    00081 // factory functions
    00082     DEPROFILE_API IdeProfileManager*    IdeProfile_GetTheManager();
    00083     DEPROFILE_API void                  IdeProfile_ShutDown();
    00084
    00085 //class IdeProfileManager
    00086 DE3D_INTERFACE_(IdeProfileManager)
    00087 {
    00088 public:
    00089     virtual void        StartProfile(deProfile * profile) = 0;
    00090     virtual deBoolean   RecordInfo(deProfile * profile) = 0;
    00091     virtual long        GrabIDNum() = 0;
    00092     virtual long        EstimateFrequency() = 0;
    00093     virtual s64         TimeSpentIn(char * ProfileName, long IDNum = 0) = 0;
    00094     virtual s64         TimeSpentIn_IDByName(char * Name) = 0;
    00095     virtual const char* EndFrame(deBoolean OutputString) = 0;
    00096     virtual void        ResetStats() = 0;
    00097 };
    00098
    00099 /// Utility class for automatically profiling the time spent in a given variable scope.
    00100 /// Will count the number of cycles executed by the CPU between time of creation and destruction.
    00101 class deProfile
    00102 {
    00103 public:
    00104     friend class deProfileManager;
    00105
    00106     inline deProfile::deProfile(char * ProfileName)
    00107     {
    00108         if (!ProfileName)
    00109             throw "You must specify a name";
    00110         TheManager = IdeProfile_GetTheManager();
    00111         strncpy(m_ProfileInfo.IDName, ProfileName, 127);
    00112         m_ProfileInfo.IDName[127] = '\0';
    00113         m_ProfileInfo.IDNum = 0;
    00114         TheManager->StartProfile(this);
    00115     }
    00116
    00117     inline deProfile::deProfile(long * ProfileIDNum)
    00118     {
    00119         // first time, set it to 0 and it will grab an ID
    00120         // then it will look up the right entry each time;
    00121         TheManager = IdeProfile_GetTheManager();
    00122         if (*ProfileIDNum)
    00123         {
    00124             m_ProfileInfo.IDNum = *ProfileIDNum;
    00125         }
    00126         else
    00127         {
    00128             m_ProfileInfo.IDNum = TheManager->GrabIDNum();
    00129             *ProfileIDNum = m_ProfileInfo.IDNum;
    00130         }
    00131         m_ProfileInfo.IDName[0] = '\0';
    00132         TheManager->StartProfile(this);
    00133     }
    00134
    00135     inline deProfile::deProfile(long * ProfileIDNum, char * ProfileName)
    00136     {
    00137         TheManager = IdeProfile_GetTheManager();
    00138         if (*ProfileIDNum)
    00139         {
    00140             m_ProfileInfo.IDNum = *ProfileIDNum;
    00141         }
    00142         else
    00143         {
    00144             m_ProfileInfo.IDNum = TheManager->GrabIDNum();
    00145             *ProfileIDNum = m_ProfileInfo.IDNum;
    00146         }
    00147
    00148         if (!ProfileName)
    00149             throw;
    00150         strncpy(m_ProfileInfo.IDName, ProfileName, 127);
    00151         m_ProfileInfo.IDName[127] = '\0';
    00152         TheManager->StartProfile(this);
    00153     }
    00154
    00155     inline deProfile::~deProfile()
    00156     {
    00157         TheManager->RecordInfo(this);
    00158     }
    00159
    00160 private:
    00161     struct ProfileInfo_t
    00162     {
    00163         u32 IDNum;
    00164         char IDName[128];
    00165     } m_ProfileInfo;
    00166     IdeProfileManager * TheManager;
    00167 };
    00168
    00169
    00170 #ifdef DESTINY3D_PLATFORM_WIN32
    00171 #   define WIN32_LEAN_AND_MEAN
    00172 #   include <windows.h>
    00173 #   include <mmsystem.h>
    00174 #   pragma comment(lib, "winmm")
    00175 // simple class for reading QueryPerformanceCounter times
    00176 // problems:
    00177 // - multiprocessor systems: may be inconsistent across CPUs;
    00178 // setting thread affinity is too much work.
    00179 // - if implemented with TSC: same problems as above.
    00180 // (we check if TSC/QPC freqs differ by more than 10% -
    00181 // can't assume PIT / PMT freq values, because new the new HPET
    00182 // timer's frequency is unspecified)
    00183 // - Q274323: jumps several seconds under heavy PCI bus load.
    00184 // readings are checked against system time and discarded if invalid.
    00185 // - "System clock problem can inflate benchmark scores":
    00186 // invalid value if not polled every 4.5 seconds? solved
    00187 // by calibration thread, which reads timer every second anyway.
    00188 class deTimer_QPC
    00189 {
    00190     s64 m_StartTime;
    00191     s64 m_StopTime;
    00192     s64 m_Frequency;
    00193 public:
    00194     inline deTimer_QPC() : m_StartTime(0), m_StopTime(0), m_Frequency(0) {}
    00195     inline ~deTimer_QPC() {}
    00196     inline void GrabStartTime()
    00197     {
    00198         if (!QueryPerformanceCounter((LARGE_INTEGER*)&m_StartTime))
    00199             throw "QPC Unsupported!";
    00200     }
    00201     inline void GrabStopTime()
    00202     {
    00203         if (!QueryPerformanceCounter((LARGE_INTEGER*)&m_StopTime))
    00204             throw "QPC Unsupported!";
    00205     }
    00206     inline double DiffTime()
    00207     {
    00208         if (m_Frequency == 0)
    00209             QueryPerformanceFrequency((LARGE_INTEGER*)&m_Frequency);
    00210         double retval = (m_StopTime-m_StartTime)/((double)m_Frequency);
    00211         return retval;
    00212     }
    00213     inline double DiffTime(double maxStep)
    00214     {
    00215         double retval = DiffTime();
    00216         if (maxStep > 0 && retval > maxStep)
    00217             retval = maxStep;
    00218         return retval;
    00219     }
    00220 };
    00221
    00222 class deTimer_TGT
    00223 {
    00224     u32 m_StartTime;
    00225     u32 m_StopTime;
    00226 public:
    00227     inline deTimer_TGT() : m_StartTime(0), m_StopTime(0) {}
    00228     inline ~deTimer_TGT() {}
    00229     inline void GrabStartTime()
    00230     {
    00231         timeBeginPeriod(1);
    00232         m_StartTime = timeGetTime();
    00233         timeEndPeriod(1);
    00234     }
    00235     inline void GrabStopTime()
    00236     {
    00237         timeBeginPeriod(1);
    00238         m_StopTime = timeGetTime();
    00239         timeEndPeriod(1);
    00240     }
    00241     inline double DiffTime()
    00242     {
    00243         double retval = (m_StopTime-m_StartTime)/1000.0;
    00244         return retval;
    00245     }
    00246     inline double DiffTime(double maxStep)
    00247     {
    00248         double retval = DiffTime();
    00249         if (maxStep > 0 && retval > maxStep)
    00250             retval = maxStep;
    00251         return retval;
    00252     }
    00253 };
    00254 #else // DESTINY3D_PLATFORM_WIN32
    00255 #   pragma note(Unsupported platform for QPC and TGT timer - deferring to TSC)
    00256 #   define DE3D_TIMER_TSC
    00257 #endif // DESTINY3D_PLATFORM_WIN32
    00258
    00259 // very simple class for reading TSC times
    00260 // problems:
    00261 // - multiprocessor systems: may be inconsistent across CPUs;
    00262 // setting thread affinity is too much work.
    00263 // - deep sleep modes: TSC may not be advanced.
    00264 // - SpeedStep/'gearshift' CPUs: frequency may change.
    00265 // this happens on notebooks now, but eventually desktop systems
    00266 // will do this as well (if not to save power, for heat reasons).
    00267 class deTimer_TSC
    00268 {
    00269     u64 m_StartTime;
    00270     u64 m_StopTime;
    00271     double m_CPU_Hz;
    00272 public:
    00273     inline deTimer_TSC() : m_StartTime(0), m_StopTime(0), m_CPU_Hz(0.0) {}
    00274     inline ~deTimer_TSC() {}
    00275     inline void GrabStartTime()
    00276     { GrabTSC(&m_StartTime); }
    00277     inline void GrabStopTime()
    00278     { GrabTSC(&m_StopTime); }
    00279     inline double DiffTime()
    00280     {
    00281         if (m_CPU_Hz == 0.0)
    00282             m_CPU_Hz = 1000000.0 * IdeProfile_GetTheManager()->EstimateFrequency();
    00283         double retval = (m_StopTime-m_StartTime)/m_CPU_Hz;
    00284         return retval;
    00285     }
    00286     inline double DiffTime(double maxStep)
    00287     {
    00288         double retval = DiffTime();
    00289         if (maxStep > 0 && retval > maxStep)
    00290             retval = maxStep;
    00291         return retval;
    00292     }
    00293 };
    00294
    00295
    00296 //#define DE3D_TIMER_TSC
    00297 #define DE3D_TIMER_QPC
    00298 //#define DE3D_TIMER_TGT
    00299
    00300 #if defined(DE3D_TIMER_TSC)
    00301     typedef deTimer_TSC deTimer;
    00302 #elif defined(DE3D_TIMER_QPC)
    00303     typedef deTimer_QPC deTimer;
    00304 #elif defined(DE3D_TIMER_TGT)
    00305     typedef deTimer_TGT deTimer;
    00306 #endif // DE3D_TIMER_QPC
    00307
    00308 #undef DE3D_TIMER_TSC
    00309 #undef DE3D_TIMER_QPC
    00310 #undef DE3D_TIMER_TGT
    00311
    00312 #define PROFILE_RELEASE_ALSO
    00313
    00314 #if defined(_DEBUG) || defined(PROFILE_RELEASE_ALSO)
    00315     #define PROFILE(ProfileID) deProfile Profile_Identifier___(ProfileID)
    00316     #define PROFILE_ID_NAME(ProfileID,Name) deProfile Profile_Identifier___(ProfileID,Name)
    00317 #else
    00318     #define PROFILE(ProfileID)
    00319     #define PROFILE_ID_NAME(ProfileID,Name)
    00320 #endif
    00321
    00322
    00323 #endif