1 /*---------------------------------------------------------------------------* 2 Project: NintendoWare 3 File: dev_Profile.h 4 5 Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. 6 7 These coded instructions, statements, and computer programs contain 8 proprietary information of Nintendo of America Inc. and/or Nintendo 9 Company Ltd., and are protected by Federal copyright law. They may 10 not be disclosed to third parties or copied or duplicated in any form, 11 in whole or in part, without the prior written consent of Nintendo. 12 13 $Revision: 22001 $ 14 *---------------------------------------------------------------------------*/ 15 16 #ifndef NW_DEV_PROFILE_H_ 17 #define NW_DEV_PROFILE_H_ 18 19 #include <nw/types.h> 20 #include <nw/os/os_Memory.h> 21 #include <nw/ut/ut_Preprocessor.h> 22 #include <nw/ut/ut_MoveArray.h> 23 #include <nw/dev/dev_Utility.h> 24 25 #if defined(NW_PLATFORM_CTR) 26 #include <nn/os.h> 27 #endif 28 29 30 namespace nw 31 { 32 namespace dev 33 { 34 35 class AutoProfile; 36 37 #ifdef NW_DEV_ENABLED 38 39 //--------------------------------------------------------------------------- 40 //! @brief プロファイル結果を保存するためのクラスです。 41 //--------------------------------------------------------------------------- 42 class ProfileManager 43 { 44 private: 45 NW_DISALLOW_COPY_AND_ASSIGN(ProfileManager); 46 47 public: 48 //! @brief プロファイル結果です。 49 struct Report 50 { 51 //! @brief コンストラクタです。 ReportReport52 Report() 53 : name(NULL), 54 elapsedTime(0), 55 callCount(0), 56 maxElapsedTime(0), 57 minElapsedTime(0), 58 iCacheMiss(0), 59 dCacheReadMiss(0), 60 dCacheWriteMiss(0) 61 {} 62 63 const char* name; //!< プロファイルの名前です。 64 s64 elapsedTime; //!< 経過時間です。 65 s32 callCount; //!< 呼び出し回数です。 66 s64 maxElapsedTime; //!< 最大の経過時間です。 67 s64 minElapsedTime; //!< 最小の経過時間です。 68 u64 iCacheMiss; //!< 命令キャッシュミス数です。 69 u64 dCacheReadMiss; //!< データキャッシュリードミス数です。 70 u64 dCacheWriteMiss; //!< データキャッシュライトミス数です。 71 }; 72 73 //! @brief ログの出力形式の定義です。 74 enum ExportFormat 75 { 76 CSV, //!< コンマ区切り形式です。 77 CHART //!< チャート形式です。 78 }; 79 80 //! @brief ログの出力精度の定義です。 81 enum Accuracy 82 { 83 MILI_SECOND, //!< ミリセコンドです。 84 MICRO_SECOND //!< マイクロセコンドです。 85 }; 86 87 //! @brief 計測を行う項目です。 88 enum Mode 89 { 90 NONE = 0x0, //!< 計測を行いません。 91 TIMER = 0x1 << 0, //!< タイマーです。 92 I_CACHE_MISS = 0x1 << 1, //!< 命令キャッシュミスです。 93 D_CACHE_READ_MISS = 0x1 << 2, //!< データキャッシュミスです。 94 D_CACHE_WRITE_MISS = 0x1 << 3 //!< データキャッシュミスです。 95 }; 96 97 //! @brief 設定内容です。 98 struct Description 99 { 100 //! @brief コンストラクタです。 DescriptionDescription101 Description() 102 : maxReport(DEFAULT_MAX_REPORT), 103 exportFormat(CHART), 104 accuracy(MILI_SECOND), 105 mode(TIMER) 106 {} 107 108 s32 maxReport; //!< レポートの最大数です。 109 ExportFormat exportFormat; //!< 出力形式です。 110 Accuracy accuracy; //!< 出力精度です。 111 u32 mode; //!< 計測を行う項目です。 112 113 }; 114 115 //! @brief プロファイルマネージャーを生成します。 116 //! 117 //! @param[in] description 設定内容です。 118 //! @param[in] allocator アロケータです。 119 //! 120 //! @return 生成されたプロファイルマネージャーです。 121 //! 122 static ProfileManager* CreateProfileManager( 123 ProfileManager::Description& description, 124 os::IAllocator* allocator); 125 126 //! @brief プロファイルマネージャーを破棄します。 127 //! 128 //! @param[in] allocator アロケータです。 129 //! 130 void Destroy(os::IAllocator* allocator); 131 132 //---------------------------------------- 133 //! @name 取得/設定 134 //@{ 135 136 //! @brief マネージャーにレポートを追加します。 137 bool AddReport(const Report& report); 138 139 //! @brief レポートを比較してマネージャーに追加します。 140 bool StoreReport(const Report& report); 141 142 //! @brief 保存したレポートを削除します。 143 void ClearReports(); 144 145 //! @brief レポートのリストを表します。 146 typedef ut::MoveArray<Report> ReportArray; 147 148 //! @brief レポートのリストの範囲を表す型の定義です。 149 typedef std::pair< 150 ReportArray::iterator, 151 ReportArray::iterator> ReportRange; 152 153 //! @brief レポートのリストの先頭と末尾を取得します。 GetReports()154 ReportRange GetReports() 155 { 156 return std::make_pair( 157 m_Reports.begin(), 158 m_Reports.end()); 159 } 160 161 //! @brief レポートの数を取得します。 GetReportCount()162 int GetReportCount() const { return m_Reports.size(); } 163 164 //! @brief レポートの数を取得します。 GetReportCapacity()165 int GetReportCapacity() const { return m_Reports.capacity(); } 166 167 //! @brief 指定したインデックス番号のレポートを取得します。 GetReport(int index)168 Report GetReport(int index) 169 { 170 return m_Reports[index]; 171 } 172 GetDescription()173 const ProfileManager::Description& GetDescription() const { return m_Description; } 174 175 //@} 176 177 //! @brief レポートをコンソールに出力します。 178 void DumpReports(); 179 180 private: 181 static const int DEFAULT_MAX_REPORT = 50; //!< デフォルトの最大レポート数です。 182 TickToTime(s64 tick,float accuracy)183 static float TickToTime(s64 tick, float accuracy) 184 { 185 #ifdef NW_PLATFORM_CTR 186 return 187 static_cast<float>(nn::os::Tick(tick).ToTimeSpan().GetNanoSeconds()) / accuracy; 188 #else 189 return static_cast<float>(tick) / accuracy; 190 #endif 191 } 192 193 ProfileManager( 194 os::IAllocator* allocator, 195 const ProfileManager::Description& description, 196 ut::MoveArray<Report> reports); 197 198 ~ProfileManager(); 199 200 ProfileManager::Description m_Description; 201 ut::MoveArray<Report> m_Reports; 202 }; 203 204 //--------------------------------------------------------------------------- 205 //! @brief デストラクタで自動的にプロファイル結果を作成するクラスです。 206 //--------------------------------------------------------------------------- 207 class AutoProfile 208 { 209 private: 210 NW_DISALLOW_COPY_AND_ASSIGN(AutoProfile); 211 212 public: 213 //! @brief コンストラクタです。 214 AutoProfile(const char* name, ProfileManager* profileManager); 215 216 //! @brief デストラクタです。 217 ~AutoProfile(); 218 219 private: 220 s64 GetTime(); 221 222 ProfileManager* m_ProfileManager; 223 ProfileManager::Report m_Report; 224 s64 m_Time; 225 u64 m_ICacheMiss; 226 u64 m_DCacheReadMiss; 227 u64 m_DCacheWriteMiss; 228 }; 229 230 //--------------------------------------------------------------------------- 231 //! @brief ProfileManager を管理するクラスです。 232 //! ProfileCenter は必要に応じて作り直してください。 233 //--------------------------------------------------------------------------- 234 class ProfileCenter 235 { 236 private: 237 NW_DISALLOW_COPY_AND_ASSIGN(ProfileCenter); 238 239 public: 240 //! @brief プロファイルの管理クラスを初期化します。 241 static void Initialize(int maxReport, os::IAllocator* allocator); 242 243 //! @brief プロファイルの管理クラスを削除します。 244 static void Finalize(os::IAllocator* allocator); 245 246 //! @brief プロファイルマネージャーを設定します。 SetProfileManager(ProfileManager * profile)247 static void SetProfileManager(ProfileManager* profile) 248 { 249 ProfileCenter::GetInstance().SetProfileManagerInternal(profile); 250 } 251 252 //! @brief プロファイルマネージャーを取得します。 GetProfileManager()253 static ProfileManager* GetProfileManager() 254 { 255 return ProfileCenter::GetInstance().GetProfileManagerInternal(); 256 } 257 258 private: SetProfileManagerInternal(ProfileManager * profileManager)259 void SetProfileManagerInternal(ProfileManager* profileManager) 260 { 261 this->m_ProfileManager = profileManager; 262 } 263 GetProfileManagerInternal()264 ProfileManager* GetProfileManagerInternal() 265 { 266 return m_ProfileManager; 267 } 268 269 //! @brief インスタンスを取得します。 270 //! 271 //! @return シングルトンのインスタンスを返します。 GetInstance()272 static ProfileCenter& GetInstance() 273 { 274 NW_NULL_ASSERT(m_Instance); 275 return *m_Instance; 276 } 277 ProfileCenter()278 ProfileCenter() 279 : m_ProfileManager(NULL) 280 {} 281 282 static ProfileCenter* m_Instance; 283 ProfileManager* m_ProfileManager; 284 }; 285 286 #else 287 288 class ProfileManager 289 { 290 struct Description 291 { DescriptionDescription292 Description(){} 293 }; 294 295 enum ExportFormat 296 { 297 CSV, 298 CHART 299 }; 300 301 enum Accuracy 302 { 303 MILI_SECOND, 304 MICRO_SECOND 305 }; 306 307 enum Mode 308 { 309 NONE, 310 TIMER, 311 I_CACHE_MISS, 312 D_CACHE_READ_MISS, 313 D_CACHE_WRITE_MISS 314 }; 315 316 struct Report 317 { ReportReport318 Report(){} 319 }; 320 321 static ProfileManager singleton; CreateProfileManager(ProfileManager::Description &,os::IAllocator *)322 ProfileManager* CreateProfileManager( 323 ProfileManager::Description&, 324 os::IAllocator*) 325 { 326 return &singleton; 327 } 328 Destroy(os::IAllocator *)329 void Destroy(os::IAllocator*){}; 330 AddReport(Report)331 bool AddReport(Report){ return false; } 332 StoreReport(Report)333 bool StoreReport(Report){ return false; } 334 ClearReports()335 void ClearReports(){} 336 GetProfileTime()337 s64 GetProfileTime() const { return 0; } 338 SetProfileTime(s64)339 void SetProfileTime(s64) {} 340 341 typedef ut::MoveArray<Report> ReportArray; 342 343 typedef std::pair< 344 ut::MoveArray<Report>::iterator, 345 ut::MoveArray<Report>::iterator> ReportRange; 346 GetReports()347 ReportRange GetReports() 348 { 349 return ReportRange(); 350 } 351 GetReportCount()352 int GetReportCount() const { return 0; } 353 GetReport(int)354 Report GetReport(int) { return Report(); } 355 DumpReports()356 void DumpReports(){} 357 358 private: ProfileManager()359 ProfileManager(){} ~ProfileManager()360 ~ProfileManager(){} 361 362 private: 363 }; 364 365 class AutoProfile 366 { 367 public: AutoProfile(const char *,ProfileManager *)368 AutoProfile(const char*, ProfileManager*){} ~AutoProfile()369 ~AutoProfile(){} 370 }; 371 372 class ProfileCenter 373 { 374 public: 375 Initialize(int,os::IAllocator *)376 static void Initialize(int, os::IAllocator*){} 377 Finalize(os::IAllocator *)378 static void Finalize(os::IAllocator*){} 379 SetProfileManager(ProfileManager *)380 static void SetProfileManager(ProfileManager*){} 381 GetProfileManager()382 static ProfileManager* GetProfileManager() { return NULL; } 383 }; 384 385 #endif // NW_DEV_ENABLED 386 387 // 非公開クラス。テスト用に間借り場所を間借り中。 388 namespace internal { 389 390 template <int MaxTag> 391 class StopWatch 392 { 393 public: 394 //! @brief コンストラクタです。 StopWatch()395 StopWatch() 396 { 397 #if defined(NW_PLATFORM_CTR) 398 nn::os::Tick startTick = nn::os::Tick::GetSystemCurrent(); 399 nn::os::Tick endTick = nn::os::Tick::GetSystemCurrent(); 400 m_OverHead = endTick - startTick; 401 #endif 402 } 403 404 //! @brief 計測を開始します。 Start()405 void Start() 406 { 407 #if defined(NW_PLATFORM_CTR) 408 for (int i = 0; i <= MaxTag; ++i) 409 { 410 m_Ticks[ i ] = ::nn::os::Tick(0); 411 } 412 m_SplitTick = nn::os::Tick::GetSystemCurrent(); 413 #endif 414 } 415 416 //! @brief 途中経過を記録します。 417 void Split(s32 tag = 0) 418 { 419 NW_ASSERT(tag < MaxTag); 420 NW_UNUSED_VARIABLE(tag); 421 422 #if defined(NW_PLATFORM_CTR) 423 nn::os::Tick current = nn::os::Tick::GetSystemCurrent(); 424 m_Ticks[ tag ] += current - m_SplitTick - m_OverHead; 425 m_SplitTick = nn::os::Tick::GetSystemCurrent(); 426 #endif 427 } 428 429 //! @brief 計測を停止します。 Stop()430 void Stop() 431 { 432 #if defined(NW_PLATFORM_CTR) 433 nn::os::Tick prev = m_SplitTick; 434 m_SplitTick = nn::os::Tick::GetSystemCurrent(); 435 m_Ticks[ MaxTag ] += m_SplitTick - prev - m_OverHead; 436 #endif 437 } 438 439 //! @brief 計測結果のレポートを出力します。 Report()440 void Report() const 441 { 442 #if defined(NW_PLATFORM_CTR) 443 444 nn::os::Tick total; 445 446 for (int i = 0; i <= MaxTag; ++i) 447 { 448 total += m_Ticks[i]; 449 450 if (static_cast<s64>(m_Ticks[i]) == 0) { continue; } 451 if (i == MaxTag) { continue; } // MaxTag は予約タグ 452 453 NW_DEV_LOG("%d : %6.2f us\n", i, static_cast<float>( m_Ticks[i].ToTimeSpan().GetNanoSeconds() ) / 1000.0f ); 454 } 455 456 NW_DEV_LOG("Total : %6.2f us\n", static_cast<float>( total.ToTimeSpan().GetNanoSeconds() ) / 1000.0f ); 457 #endif 458 } 459 460 private: 461 #if defined(NW_PLATFORM_CTR) 462 ::nn::os::Tick m_Ticks[MaxTag + 1]; 463 ::nn::os::Tick m_SplitTick; 464 ::nn::os::Tick m_OverHead; 465 #endif 466 }; 467 } // namespace internal 468 469 470 } // namespace nw::dev 471 } // namespace nw 472 473 #endif // NW_DEV_PROFILE_H_ 474