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