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