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