1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_Stopwatch.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_LYT_STOPWATCH_H_
19 #define NW_LYT_STOPWATCH_H_
20 
21 #include <climits>
22 #include <math.h>
23 #include <nw/sdk.h>
24 #include <nw/ut/ut_LinkList.h>
25 
26 #ifdef NW_PLATFORM_CTR
27 #include <nn/os/os_Tick.h>
28 #endif
29 
30 namespace nw {
31 namespace lyt {
32 namespace internal {
33 
34 #define NW_LYT_PROFILE 1
35 
36 #ifdef NW_LYT_PROFILE
37 #  define NW_LYT_JOIN(x, y) NW_LYT_JOIN_AGAIN(x, y)
38 #  define NW_LYT_JOIN_AGAIN(x, y) x ## y
39 
40 #  define NW_LYT_STOPWATCH_MEASURE(no, label) \
41     nw::lyt::internal::Measure NW_LYT_JOIN(measure, __LINE__) ( \
42         nw::lyt::internal::Stopwatch::Instance<no>(label), no)
43 
44 #  define NW_LYT_STOPWATCH_START(no, label) \
45     if(nw::lyt::internal::Stopwatch::IsTarget(no)) \
46         nw::lyt::internal::Stopwatch::Instance<no>().Start(label)
47 
48 #  define NW_LYT_STOPWATCH_STOP(no) \
49     if(nw::lyt::internal::Stopwatch::IsTarget(no)) \
50         nw::lyt::internal::Stopwatch::Instance<no>().Stop()
51 #else
52 #  define NW_LYT_STOPWATCH_MEASURE(no, label)
53 #  define NW_LYT_STOPWATCH_START(no, label)
54 #  define NW_LYT_STOPWATCH_STOP(no)
55 #endif
56 
57 #ifdef NW_PLATFORM_CTR
58 using nn::fnd::TimeSpan;
59 using nn::os::Tick;
60 #endif
61 
62 //---------------------------------------------------------------------------
63 //! 経過時間を計測します。
64 //---------------------------------------------------------------------------
65 class Stopwatch : public nw::ut::LinkListNode
66 {
67 public:
68     static const s64 S64_MAX = (s64)(((u64)-1) >> 1);
69 
70     //! インスタンスを保持するリストです。
71     typedef nw::ut::LinkList<Stopwatch, 0> List;
72 
73     //! @brief コンストラクタです。
74     Stopwatch(int no = 0, const char* label = NULL);
75 
76     //! @brief 計測を開始します。
77     //!
78     //! @param label  計測対象を示すラベルを指定できます。
79     //!
80     void Start(const char* label = NULL)
81     {
82 #ifndef NW_PLATFORM_CTR
83         NW_UNUSED_VARIABLE(label)
84 #else
85         if (label != NULL)
86         {
87             this->SetLabel(label);
88         }
89 
90         NW_ASSERT(!this->IsRunning());
91 
92         m_StartTick = Tick::GetSystemCurrent();
93 #endif
94     }
95 
96     //! @brief 計測を停止します。
Stop()97     void Stop()
98     {
99 #ifdef NW_PLATFORM_CTR
100         Tick stopTick = Tick::GetSystemCurrent();
101 
102         NW_ASSERT(this->IsRunning());
103 
104         Tick elapsed = stopTick - m_StartTick;
105         m_StartTick = Tick();
106 
107         if (s64(elapsed) < m_MinSample)
108         {
109             m_MinSample = s64(elapsed);
110         }
111 
112         if (s64(elapsed) > m_MaxSample)
113         {
114             m_MaxSample = s64(elapsed);
115         }
116 
117         m_TotalTick += elapsed;
118         ++m_Count;
119 #endif
120     }
121 
122     void Reset();
123 
124     static void ResetAll();
125 
126     //! @brief 番号を設定します。
SetNo(int no)127     void SetNo(int no)
128     {
129 #ifndef NW_PLATFORM_CTR
130         NW_UNUSED_VARIABLE(no);
131 #else
132         m_No = no;
133 #endif
134     }
135 
136     //! @brief ラベルを設定します。
SetLabel(const char * label)137     void SetLabel(const char* label)
138     {
139 #ifndef NW_PLATFORM_CTR
140         NW_UNUSED_VARIABLE(label);
141 #else
142         m_Label = label;
143 #endif
144     }
145 
146 #ifdef NW_PLATFORM_CTR
147     //! @brief 計測中か調べます。
IsRunning()148     bool IsRunning() const
149     {
150         return m_StartTick != Tick();
151     }
152 
153     //! @brief 番号を取得します。
GetNo()154     int GetNo() const
155     {
156         return m_No;
157     }
158 
159     //! @brief ラベルを取得します。
GetLabel()160     const char* GetLabel() const
161     {
162         return m_Label;
163     }
164 
165     //! @brief 経過時間の合計を取得します。
GetElapsedTime()166     const TimeSpan GetElapsedTime() const
167     {
168         return m_TotalTick;
169     }
170 
171     //! @brief 測定回数を取得します。
GetCount()172     int GetCount() const
173     {
174         return m_Count;
175     }
176 
177     //! @brief 最小値のサンプルを取得します。
GetMinSample()178     TimeSpan GetMinSample() const
179     {
180         if (m_Count == 0)
181         {
182             return Tick(0).ToTimeSpan();
183         }
184         else
185         {
186             return Tick(m_MinSample).ToTimeSpan();
187         }
188     }
189 
190     //! @brief 最大値のサンプルを取得します。
GetMaxSample()191     TimeSpan GetMaxSample() const
192     {
193         if (m_Count == 0)
194         {
195             return Tick(0).ToTimeSpan();
196         }
197         else
198         {
199             return Tick(m_MaxSample).ToTimeSpan();
200         }
201     }
202 #endif
203 
204     //! @brief インスタンスを取得します。
205     //!
206     //! @tparam no  計測対象に固有の番号を指定します。
207     //! @param label  計測対象を示すラベルが指定できます。
208     //!
209     template <int no>
210     static Stopwatch& Instance(const char* label = NULL)
211     {
212         static Stopwatch obj(no);
213 
214         if (label != NULL)
215         {
216             obj.SetLabel(label);
217         }
218 
219         return obj;
220     }
221 
222     //! @brief インスタンスのリストを取得します。
GetList()223     static List& GetList()
224     {
225         static List list;
226         return list;
227     }
228 
229     //! @brief 計測を有効にします。
230     //! @details
231     //! SetTargetNo() で全インスタンス番号を指定するのと等価です。
232     static void Enable();
233 
234     //! @brief 計測を無効にします。
235     //! @details
236     //! SetTargetNo() で min > max を指定するのと等価です。
237     static void Disable();
238 
239     //! @brief インスタンス番号が計測対象かどうかを判定します。
IsTarget(int no)240     static bool IsTarget(int no)
241     {
242         return s_TargetNoMin <= no && no <= s_TargetNoMax;
243     }
244 
245     //! @brief 計測対象とするインスタンス番号の範囲を設定します。
SetTargetNo(int min,int max)246     static void SetTargetNo(int min, int max)
247     {
248         s_TargetNoMin = min;
249         s_TargetNoMax = max;
250     }
251 
252     //! @brief 計測対象とするインスタンス番号を設定します。
SetTargetNo(int no)253     static void SetTargetNo(int no)
254     {
255         SetTargetNo(no, no);
256     }
257 
258     //! @brief 計測結果をコンソールに出力します。
259     static void Dump(const Stopwatch& stopwatch);
260 
261     //! @brief すべての計測結果をコンソールに出力します。
262     static void Dump();
263 
264     //! @brief 計測結果のヘッダを出力します。
265     static void DumpHeader();
266 
267 protected:
268 #ifdef NW_PLATFORM_CTR
269     //! @details :private
270     int m_Count;
271 
272     //! @details :private
273     int m_No;
274 
275     //! @details :private
276     const char* m_Label;
277 
278     //! @details :private
279     Tick m_TotalTick;
280 
281     //! @details :private
282     Tick m_StartTick;
283 
284     //! @details :private
285     s64 m_MinSample;
286 
287     //! @details :private
288     s64 m_MaxSample;
289 #endif
290 
291     //! @details :private
292     static int s_TargetNoMin;
293 
294     //! @details :private
295     static int s_TargetNoMax;
296 };
297 
298 //---------------------------------------------------------------------------
299 //! 計測の開始と終了を自動化します。
300 //---------------------------------------------------------------------------
301 class Measure
302 {
303 public:
Measure(Stopwatch & stopwatch,int no)304     Measure(Stopwatch& stopwatch, int no)
305       : m_Stopwatch(stopwatch)
306     {
307 #ifdef NW_PLATFORM_CTR
308         if(Stopwatch::IsTarget(no))
309         {
310             m_Stopwatch.Start();
311         }
312 #endif
313     }
314 
~Measure()315     ~Measure()
316     {
317 #ifdef NW_PLATFORM_CTR
318         if(m_Stopwatch.IsRunning())
319         {
320             m_Stopwatch.Stop();
321         }
322 #endif
323     }
324 
325 protected:
326     //! @details :private
327     Stopwatch& m_Stopwatch;
328 };
329 
330 } // namespace internal
331 } // namespace lyt
332 } // namespace nw
333 
334 #endif // NW_LYT_STOPWATCH_H_
335