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