/*---------------------------------------------------------------------------* Project: NintendoWare File: dev_Profile.h Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #ifndef NW_DEV_PROFILE_H_ #define NW_DEV_PROFILE_H_ #include #include #include #include #include #if defined(NW_PLATFORM_CTR) #include #endif namespace nw { namespace dev { class AutoProfile; #ifdef NW_DEV_ENABLED //--------------------------------------------------------------------------- //! @brief プロファイル結果を保存するためのクラスです。 //--------------------------------------------------------------------------- class ProfileManager { private: NW_DISALLOW_COPY_AND_ASSIGN(ProfileManager); public: //! @brief プロファイル結果です。 struct Report { //! @brief コンストラクタです。 Report() : name(NULL), elapsedTime(0), callCount(0), maxElapsedTime(0), minElapsedTime(0), iCacheMiss(0), dCacheReadMiss(0), dCacheWriteMiss(0) {} const char* name; //!< プロファイルの名前です。 s64 elapsedTime; //!< 経過時間です。 s32 callCount; //!< 呼び出し回数です。 s64 maxElapsedTime; //!< 最大の経過時間です。 s64 minElapsedTime; //!< 最小の経過時間です。 u64 iCacheMiss; //!< 命令キャッシュミス数です。 u64 dCacheReadMiss; //!< データキャッシュリードミス数です。 u64 dCacheWriteMiss; //!< データキャッシュライトミス数です。 }; //! @brief ログの出力形式の定義です。 enum ExportFormat { CSV, //!< コンマ区切り形式です。 CHART //!< チャート形式です。 }; //! @brief ログの出力精度の定義です。 enum Accuracy { MILI_SECOND, //!< ミリセコンドです。 MICRO_SECOND //!< マイクロセコンドです。 }; //! @brief 計測を行う項目です。 enum Mode { NONE = 0x0, //!< 計測を行いません。 TIMER = 0x1 << 0, //!< タイマーです。 I_CACHE_MISS = 0x1 << 1, //!< 命令キャッシュミスです。 D_CACHE_READ_MISS = 0x1 << 2, //!< データキャッシュミスです。 D_CACHE_WRITE_MISS = 0x1 << 3 //!< データキャッシュミスです。 }; //! @brief 設定内容です。 struct Description { //! @brief コンストラクタです。 Description() : maxReport(DEFAULT_MAX_REPORT), exportFormat(CHART), accuracy(MILI_SECOND), mode(TIMER) {} s32 maxReport; //!< レポートの最大数です。 ExportFormat exportFormat; //!< 出力形式です。 Accuracy accuracy; //!< 出力精度です。 u32 mode; //!< 計測を行う項目です。 }; //! @brief プロファイルマネージャーを生成します。 //! //! @param[in] description 設定内容です。 //! @param[in] allocator アロケータです。 //! //! @return 生成されたプロファイルマネージャーです。 //! static ProfileManager* CreateProfileManager( ProfileManager::Description& description, os::IAllocator* allocator); //! @brief プロファイルマネージャーを破棄します。 //! //! @param[in] allocator アロケータです。 //! void Destroy(os::IAllocator* allocator); //---------------------------------------- //! @name 取得/設定 //@{ //! @brief マネージャーにレポートを追加します。 bool AddReport(const Report& report); //! @brief レポートを比較してマネージャーに追加します。 bool StoreReport(const Report& report); //! @brief 保存したレポートを削除します。 void ClearReports(); //! @brief レポートのリストを表します。 typedef ut::MoveArray ReportArray; //! @brief レポートのリストの範囲を表す型の定義です。 typedef std::pair< ReportArray::iterator, ReportArray::iterator> ReportRange; //! @brief レポートのリストの先頭と末尾を取得します。 ReportRange GetReports() { return std::make_pair( m_Reports.begin(), m_Reports.end()); } //! @brief レポートの数を取得します。 int GetReportCount() const { return m_Reports.size(); } //! @brief レポートの数を取得します。 int GetReportCapacity() const { return m_Reports.capacity(); } //! @brief 指定したインデックス番号のレポートを取得します。 Report GetReport(int index) { return m_Reports[index]; } const ProfileManager::Description& GetDescription() const { return m_Description; } //@} //! @brief レポートをコンソールに出力します。 void DumpReports(); private: static const int DEFAULT_MAX_REPORT = 50; //!< デフォルトの最大レポート数です。 static float TickToTime(s64 tick, float accuracy) { #ifdef NW_PLATFORM_CTR return static_cast(nn::os::Tick(tick).ToTimeSpan().GetNanoSeconds()) / accuracy; #else return static_cast(tick) / accuracy; #endif } ProfileManager( os::IAllocator* allocator, const ProfileManager::Description& description, ut::MoveArray reports); ~ProfileManager(); ProfileManager::Description m_Description; ut::MoveArray m_Reports; }; //--------------------------------------------------------------------------- //! @brief デストラクタで自動的にプロファイル結果を作成するクラスです。 //--------------------------------------------------------------------------- class AutoProfile { private: NW_DISALLOW_COPY_AND_ASSIGN(AutoProfile); public: //! @brief コンストラクタです。 AutoProfile(const char* name, ProfileManager* profileManager); //! @brief デストラクタです。 ~AutoProfile(); private: s64 GetTime(); ProfileManager* m_ProfileManager; ProfileManager::Report m_Report; s64 m_Time; u64 m_ICacheMiss; u64 m_DCacheReadMiss; u64 m_DCacheWriteMiss; }; //--------------------------------------------------------------------------- //! @brief ProfileManager を管理するクラスです。 //! ProfileCenter は必要に応じて作り直してください。 //--------------------------------------------------------------------------- class ProfileCenter { private: NW_DISALLOW_COPY_AND_ASSIGN(ProfileCenter); public: //! @brief プロファイルの管理クラスを初期化します。 static void Initialize(int maxReport, os::IAllocator* allocator); //! @brief プロファイルの管理クラスを削除します。 static void Finalize(os::IAllocator* allocator); //! @brief プロファイルマネージャーを設定します。 static void SetProfileManager(ProfileManager* profile) { ProfileCenter::GetInstance().SetProfileManagerInternal(profile); } //! @brief プロファイルマネージャーを取得します。 static ProfileManager* GetProfileManager() { return ProfileCenter::GetInstance().GetProfileManagerInternal(); } private: void SetProfileManagerInternal(ProfileManager* profileManager) { this->m_ProfileManager = profileManager; } ProfileManager* GetProfileManagerInternal() { return m_ProfileManager; } //! @brief インスタンスを取得します。 //! //! @return シングルトンのインスタンスを返します。 static ProfileCenter& GetInstance() { NW_NULL_ASSERT(m_Instance); return *m_Instance; } ProfileCenter() : m_ProfileManager(NULL) {} static ProfileCenter* m_Instance; ProfileManager* m_ProfileManager; }; #else class ProfileManager { struct Description { Description(){} }; enum ExportFormat { CSV, CHART }; enum Accuracy { MILI_SECOND, MICRO_SECOND }; enum Mode { NONE, TIMER, I_CACHE_MISS, D_CACHE_READ_MISS, D_CACHE_WRITE_MISS }; struct Report { Report(){} }; static ProfileManager singleton; ProfileManager* CreateProfileManager( ProfileManager::Description&, os::IAllocator*) { return &singleton; } void Destroy(os::IAllocator*){}; bool AddReport(Report){ return false; } bool StoreReport(Report){ return false; } void ClearReports(){} s64 GetProfileTime() const { return 0; } void SetProfileTime(s64) {} typedef ut::MoveArray ReportArray; typedef std::pair< ut::MoveArray::iterator, ut::MoveArray::iterator> ReportRange; ReportRange GetReports() { return ReportRange(); } int GetReportCount() const { return 0; } Report GetReport(int) { return Report(); } void DumpReports(){} private: ProfileManager(){} ~ProfileManager(){} private: }; class AutoProfile { public: AutoProfile(const char*, ProfileManager*){} ~AutoProfile(){} }; class ProfileCenter { public: static void Initialize(int, os::IAllocator*){} static void Finalize(os::IAllocator*){} static void SetProfileManager(ProfileManager*){} static ProfileManager* GetProfileManager() { return NULL; } }; #endif // NW_DEV_ENABLED // 非公開クラス。テスト用に間借り場所を間借り中。 namespace internal { template class StopWatch { public: //! @brief コンストラクタです。 StopWatch() { #if defined(NW_PLATFORM_CTR) nn::os::Tick startTick = nn::os::Tick::GetSystemCurrent(); nn::os::Tick endTick = nn::os::Tick::GetSystemCurrent(); m_OverHead = endTick - startTick; #endif } //! @brief 計測を開始します。 void Start() { #if defined(NW_PLATFORM_CTR) for (int i = 0; i <= MaxTag; ++i) { m_Ticks[ i ] = ::nn::os::Tick(0); } m_SplitTick = nn::os::Tick::GetSystemCurrent(); #endif } //! @brief 途中経過を記録します。 void Split(s32 tag = 0) { NW_ASSERT(tag < MaxTag); NW_UNUSED_VARIABLE(tag); #if defined(NW_PLATFORM_CTR) nn::os::Tick current = nn::os::Tick::GetSystemCurrent(); m_Ticks[ tag ] += current - m_SplitTick - m_OverHead; m_SplitTick = nn::os::Tick::GetSystemCurrent(); #endif } //! @brief 計測を停止します。 void Stop() { #if defined(NW_PLATFORM_CTR) nn::os::Tick prev = m_SplitTick; m_SplitTick = nn::os::Tick::GetSystemCurrent(); m_Ticks[ MaxTag ] += m_SplitTick - prev - m_OverHead; #endif } //! @brief 計測結果のレポートを出力します。 void Report() const { #if defined(NW_PLATFORM_CTR) nn::os::Tick total; for (int i = 0; i <= MaxTag; ++i) { total += m_Ticks[i]; if (static_cast(m_Ticks[i]) == 0) { continue; } if (i == MaxTag) { continue; } // MaxTag は予約タグ NW_DEV_LOG("%d : %6.2f us\n", i, static_cast( m_Ticks[i].ToTimeSpan().GetNanoSeconds() ) / 1000.0f ); } NW_DEV_LOG("Total : %6.2f us\n", static_cast( total.ToTimeSpan().GetNanoSeconds() ) / 1000.0f ); #endif } private: #if defined(NW_PLATFORM_CTR) ::nn::os::Tick m_Ticks[MaxTag + 1]; ::nn::os::Tick m_SplitTick; ::nn::os::Tick m_OverHead; #endif }; } // namespace internal } // namespace nw::dev } // namespace nw #endif // NW_DEV_PROFILE_H_