[NUI][Samples] Fix exception during shutdown + Remove useless codes
[platform/core/csapi/tizenfx.git] / test / Tizen.NUI.PerformanceTest / PerformanceTest.cs
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using Tizen.NUI;
20 using Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Constants;
22
23
24 class PerformanceTestExample : NUIApplication
25 {
26     const uint ROWS_COUNT = 40;
27     const uint COLUMNS_COUNT = 40;
28     const uint TOTAL_COLUMNS_COUNT = 80;
29     const uint DURATION_PER_COLUMNS = 50; // miliseconds
30     // Increase animation time cause OnTick time can be delayed.
31     const uint DURATION_OF_ANIMATION = (DURATION_PER_COLUMNS * (COLUMNS_COUNT * 4 / 3)); // miliseconds.
32     
33
34     const float VIEW_MARGIN_RATE = 0.2f;
35     enum ViewTestType
36     {
37         TEST_TYPE_COLOR = 0,            ///< Test with simple color
38         TEST_TYPE_IMAGE,                ///< Test with simple image
39         TEST_TYPE_TEXT,                 ///< Test with simple text label
40         TEST_TYPE_ROUNDED_COLOR,        ///< Test with rounded color
41         TEST_TYPE_BORDER_COLOR,         ///< Test with borderline color
42         TEST_TYPE_ROUNDED_BORDER_COLOR, ///< Test with rounded borderline color
43         TEST_TYPE_BLUR_COLOR,           ///< Test with blur color
44         TEST_TYPE_ROUNDED_BLUR_COLOR,   ///< Test with blur color
45         TEST_TYPE_MAX,
46     };
47
48     static string TestTypeString(ViewTestType type)
49     {
50         switch(type)
51         {
52             case ViewTestType.TEST_TYPE_COLOR:               return "COLOR";
53             case ViewTestType.TEST_TYPE_IMAGE:               return "IMAGE";
54             case ViewTestType.TEST_TYPE_TEXT:                return "TEXT";
55             case ViewTestType.TEST_TYPE_ROUNDED_COLOR:       return "ROUNDED COLOR";
56             case ViewTestType.TEST_TYPE_BORDER_COLOR:        return "BORDER COLOR";
57             case ViewTestType.TEST_TYPE_ROUNDED_BORDER_COLOR:return "ROUNDED BORDER COLOR";
58             case ViewTestType.TEST_TYPE_BLUR_COLOR:          return "BLUR COLOR";
59             case ViewTestType.TEST_TYPE_ROUNDED_BLUR_COLOR:  return "ROUNDED BLUR COLOR";
60             default:                                         return "UNKNOWN";
61         }
62     }
63
64     static string IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "image/";
65     readonly static string[] IMAGE_PATH = 
66     {
67         IMAGE_DIR + "gallery-small-1.jpg",
68     };
69
70     class Statistic
71     {
72         const double trimRate = 0.34;
73         global::System.Collections.Generic.List<double> v;
74         int vcnt;
75         double vsum;
76         public Statistic()
77         {
78             clear();
79         }
80         public void clear()
81         {
82             v = new global::System.Collections.Generic.List<double>();
83             vcnt = 0;
84             vsum = 0.0;
85         }
86         public void add(double x)
87         {
88             v.Add(x);
89             vcnt++;
90             vsum += x;
91         }
92         public double getAverage()
93         {
94             if(vcnt == 0)return 0.0;
95             return vsum / vcnt;
96         }
97         public double getTrimedAverage()
98         {
99             if(vcnt == 0)return 0.0;
100             v.Sort();
101             double trimVsum = 0;
102             int removedCnt = (int)(vcnt * trimRate * 0.5); // floor
103             int trimVcnt = vcnt - removedCnt * 2;
104             if(trimVcnt == 0)
105             {
106                 trimVcnt += 2;
107                 removedCnt--;
108             }
109             for(int i = removedCnt; i < vcnt - removedCnt; i++)
110             {
111                 trimVsum += v[i];
112             }
113
114             return trimVsum / trimVcnt;
115         }
116     };
117     Statistic mCreationStatistic;
118     Window mWindow;
119     Vector2 mWindowSize;
120     Vector2 mSize;
121     ViewTestType mTestType = ViewTestType.TEST_TYPE_COLOR;
122
123     // To keep reference count.
124     global::System.Collections.Generic.LinkedList<View> mCreatingControlList;
125     global::System.Collections.Generic.LinkedList<View> mRemovingControlList;
126     global::System.Collections.Generic.LinkedList<Timer> mTimerList;
127     global::System.Collections.Generic.LinkedList<Animation> mCreatingAnimationList;
128     global::System.Collections.Generic.LinkedList<Animation> mRemovingAnimationList;
129
130     uint mColumnsCount = ROWS_COUNT;
131     uint mRowsCount = COLUMNS_COUNT;
132     uint mTotalColumnsCount = TOTAL_COLUMNS_COUNT;
133     uint mDurationPerColumns = DURATION_PER_COLUMNS; // miliseconds
134     
135     uint mCreateCount = 0u;
136     uint mDeleteCount = 0u;
137     uint mImageCount  = 0u;
138
139     DateTime appStartTime;
140     DateTime appEndTime;
141     protected void CreateScene()
142     {
143         appStartTime = DateTime.Now;
144
145         mCreatingControlList  = new global::System.Collections.Generic.LinkedList<View>();
146         mRemovingControlList  = new global::System.Collections.Generic.LinkedList<View>();
147         mTimerList = new global::System.Collections.Generic.LinkedList<Timer>();
148         mCreatingAnimationList = new global::System.Collections.Generic.LinkedList<Animation>();
149         mRemovingAnimationList = new global::System.Collections.Generic.LinkedList<Animation>();
150
151         mWindow = Window.Instance;
152         mWindow.BackgroundColor = Color.White;
153         mWindowSize = mWindow.WindowSize;
154
155         mSize = new Vector2(mWindowSize.X / mColumnsCount, mWindowSize.Y / mRowsCount);
156
157         Timer timer = new Timer(mDurationPerColumns);
158         timer.Tick += OnTick;
159         mTimerList.AddLast(timer);
160
161         mDeleteCount = 0;
162
163         mCreationStatistic = new Statistic();
164
165         timer.Start();
166
167         mWindow.KeyEvent += OnKeyEvent;
168     }
169     bool OnTick(object o, EventArgs e)
170     {
171         CreateColumnView();
172         if(mCreateCount < mColumnsCount)
173         {
174             // Start next phase.
175             Timer timer = new Timer(mDurationPerColumns);
176             timer.Tick += OnTick;
177             mTimerList.AddLast(timer);
178
179             timer.Start();
180         }
181         return false;
182     }
183     void CreateColumnView()
184     {
185         DateTime startTime;
186         DateTime endTime;
187
188         startTime = DateTime.Now;
189
190         View columnView = new View()
191         {
192             BackgroundColor = Color.Blue,
193             Size = new Size(mSize.X, mWindowSize.Y),
194             Position = new Position(mSize.X * (mCreateCount % mColumnsCount), -mWindowSize.Y),
195
196             ParentOrigin = Position.ParentOriginTopLeft,
197             PivotPoint = Position.PivotPointTopLeft,
198             PositionUsesPivotPoint = true,
199         };
200
201         for(int i = 0; i < mRowsCount; ++i)
202         {
203             View bgView;
204             switch(mTestType)
205             {
206                 case ViewTestType.TEST_TYPE_COLOR:
207                 default:
208                 {
209                     bgView = CreateColor();
210                     break;
211                 }
212                 case ViewTestType.TEST_TYPE_IMAGE:
213                 {
214                     bgView = CreateImage();
215                     break;
216                 }
217                 case ViewTestType.TEST_TYPE_TEXT:
218                 {
219                     bgView = CreateTextLabel();
220                     break;
221                 }
222                 case ViewTestType.TEST_TYPE_ROUNDED_COLOR:
223                 {
224                     bgView = CreateRoundedColor();
225                     break;
226                 }
227                 case ViewTestType.TEST_TYPE_BORDER_COLOR:
228                 {
229                     bgView = CreateBorderColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE);
230                     break;
231                 }
232                 case ViewTestType.TEST_TYPE_ROUNDED_BORDER_COLOR:
233                 {
234                     bgView = CreateRoundedBorderColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE);
235                     break;
236                 }
237                 case ViewTestType.TEST_TYPE_BLUR_COLOR:
238                 {
239                     bgView = CreateBlurColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE * 0.5f);
240                     break;
241                 }
242                 case ViewTestType.TEST_TYPE_ROUNDED_BLUR_COLOR:
243                 {
244                     bgView = CreateRoundedBlurColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE * 0.5f);
245                     break;
246                 }
247             }
248             bgView.Size = new Size(mSize.X * (1.0f - VIEW_MARGIN_RATE), mSize.Y * (1.0f - VIEW_MARGIN_RATE));
249             bgView.Position = new Position(mSize.X * VIEW_MARGIN_RATE * 0.5f, (mSize.Y * VIEW_MARGIN_RATE * 0.5f) + (mSize.Y * (float)i));
250             columnView.Add(bgView);
251         }
252
253         mWindow.Add(columnView);
254         mCreatingControlList.AddLast(columnView);
255
256         // Add appearing animation
257         Animation appearingAnimation = new Animation((int)(DURATION_OF_ANIMATION));
258         appearingAnimation.AnimateTo(columnView, "PositionY", 0.0f);
259         appearingAnimation.Finished += OnAppearAnimationFinished;
260         appearingAnimation.Play();
261
262         mCreatingAnimationList.AddLast(appearingAnimation);
263
264         endTime = DateTime.Now;
265
266         mCreationStatistic.add((endTime - startTime).TotalMilliseconds);
267
268         mCreateCount++;
269
270         if(mCreateCount % mTotalColumnsCount == 0)
271         {
272             Tizen.Log.Error("NUI.PerfNew", $"Average of creation {mRowsCount} NUI({TestTypeString(mTestType)}) : {mCreationStatistic.getTrimedAverage()} ms\n");
273             mCreationStatistic.clear();
274             mTestType = (ViewTestType)(((int)(mTestType) + 1) % (int)(ViewTestType.TEST_TYPE_MAX));
275         }
276     }
277
278     void OnKeyEvent(object source, Window.KeyEventArgs e)
279     {
280         if (e.Key.State == Key.StateType.Down)
281         {
282             FullGC();
283             //Streamline.AnnotateChannelEnd(0);
284
285             switch( e.Key.KeyPressedName )
286             {
287                 case "Escape":
288                 case "Back":
289                 {
290                     Deactivate();
291                     Exit();
292                 }
293                 break;
294             }
295         }
296     }
297
298     void OnAppearAnimationFinished(object o, EventArgs e)
299     {
300         // We can assume that front of mControlList must be disappearing.
301         var currentControl = mCreatingControlList.First.Value;
302         mCreatingControlList.RemoveFirst();
303
304         // Dereference timer safety
305         if(mTimerList.Count > 0)
306         {
307             mTimerList.First.Value.Dispose();
308             mTimerList.RemoveFirst();
309         }
310
311         // Dereference animation safety
312         mCreatingAnimationList.RemoveFirst();
313
314         mRemovingControlList.AddLast(currentControl);
315
316         if(mCreateCount < mTotalColumnsCount * (int)(ViewTestType.TEST_TYPE_MAX))
317         {
318             CreateColumnView();
319         }
320
321         // Add disappearing animation
322         Animation disappearingAnimation = new Animation((int)(DURATION_OF_ANIMATION));
323         disappearingAnimation.AnimateTo(currentControl, "PositionY", (float)mWindowSize.Y);
324         disappearingAnimation.Finished += OnDisappearAnimationFinished;
325         disappearingAnimation.Play();
326
327         mRemovingAnimationList.AddLast(disappearingAnimation);
328     }
329     void OnDisappearAnimationFinished(object o, EventArgs e)
330     {
331         // We can assume that front of mControlList must be disappearing.
332         var currentControl = mRemovingControlList.First.Value;
333         mRemovingControlList.RemoveFirst();
334
335         // We can assume that front of mViewList must be deleted.
336         currentControl.Unparent();
337         currentControl.DisposeRecursively();
338
339         // Dereference animation safety
340         mRemovingAnimationList.RemoveFirst();
341
342         mDeleteCount++;
343
344         // If all views are deleted, quit this application. byebye~
345         if(mDeleteCount == mTotalColumnsCount * (int)ViewTestType.TEST_TYPE_MAX)
346         {
347             appEndTime = DateTime.Now;
348             Tizen.Log.Error("NUI.PerfNew", $"Duration of all app running time : {((appEndTime - appStartTime)).TotalMilliseconds} ms\n");
349             Deactivate();
350             FullGC();
351             Exit();
352         }
353     }
354
355     private View CreateColor()
356     {
357         View bgView = new View()
358         {
359             BackgroundColor = Color.Yellow,
360
361             ParentOrigin = Position.ParentOriginTopLeft,
362             PivotPoint = Position.PivotPointTopLeft,
363             PositionUsesPivotPoint = true,
364         };
365         return bgView;
366     }
367     private View CreateImage()
368     {
369         ImageView bgView = new ImageView()
370         {
371             ResourceUrl = IMAGE_PATH[(mImageCount++) % (IMAGE_PATH.Length)],
372
373             ParentOrigin = Position.ParentOriginTopLeft,
374             PivotPoint = Position.PivotPointTopLeft,
375             PositionUsesPivotPoint = true,
376         };
377         return bgView;
378     }
379     private View CreateTextLabel()
380     {
381         TextLabel bgView = new TextLabel()
382         {
383             Text = "Hello, World!",
384
385             ParentOrigin = Position.ParentOriginTopLeft,
386             PivotPoint = Position.PivotPointTopLeft,
387             PositionUsesPivotPoint = true,
388         };
389         return bgView;
390     }
391     private View CreateRoundedColor()
392     {
393         View bgView = new View()
394         {
395             BackgroundColor = Color.Yellow,
396             CornerRadius = 0.5f,
397             CornerRadiusPolicy = VisualTransformPolicyType.Relative,
398
399             ParentOrigin = Position.ParentOriginTopLeft,
400             PivotPoint = Position.PivotPointTopLeft,
401             PositionUsesPivotPoint = true,
402         };
403         return bgView;
404     }
405
406     private View CreateBorderColor(float requiredBorderlineWidth)
407     {
408         View bgView = new View()
409         {
410             BackgroundColor = Color.Yellow,
411             BorderlineColor = Color.Red,
412             BorderlineWidth = requiredBorderlineWidth,
413
414             ParentOrigin = Position.ParentOriginTopLeft,
415             PivotPoint = Position.PivotPointTopLeft,
416             PositionUsesPivotPoint = true,
417         };
418         return bgView;
419     }
420     private View CreateRoundedBorderColor(float requiredBorderlineWidth)
421     {
422         View bgView = new View()
423         {
424             BackgroundColor = Color.Yellow,
425             CornerRadius = 0.5f,
426             CornerRadiusPolicy = VisualTransformPolicyType.Relative,
427             BorderlineColor = Color.Red,
428             BorderlineWidth = requiredBorderlineWidth,
429
430             ParentOrigin = Position.ParentOriginTopLeft,
431             PivotPoint = Position.PivotPointTopLeft,
432             PositionUsesPivotPoint = true,
433         };
434         return bgView;
435     }
436     private View CreateBlurColor(float requiredBlurRadius)
437     {
438         View bgView = new View()
439         {
440             ParentOrigin = Position.ParentOriginTopLeft,
441             PivotPoint = Position.PivotPointTopLeft,
442             PositionUsesPivotPoint = true,
443         };
444
445         using(PropertyMap map = new PropertyMap())
446         {
447             map.Insert((int)Visual.Property.Type, new PropertyValue((int)Visual.Type.Color));
448             map.Insert((int)ColorVisualProperty.MixColor, new PropertyValue(Color.Yellow));
449             map.Insert((int)ColorVisualProperty.BlurRadius, new PropertyValue(requiredBlurRadius));
450
451             bgView.Background = map;
452         }
453
454         return bgView;
455     }
456     private View CreateRoundedBlurColor(float requiredBlurRadius)
457     {
458         View bgView = new View()
459         {
460             ParentOrigin = Position.ParentOriginTopLeft,
461             PivotPoint = Position.PivotPointTopLeft,
462             PositionUsesPivotPoint = true,
463         };;
464
465         using(PropertyMap map = new PropertyMap())
466         {
467             map.Insert((int)Visual.Property.Type, new PropertyValue((int)Visual.Type.Color));
468             map.Insert((int)ColorVisualProperty.MixColor, new PropertyValue(Color.Yellow));
469             map.Insert((int)ColorVisualProperty.BlurRadius, new PropertyValue(requiredBlurRadius));
470             map.Insert((int)Visual.Property.CornerRadius, new PropertyValue(0.5f));
471             map.Insert((int)Visual.Property.CornerRadiusPolicy, new PropertyValue((int)VisualTransformPolicyType.Relative));
472
473             bgView.Background = map;
474         }
475
476         return bgView;
477     }
478
479     public void Activate()
480     {
481         CreateScene();
482     }
483     public void FullGC()
484     {
485         global::System.GC.Collect();
486         global::System.GC.WaitForPendingFinalizers();
487         global::System.GC.Collect();
488     }
489
490     public void Deactivate()
491     {
492         DestroyScene();
493     }
494
495     private void CleanList<T>(ref global::System.Collections.Generic.LinkedList<T> list) where T : BaseHandle
496     {
497         while(list.Count > 0)
498         {
499             list.First.Value.Dispose();
500             list.RemoveFirst();
501         }
502         list = null;
503     }
504
505     private void DestroyScene()
506     {
507         // Dereference safety
508         CleanList(ref mCreatingControlList);
509         CleanList(ref mRemovingControlList);
510         CleanList(ref mTimerList);
511         CleanList(ref mCreatingAnimationList);
512         CleanList(ref mRemovingAnimationList);
513     }
514
515     protected override void OnCreate()
516     {
517         // Up call to the Base class first
518         base.OnCreate();
519         Activate();
520     }
521
522     /// <summary>
523     /// The main entry point for the application.
524     /// </summary>
525     [STAThread] // Forces app to use one thread to access NUI
526     static void Main(string[] args)
527     {
528         PerformanceTestExample example = new PerformanceTestExample();
529         example.Run(args);
530     }
531 }