fc1fd49c491305397c8f77dcf1591dbee3743a9a
[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         TEST_TYPE_COLOR = 0,            ///< Test with simple color
37         TEST_TYPE_IMAGE,                ///< Test with simple image
38         TEST_TYPE_TEXT,                 ///< Test with simple text label
39         TEST_TYPE_ROUNDED_COLOR,        ///< Test with rounded color
40         TEST_TYPE_BORDER_COLOR,         ///< Test with borderline color
41         TEST_TYPE_ROUNDED_BORDER_COLOR, ///< Test with rounded borderline color
42         TEST_TYPE_BLUR_COLOR,           ///< Test with blur color
43         TEST_TYPE_ROUNDED_BLUR_COLOR,   ///< Test with blur color
44         TEST_TYPE_MAX,
45     };
46
47     static string TestTypeString(ViewTestType type)
48     {
49         switch(type)
50         {
51             case ViewTestType.TEST_TYPE_COLOR:               return "COLOR";
52             case ViewTestType.TEST_TYPE_IMAGE:               return "IMAGE";
53             case ViewTestType.TEST_TYPE_TEXT:                return "TEXT";
54             case ViewTestType.TEST_TYPE_ROUNDED_COLOR:       return "ROUNDED COLOR";
55             case ViewTestType.TEST_TYPE_BORDER_COLOR:        return "BORDER COLOR";
56             case ViewTestType.TEST_TYPE_ROUNDED_BORDER_COLOR:return "ROUNDED BORDER COLOR";
57             case ViewTestType.TEST_TYPE_BLUR_COLOR:          return "BLUR COLOR";
58             case ViewTestType.TEST_TYPE_ROUNDED_BLUR_COLOR:  return "ROUNDED BLUR COLOR";
59             default:                                         return "UNKNOWN";
60         }
61     }
62
63     static string IMAGE_DIR = Tizen.Applications.Application.Current.DirectoryInfo.Resource + "image/";
64     readonly static string[] IMAGE_PATH = {
65         IMAGE_DIR + "gallery-small-1.jpg",
66     };
67
68     class Statistic
69     {
70         const double trimRate = 0.34;
71         global::System.Collections.Generic.List<double> v;
72         int vcnt;
73         double vsum;
74         public Statistic()
75         {
76             clear();
77         }
78         public void clear()
79         {
80             v = new global::System.Collections.Generic.List<double>();
81             vcnt = 0;
82             vsum = 0.0;
83         }
84         public void add(double x)
85         {
86             v.Add(x);
87             vcnt++;
88             vsum += x;
89         }
90         public double getAverage()
91         {
92             if(vcnt == 0)return 0.0;
93             return vsum / vcnt;
94         }
95         public double getTrimedAverage()
96         {
97             if(vcnt == 0)return 0.0;
98             v.Sort();
99             double trimVsum = 0;
100             int removedCnt = (int)(vcnt * trimRate * 0.5); // floor
101             int trimVcnt = vcnt - removedCnt * 2;
102             if(trimVcnt == 0)
103             {
104                 trimVcnt += 2;
105                 removedCnt--;
106             }
107             for(int i = removedCnt; i < vcnt - removedCnt; i++)
108             {
109                 trimVsum += v[i];
110             }
111
112             return trimVsum / trimVcnt;
113         }
114     };
115     Statistic mCreationStatistic;
116     Window mWindow;
117     Vector2 mWindowSize;
118     Vector2 mSize;
119     ViewTestType mTestType = ViewTestType.TEST_TYPE_COLOR;
120
121     // To keep reference count.
122     global::System.Collections.Generic.LinkedList<View> mCreatingControlList;
123     global::System.Collections.Generic.LinkedList<View> mRemovingControlList;
124     global::System.Collections.Generic.LinkedList<Timer> mTimerList;
125     global::System.Collections.Generic.LinkedList<Animation> mCreatingAnimationList;
126     global::System.Collections.Generic.LinkedList<Animation> mRemovingAnimationList;
127
128     uint mColumnsCount = ROWS_COUNT;
129     uint mRowsCount = COLUMNS_COUNT;
130     uint mTotalColumnsCount = TOTAL_COLUMNS_COUNT;
131     uint mDurationPerColumns = DURATION_PER_COLUMNS; // miliseconds
132
133     uint tickCount;
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         tickCount = 0;
162         mDeleteCount = 0;
163
164         mCreationStatistic = new Statistic();
165
166         timer.Start();
167
168         mWindow.KeyEvent += OnKeyEvent;
169     }
170     bool OnTick(object o, EventArgs e)
171     {
172         CreateColumnView();
173         if(mCreateCount < mColumnsCount)
174         {
175             // Start next phase.
176             Timer timer = new Timer(mDurationPerColumns);
177             timer.Tick += OnTick;
178             mTimerList.AddLast(timer);
179
180             timer.Start();
181         }
182         return false;
183     }
184     void CreateColumnView()
185     {
186         DateTime startTime;
187         DateTime endTime;
188
189         startTime = DateTime.Now;
190
191         View columnView = new View()
192         {
193             BackgroundColor = Color.Blue,
194             Size = new Size(mSize.X, mWindowSize.Y),
195             Position = new Position(mSize.X * (mCreateCount % mColumnsCount), -mWindowSize.Y),
196
197             ParentOrigin = Position.ParentOriginTopLeft,
198             PivotPoint = Position.PivotPointTopLeft,
199             PositionUsesPivotPoint = true,
200         };
201
202         for(int i = 0; i < mRowsCount; ++i)
203         {
204             View bgView;
205             switch(mTestType)
206             {
207                 case ViewTestType.TEST_TYPE_COLOR:
208                 default:
209                 {
210                     bgView = CreateColor();
211                     break;
212                 }
213                 case ViewTestType.TEST_TYPE_IMAGE:
214                 {
215                     bgView = CreateImage();
216                     break;
217                 }
218                 case ViewTestType.TEST_TYPE_TEXT:
219                 {
220                     bgView = CreateTextLabel();
221                     break;
222                 }
223                 case ViewTestType.TEST_TYPE_ROUNDED_COLOR:
224                 {
225                     bgView = CreateRoundedColor();
226                     break;
227                 }
228                 case ViewTestType.TEST_TYPE_BORDER_COLOR:
229                 {
230                     bgView = CreateBorderColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE);
231                     break;
232                 }
233                 case ViewTestType.TEST_TYPE_ROUNDED_BORDER_COLOR:
234                 {
235                     bgView = CreateRoundedBorderColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE);
236                     break;
237                 }
238                 case ViewTestType.TEST_TYPE_BLUR_COLOR:
239                 {
240                     bgView = CreateBlurColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE * 0.5f);
241                     break;
242                 }
243                 case ViewTestType.TEST_TYPE_ROUNDED_BLUR_COLOR:
244                 {
245                     bgView = CreateRoundedBlurColor(Math.Min(mSize.X, mSize.Y) * VIEW_MARGIN_RATE * 0.5f);
246                     break;
247                 }
248             }
249             bgView.Size = new Size(mSize.X * (1.0f - VIEW_MARGIN_RATE), mSize.Y * (1.0f - VIEW_MARGIN_RATE));
250             bgView.Position = new Position(mSize.X * VIEW_MARGIN_RATE * 0.5f, (mSize.Y * VIEW_MARGIN_RATE * 0.5f) + (mSize.Y * (float)i));
251             columnView.Add(bgView);
252         }
253
254         mWindow.Add(columnView);
255         mCreatingControlList.AddLast(columnView);
256
257         // Add appearing animation
258         Animation appearingAnimation = new Animation((int)(DURATION_OF_ANIMATION));
259         appearingAnimation.AnimateTo(columnView, "PositionY", 0.0f);
260         appearingAnimation.Finished += OnAppearAnimationFinished;
261         appearingAnimation.Play();
262
263         mCreatingAnimationList.AddLast(appearingAnimation);
264
265         endTime = DateTime.Now;
266
267         mCreationStatistic.add((endTime - startTime).TotalMilliseconds);
268
269         mCreateCount++;
270
271         if(mCreateCount % mTotalColumnsCount == 0)
272         {
273             Tizen.Log.Error("NUI.PerfNew", $"Average of creation {mRowsCount} NUI({TestTypeString(mTestType)}) : {mCreationStatistic.getTrimedAverage()} ms\n");
274             mCreationStatistic.clear();
275             mTestType = (ViewTestType)(((int)(mTestType) + 1) % (int)(ViewTestType.TEST_TYPE_MAX));
276         }
277     }
278
279     void OnKeyEvent(object source, Window.KeyEventArgs e)
280     {
281         if (e.Key.State == Key.StateType.Down)
282         {
283             FullGC();
284             //Streamline.AnnotateChannelEnd(0);
285
286             switch( e.Key.KeyPressedName )
287             {
288                 case "Escape":
289                 case "Back":
290                 {
291                     Deactivate();
292                     Exit();
293                 }
294                 break;
295             }
296         }
297     }
298
299     void OnAppearAnimationFinished(object o, EventArgs e)
300     {
301         // We can assume that front of mControlList must be disappearing.
302         var currentControl = mCreatingControlList.First.Value;
303         mCreatingControlList.RemoveFirst();
304
305         // Dereference timer safety
306         if(mTimerList.Count > 0)
307         {
308             mTimerList.First.Value.Dispose();
309             mTimerList.RemoveFirst();
310         }
311
312         // Dereference animation safety
313         mCreatingAnimationList.RemoveFirst();
314
315         mRemovingControlList.AddLast(currentControl);
316
317         if(mCreateCount < mTotalColumnsCount * (int)(ViewTestType.TEST_TYPE_MAX))
318         {
319             CreateColumnView();
320         }
321
322         // Add disappearing animation
323         Animation disappearingAnimation = new Animation((int)(DURATION_OF_ANIMATION));
324         disappearingAnimation.AnimateTo(currentControl, "PositionY", (float)mWindowSize.Y);
325         disappearingAnimation.Finished += OnDisappearAnimationFinished;
326         disappearingAnimation.Play();
327
328         mRemovingAnimationList.AddLast(disappearingAnimation);
329     }
330     void OnDisappearAnimationFinished(object o, EventArgs e)
331     {
332         // We can assume that front of mControlList must be disappearing.
333         var currentControl = mRemovingControlList.First.Value;
334         mRemovingControlList.RemoveFirst();
335
336         // We can assume that front of mViewLIst must be deleted.
337         currentControl.Unparent();
338         currentControl.DisposeRecursively();
339
340         // Dereference animation safety
341         mRemovingAnimationList.RemoveFirst();
342
343         mDeleteCount++;
344
345         // If all views are deleted, quit this application. byebye~
346         if(mDeleteCount == mTotalColumnsCount * (int)ViewTestType.TEST_TYPE_MAX)
347         {
348             appEndTime = DateTime.Now;
349             Tizen.Log.Error("NUI.PerfNew", $"Duration of all app running time : {((appEndTime - appStartTime)).TotalMilliseconds} ms\n");
350             Deactivate();
351             FullGC();
352             Exit();
353         }
354     }
355
356     private View CreateColor()
357     {
358         View bgView = new View(){
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             BackgroundColor = Color.Yellow,
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             Text = "Hello, World!",
383
384             ParentOrigin = Position.ParentOriginTopLeft,
385             PivotPoint = Position.PivotPointTopLeft,
386             PositionUsesPivotPoint = true,
387         };
388         return bgView;
389     }
390     private View CreateRoundedColor()
391     {
392         View bgView = new View(){
393             BackgroundColor = Color.Yellow,
394             CornerRadius = 0.5f,
395             CornerRadiusPolicy = VisualTransformPolicyType.Relative,
396
397             ParentOrigin = Position.ParentOriginTopLeft,
398             PivotPoint = Position.PivotPointTopLeft,
399             PositionUsesPivotPoint = true,
400         };
401         return bgView;
402     }
403
404     private View CreateBorderColor(float requiredBorderlineWidth)
405     {
406         View bgView = new View(){
407             BackgroundColor = Color.Yellow,
408             BorderlineColor = Color.Red,
409             BorderlineWidth = requiredBorderlineWidth,
410
411             ParentOrigin = Position.ParentOriginTopLeft,
412             PivotPoint = Position.PivotPointTopLeft,
413             PositionUsesPivotPoint = true,
414         };
415         return bgView;
416     }
417     private View CreateRoundedBorderColor(float requiredBorderlineWidth)
418     {
419         View bgView = new View(){
420             BackgroundColor = Color.Yellow,
421             CornerRadius = 0.5f,
422             CornerRadiusPolicy = VisualTransformPolicyType.Relative,
423             BorderlineColor = Color.Red,
424             BorderlineWidth = requiredBorderlineWidth,
425
426             ParentOrigin = Position.ParentOriginTopLeft,
427             PivotPoint = Position.PivotPointTopLeft,
428             PositionUsesPivotPoint = true,
429         };
430         return bgView;
431     }
432     private View CreateBlurColor(float requiredBlurRadius)
433     {
434         View bgView = new View()
435         {
436             ParentOrigin = Position.ParentOriginTopLeft,
437             PivotPoint = Position.PivotPointTopLeft,
438             PositionUsesPivotPoint = true,
439         };
440
441         using(PropertyMap map = new PropertyMap())
442         {
443             map.Insert((int)Visual.Property.Type, new PropertyValue((int)Visual.Type.Color));
444             map.Insert((int)ColorVisualProperty.MixColor, new PropertyValue(Color.Yellow));
445             map.Insert((int)ColorVisualProperty.BlurRadius, new PropertyValue(requiredBlurRadius));
446
447             bgView.Background = map;
448         }
449
450         return bgView;
451     }
452     private View CreateRoundedBlurColor(float requiredBlurRadius)
453     {
454         View bgView = new View()
455         {
456             ParentOrigin = Position.ParentOriginTopLeft,
457             PivotPoint = Position.PivotPointTopLeft,
458             PositionUsesPivotPoint = true,
459         };;
460
461         using(PropertyMap map = new PropertyMap())
462         {
463             map.Insert((int)Visual.Property.Type, new PropertyValue((int)Visual.Type.Color));
464             map.Insert((int)ColorVisualProperty.MixColor, new PropertyValue(Color.Yellow));
465             map.Insert((int)ColorVisualProperty.BlurRadius, new PropertyValue(requiredBlurRadius));
466             map.Insert((int)Visual.Property.CornerRadius, new PropertyValue(0.5f));
467             map.Insert((int)Visual.Property.CornerRadiusPolicy, new PropertyValue((int)VisualTransformPolicyType.Relative));
468
469             bgView.Background = map;
470         }
471
472         return bgView;
473     }
474
475     public void Activate()
476     {
477         CreateScene();
478     }
479     public void FullGC(){
480         global::System.GC.Collect();
481         global::System.GC.WaitForPendingFinalizers();
482         global::System.GC.Collect();
483     }
484
485     public void Deactivate()
486     {
487         DestroyScene();
488     }
489     private void DestroyScene()
490     {
491     }
492
493     protected override void OnCreate()
494     {
495         // Up call to the Base class first
496         base.OnCreate();
497         Activate();
498     }
499
500     /// <summary>
501     /// The main entry point for the application.
502     /// </summary>
503     [STAThread] // Forces app to use one thread to access NUI
504     static void Main(string[] args)
505     {
506         PerformanceTestExample example = new PerformanceTestExample();
507         example.Run(args);
508     }
509 }