From c6fd65917840c758f7f1faae978d8c3ebd335d32 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Wed, 23 Mar 2022 16:10:38 +0900 Subject: [PATCH] Add perf sample with view creation. Add sample for Control::New test. Also, we can check control-creation time by ttrace. We can disable this sample's ttrace by export DALI_TRACE_PERF_VIEW_CREATION_SAMPLE=false Change-Id: Ia2523a0a99400563efcde39fba2e304834cb1fba Signed-off-by: Eunki, Hong --- com.samsung.dali-demo.xml | 3 + .../perf-view-creation-example.cpp | 550 +++++++++++++++++++++ resources/po/en_GB.po | 3 + resources/po/en_US.po | 3 + shared/dali-demo-strings.h | 2 + tests-reel/dali-tests-reel.cpp | 1 + 6 files changed, 562 insertions(+) create mode 100644 examples/perf-view-creation/perf-view-creation-example.cpp diff --git a/com.samsung.dali-demo.xml b/com.samsung.dali-demo.xml index 7e36ba1..a4b570a 100644 --- a/com.samsung.dali-demo.xml +++ b/com.samsung.dali-demo.xml @@ -211,6 +211,9 @@ + + + diff --git a/examples/perf-view-creation/perf-view-creation-example.cpp b/examples/perf-view-creation/perf-view-creation-example.cpp new file mode 100644 index 0000000..07f6e0f --- /dev/null +++ b/examples/perf-view-creation/perf-view-creation-example.cpp @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include "shared/utility.h" + +using namespace Dali; +using namespace Dali::Toolkit; +using namespace std; + +// TODO : borderline, blur type need to solve partial update issue. +// Until that issue exist, just block it. +#define ALLOW_BORDER_AND_BLUR 0 + +namespace +{ +enum class ControlTestType +{ + // clang-format off + COLOR = 0, ///< Test with simple color + IMAGE, ///< Test with simple image + TEXT, ///< Test with simple text label + ROUNDED_COLOR, ///< Test with rounded color +#if ALLOW_BORDER_AND_BLUR + BORDER_COLOR, ///< Test with borderline color + ROUNDED_BORDER_COLOR, ///< Test with rounded borderline color + BLUR_COLOR, ///< Test with blur color + ROUNDED_BLUR_COLOR, ///< Test with blur color +#endif + TYPE_MAX, + // clang-format on +}; + +const char* TestTypeString(ControlTestType type) +{ + // clang-format off + switch(type) + { + case ControlTestType::COLOR: return "COLOR"; + case ControlTestType::IMAGE: return "IMAGE"; + case ControlTestType::TEXT: return "TEXT"; + case ControlTestType::ROUNDED_COLOR: return "ROUNDED COLOR"; +#if ALLOW_BORDER_AND_BLUR + case ControlTestType::BORDER_COLOR: return "BORDER COLOR"; + case ControlTestType::ROUNDED_BORDER_COLOR:return "ROUNDED BORDER COLOR"; + case ControlTestType::BLUR_COLOR: return "BLUR COLOR"; + case ControlTestType::ROUNDED_BLUR_COLOR: return "ROUNDED BLUR COLOR"; +#endif + default: return "UNKNOWN"; + } + // clang-format on +} + +// NOTE : Due to the image load is bottleneck on target, we just use single small image. +const char* IMAGE_PATH[] = { + DEMO_IMAGE_DIR "gallery-small-1.jpg", +}; + +constexpr uint32_t NUM_IMAGES = sizeof(IMAGE_PATH) / sizeof(char*); + +constexpr uint32_t ROWS_COUNT(40); +constexpr uint32_t COLUMNS_COUNT(40); +constexpr uint32_t TOTAL_COLUMNS_COUNT(80); +constexpr uint32_t DURATION_PER_COLUMNS(50); // miliseconds. +// Increase animation time cause OnTick time can be delayed. +constexpr uint32_t DURATION_OF_ANIMATION(DURATION_PER_COLUMNS*(COLUMNS_COUNT * 4 / 3)); // miliseconds. + +// We should render same type of views in some timing. +static_assert(COLUMNS_COUNT * 2 <= TOTAL_COLUMNS_COUNT); + +constexpr float VIEW_MARGIN_RATE = 0.1f; + +// copy from dali-adaptor time-service.cpp +void GetNanoseconds(uint64_t& timeInNanoseconds) +{ + // Get the time of a monotonic clock since its epoch. + auto epoch = std::chrono::steady_clock::now().time_since_epoch(); + + auto duration = std::chrono::duration_cast(epoch); + + timeInNanoseconds = static_cast(duration.count()); +} + +Control CreateColor() +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + bgView.SetBackgroundColor(Color::YELLOW); + return bgView; +} + +Control CreateImage(uint32_t& imageCount) +{ + Control bgView = ImageView::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, IMAGE_PATH[imageCount++ % NUM_IMAGES]); + return bgView; +} + +Control CreateTextLabel() +{ + Control bgView = TextLabel::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS, "Hello, World!"); + return bgView; +} + +Control CreateRoundedColor() +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW; + map[DevelVisual::Property::CORNER_RADIUS] = 0.5f; + map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE; + + bgView[Control::Property::BACKGROUND] = map; + + return bgView; +} + +#if ALLOW_BORDER_AND_BLUR +Control CreateBorderColor(const float& requiredBorderlineWidth) +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW; + map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth; + map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED; + + bgView[Control::Property::BACKGROUND] = map; + + return bgView; +} + +Control CreateRoundedBorderColor(const float& requiredBorderlineWidth) +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW; + map[DevelVisual::Property::CORNER_RADIUS] = 0.5f; + map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE; + map[DevelVisual::Property::BORDERLINE_WIDTH] = requiredBorderlineWidth; + map[DevelVisual::Property::BORDERLINE_COLOR] = Color::RED; + + bgView[Control::Property::BACKGROUND] = map; + + return bgView; +} + +Control CreateBlurColor(const float& requiredBlurRadius) +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW; + map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius; + + bgView[Control::Property::BACKGROUND] = map; + + return bgView; +} + +Control CreateRoundedBlurColor(const float& requiredBlurRadius) +{ + Control bgView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + + Property::Map map; + map[Visual::Property::TYPE] = Visual::COLOR; + map[ColorVisual::Property::MIX_COLOR] = Color::YELLOW; + map[DevelVisual::Property::CORNER_RADIUS] = 0.5f; + map[DevelVisual::Property::CORNER_RADIUS_POLICY] = Visual::Transform::Policy::RELATIVE; + map[DevelColorVisual::Property::BLUR_RADIUS] = requiredBlurRadius; + + bgView[Control::Property::BACKGROUND] = map; + + return bgView; +} +#endif + +/** + * @brief Statistic container that we can get average / sum / min/ max. + * + * @tparam T Type of data. T should define add, compare, div-by-int, numeric_limits::min and max + */ +template +struct Statistic +{ + static constexpr double trimRate = 0.34; + + std::vector v; + int vcnt; + T vsum; + T vmax; + T vmin; + Statistic() + { + Clear(); + } + + void Clear() + { + v.clear(); + vcnt = 0; + vsum = 0; + vmax = std::numeric_limits::min(); + vmin = std::numeric_limits::max(); + } + + void Add(T x) + { + v.emplace_back(x); + vsum += x; + vcnt++; + vmax = std::max(vmax, x); + vmin = std::min(vmin, x); + } + + double GetAverage() + { + if(vcnt == 0) return 0.0; + return static_cast(vsum) / vcnt; + } + + double GetTrimedAverage() + { + if(vcnt == 0) return 0.0; + std::sort(v.begin(), v.end()); + T trimVsum = 0; + int removedCnt = static_cast(vcnt * trimRate * 0.5); // floor + int trimVcnt = vcnt - removedCnt * 2; + if(trimVcnt == 0) + { + trimVcnt += 2; + removedCnt--; + } + for(int i = removedCnt; i < vcnt - removedCnt; i++) + { + trimVsum += v[i]; + } + + return static_cast(trimVsum) / trimVcnt; + } +}; + +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERF_VIEW_CREATION_SAMPLE, true); + +} // namespace + +/** + * Test application to compare performance between various type of Views creation time & manually created Renderers + */ +class PerfViewCreation : public ConnectionTracker +{ +public: + PerfViewCreation(Application& application) + : mApplication(application), + mRowsCount(ROWS_COUNT), + mColumnsCount(COLUMNS_COUNT), + mTotalColumnsCount(TOTAL_COLUMNS_COUNT), + mDurationPerColumns(DURATION_PER_COLUMNS), + mDurationOfAnimation(DURATION_OF_ANIMATION), + mTestType(ControlTestType::COLOR) + { + // Connect to the Application's Init signal + mApplication.InitSignal().Connect(this, &PerfViewCreation::Create); + } + + ~PerfViewCreation() = default; + + // The Init signal is received once (only) during the Application lifetime + void Create(Application& application) + { + GetNanoseconds(mAppStartTime); + + // Get a handle to the window + mWindow = application.GetWindow(); + mWindow.SetBackgroundColor(Color::WHITE); + mWindowSize = mWindow.GetSize(); + + mWindow.GetRootLayer().SetProperty(Layer::Property::DEPTH_TEST, false); + + mSize = Vector3(mWindowSize.x / mColumnsCount, mWindowSize.y / mRowsCount, 0.0f); + + Timer timer = Timer::New(mDurationPerColumns); + timer.TickSignal().Connect(this, &PerfViewCreation::OnTick); + mTimerList.push_back(timer); + + mCreationStatistic.Clear(); + + mCreateCount = 0; + mDeleteCount = 0; + mImageCount = 0; + + timer.Start(); + + // Respond to key events + mWindow.KeyEventSignal().Connect(this, &PerfViewCreation::OnKeyEvent); + } + + bool OnTick() + { + CreateColumnView(); + if(mCreateCount < mColumnsCount) + { + // Start next phase. + Timer timer = Timer::New(mDurationPerColumns); + timer.TickSignal().Connect(this, &PerfViewCreation::OnTick); + mTimerList.push_back(timer); + + timer.Start(); + } + return false; + } + void CreateColumnView() + { + uint64_t startTime; + uint64_t endTime; + + GetNanoseconds(startTime); + DALI_TRACE_BEGIN(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION"); + + Control columnView = Control::New(Control::ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS); + columnView.SetBackgroundColor(Color::BLUE); + columnView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT; + columnView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT; + columnView[Actor::Property::SIZE] = Vector2(mSize.x, (float)mWindowSize.y); + columnView[Actor::Property::POSITION] = Vector2(mSize.x * (mCreateCount % mColumnsCount), -(float)mWindowSize.y); + for(uint32_t i = 0; i < mRowsCount; ++i) + { + Control bgView; + switch(mTestType) + { + case ControlTestType::COLOR: + default: + { + bgView = CreateColor(); + break; + } + case ControlTestType::IMAGE: + { + bgView = CreateImage(mImageCount); + break; + } + case ControlTestType::TEXT: + { + bgView = CreateTextLabel(); + break; + } + case ControlTestType::ROUNDED_COLOR: + { + bgView = CreateRoundedColor(); + break; + } +#if ALLOW_BORDER_AND_BLUR + case ControlTestType::BORDER_COLOR: + { + bgView = CreateBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE); + break; + } + case ControlTestType::ROUNDED_BORDER_COLOR: + { + bgView = CreateRoundedBorderColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE); + break; + } + case ControlTestType::BLUR_COLOR: + { + bgView = CreateBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f); + break; + } + case ControlTestType::ROUNDED_BLUR_COLOR: + { + bgView = CreateRoundedBlurColor(std::min(mSize.x, mSize.y) * VIEW_MARGIN_RATE * 0.5f); + break; + } +#endif + } + + bgView[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT; + bgView[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT; + bgView[Actor::Property::SIZE] = Vector2(mSize.x * (1.0f - VIEW_MARGIN_RATE), mSize.y * (1.0f - VIEW_MARGIN_RATE)); + bgView[Actor::Property::POSITION] = Vector2(mSize.x * VIEW_MARGIN_RATE * 0.5f, mSize.y * VIEW_MARGIN_RATE * 0.5f + mSize.y * i); + columnView.Add(bgView); + } + + mWindow.GetRootLayer().Add(columnView); + mCreatingControlList.push_back(columnView); + + // Add appearing animation + Animation appearingAnimation = Animation::New(mDurationOfAnimation * 0.001f); + appearingAnimation.AnimateTo(Property(columnView, Actor::Property::POSITION_Y), 0.0f); + appearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnAppearAnimationFinished); + appearingAnimation.Play(); + + mCreatingAnimationList.push_back(appearingAnimation); + + GetNanoseconds(endTime); + + DALI_TRACE_END(gTraceFilter, "DALI_SAMPLE_PERF_VIEW_CREATION"); + + // Append duration of creation time. + mCreationStatistic.Add((endTime - startTime) / 1000000.0); + + mCreateCount++; + + if(mCreateCount % mTotalColumnsCount == 0) + { + DALI_LOG_ERROR("Average of creation %d DALI(%s) : %.6lf ms\n", mRowsCount, TestTypeString(mTestType), mCreationStatistic.GetTrimedAverage()); + mCreationStatistic.Clear(); + mTestType = static_cast((static_cast(mTestType) + 1) % static_cast(ControlTestType::TYPE_MAX)); + } + } + + bool OnTouch(Actor actor, const TouchEvent& touch) + { + // quit the application + mApplication.Quit(); + return true; + } + + void OnKeyEvent(const KeyEvent& event) + { + if(event.GetState() == KeyEvent::DOWN) + { + if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK)) + { + mApplication.Quit(); + } + } + } + + void OnAppearAnimationFinished(Animation& animation) + { + // We can assume that front of mControlList must be disappearing. + auto currentControl = mCreatingControlList.front(); + mCreatingControlList.pop_front(); + + // Dereference timer safety + if(mTimerList.empty()) + { + mTimerList.pop_front(); + } + + // Dereference animation safety + mCreatingAnimationList.pop_back(); + + mRemovingControlList.push_back(currentControl); + + if(mCreateCount < mTotalColumnsCount * (static_cast(ControlTestType::TYPE_MAX))) + { + CreateColumnView(); + } + + // Add disappearing animation + Animation disappearingAnimation = Animation::New(mDurationOfAnimation * 0.001f); + disappearingAnimation.AnimateTo(Property(currentControl, Actor::Property::POSITION_Y), (float)mWindowSize.y); + disappearingAnimation.FinishedSignal().Connect(this, &PerfViewCreation::OnDisappearAnimationFinished); + disappearingAnimation.Play(); + + mRemovingAnimationList.push_back(disappearingAnimation); + } + void OnDisappearAnimationFinished(Animation& animation) + { + // We can assume that front of mControlList must be deleted. + mRemovingControlList.front().Unparent(); + mRemovingControlList.pop_front(); + + // Dereference animation safety + mRemovingAnimationList.pop_back(); + + mDeleteCount++; + + // If all controls are deleted, quit this application. byebye~ + if(mDeleteCount == mTotalColumnsCount * (static_cast(ControlTestType::TYPE_MAX))) + { + GetNanoseconds(mAppEndTime); + + DALI_LOG_ERROR("Duration of all app running time : %.6lf ms\n", (mAppEndTime - mAppStartTime) / 1000000.0); + mApplication.Quit(); + } + } + +private: + Application& mApplication; + Window mWindow; + Vector2 mWindowSize; + + std::list mCreatingControlList; + std::list mRemovingControlList; + std::list mCreatingAnimationList; + std::list mRemovingAnimationList; + std::list mTimerList; + + Vector3 mSize; + + const uint32_t mRowsCount; + const uint32_t mColumnsCount; + const uint32_t mTotalColumnsCount; + + const uint32_t mDurationPerColumns; + const uint32_t mDurationOfAnimation; + + ControlTestType mTestType; + + uint32_t mCreateCount = 0; + uint32_t mDeleteCount = 0; + uint32_t mImageCount = 0; + + uint64_t mAppStartTime; + uint64_t mAppEndTime; + + Statistic mCreationStatistic; +}; + +int DALI_EXPORT_API main(int argc, char** argv) +{ + Application application = Application::New(&argc, &argv); + + PerfViewCreation test(application); + application.MainLoop(); + + return 0; +} diff --git a/resources/po/en_GB.po b/resources/po/en_GB.po index fb46dfe..ef898c2 100755 --- a/resources/po/en_GB.po +++ b/resources/po/en_GB.po @@ -169,6 +169,9 @@ msgstr "Particles" msgid "DALI_DEMO_STR_TITLE_PERF_SCROLL" msgstr "Scrolling Performance" +msgid "DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION" +msgstr "Creation View Performance" + msgid "DALI_DEMO_STR_TITLE_POINT_MESH" msgstr "Point Mesh" diff --git a/resources/po/en_US.po b/resources/po/en_US.po index 1896dec..50f1998 100755 --- a/resources/po/en_US.po +++ b/resources/po/en_US.po @@ -175,6 +175,9 @@ msgstr "Particles" msgid "DALI_DEMO_STR_TITLE_PERF_SCROLL" msgstr "Scrolling Performance" +msgid "DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION" +msgstr "Creation View Performance" + msgid "DALI_DEMO_STR_TITLE_POINT_MESH" msgstr "Point Mesh" diff --git a/shared/dali-demo-strings.h b/shared/dali-demo-strings.h index d6b0b9c..46b310a 100644 --- a/shared/dali-demo-strings.h +++ b/shared/dali-demo-strings.h @@ -97,6 +97,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_PARTICLES dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PARTICLES") #define DALI_DEMO_STR_TITLE_PBR dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PBR") #define DALI_DEMO_STR_TITLE_PERF_SCROLL dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PERF_SCROLL") +#define DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION") #define DALI_DEMO_STR_TITLE_POINT_MESH dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_POINT_MESH") #define DALI_DEMO_STR_TITLE_POPUP dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_POPUP") #define DALI_DEMO_STR_TITLE_PIVOT dgettext(DALI_DEMO_DOMAIN_LOCAL, "DALI_DEMO_STR_TITLE_PIVOT") @@ -207,6 +208,7 @@ extern "C" #define DALI_DEMO_STR_TITLE_PARTICLES "Particles" #define DALI_DEMO_STR_TITLE_PBR "PBR" #define DALI_DEMO_STR_TITLE_PERF_SCROLL "Scrolling Performance" +#define DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION "Creation View Performance" #define DALI_DEMO_STR_TITLE_POINT_MESH "Point Mesh" #define DALI_DEMO_STR_TITLE_POPUP "Popup" #define DALI_DEMO_STR_TITLE_PIVOT "Pivot" diff --git a/tests-reel/dali-tests-reel.cpp b/tests-reel/dali-tests-reel.cpp index b53a239..e5ca014 100644 --- a/tests-reel/dali-tests-reel.cpp +++ b/tests-reel/dali-tests-reel.cpp @@ -43,6 +43,7 @@ int DALI_EXPORT_API main(int argc, char** argv) demo.AddExample(Example("homescreen-benchmark.example", DALI_DEMO_STR_TITLE_HOMESCREEN)); demo.AddExample(Example("pre-render-callback.example", DALI_DEMO_STR_TITLE_PRE_RENDER_CALLBACK)); demo.AddExample(Example("perf-scroll.example", DALI_DEMO_STR_TITLE_PERF_SCROLL)); + demo.AddExample(Example("perf-view-creation.example", DALI_DEMO_STR_TITLE_PERF_VIEW_CREATION)); demo.AddExample(Example("point-mesh.example", DALI_DEMO_STR_TITLE_POINT_MESH)); demo.AddExample(Example("property-notification.example", DALI_DEMO_STR_TITLE_PROPERTY_NOTIFICATION)); demo.AddExample(Example("simple-visuals-control.example", DALI_DEMO_STR_TITLE_SIMPLE_VISUALS_CONTROL)); -- 2.7.4