RS超节点数上报

Signed-off-by: 周思远 <zhousiyuan8@huawei.com>
This commit is contained in:
周思远 2024-04-27 16:50:33 +08:00
parent 4bc8d10219
commit a2f5a79f46
9 changed files with 420 additions and 0 deletions

View File

@ -146,6 +146,19 @@ FIRST_FRAME_DRAWN:
__BASE: {type: BEHAVIOR, level: MINOR, tag: performance, desc: interaction jank statistics}
APP_PID: {type: INT32, desc: app process id}
RS_NODE_LIMIT_EXCEEDED:
__BASE: {type: BEHAVIOR, level: MINOR, tag: performance, desc: rs node limit exceeded statistics}
RS_NODE_LIMIT: {type: UINT32, desc: the upper limit of the total number of rs nodes}
RS_ACTUAL_NODE: {type: UINT32, desc: current total number of rs nodes}
TIMESTAMP: {type: UINT64, desc: current timestamp}
RS_APP_WINDOW_TOTAL: {type: UINT32, desc: current total app windows on rs tree}
RS_TOP1_APP_NAME: {type: STRING, desc: name of current app with top1 rs nodes}
RS_TOP1_APP_NODE: {type: UINT32, desc: number of nodes of current app with top1 rs nodes}
RS_TOP2_APP_NAME: {type: STRING, desc: name of current app with top2 rs nodes}
RS_TOP2_APP_NODE: {type: UINT32, desc: number of nodes of current app with top2 rs nodes}
RS_TOP3_APP_NAME: {type: STRING, desc: name of current app with top3 rs nodes}
RS_TOP3_APP_NODE: {type: UINT32, desc: number of nodes of current app with top3 rs nodes}
HGM_VOTER_INFO:
__BASE: {type: STATISTIC, level: MINOR, desc: hgm voter info statistics}
MSG: {type: STRING, desc: voter info}

View File

@ -35,6 +35,7 @@
#include "draw/brush.h"
#include "platform/common/rs_log.h"
#include "platform/ohos/rs_node_stats.h"
#include "utils/rect.h"
#include "utils/region.h"
@ -263,6 +264,9 @@ void RSSurfaceRenderNodeDrawable::OnDraw(Drawing::Canvas& canvas)
rscanvas->PopDirtyRegion();
RS_TRACE_NAME_FMT("RSSurfaceRenderNodeDrawable::OnDraw SurfaceNode: [%s], NodeId: %llu, ProcessedNodes: %d",
surfaceNode->GetName().c_str(), surfaceNode->GetId(), RSRenderNodeDrawable::GetProcessedNodeCount());
const RSNodeStatsType nodeStats = CreateRSNodeStatsItem(
RSRenderNodeDrawable::GetProcessedNodeCount(), surfaceNode->GetId(), surfaceNode->GetName());
RSNodeStats::GetInstance().AddNodeStats(nodeStats);
}
RSRenderParams::parentSurfaceMatrix_ = parentSurfaceMatrix;

View File

@ -36,6 +36,7 @@
#include "pipeline/sk_resource_manager.h"
#include "platform/common/rs_log.h"
#include "platform/ohos/rs_jank_stats.h"
#include "platform/ohos/rs_node_stats.h"
#ifdef RES_SCHED_ENABLE
#include "system_ability_definition.h"
#include "if_system_ability_manager.h"
@ -242,7 +243,9 @@ void RSUniRenderThread::Render()
}
// TO-DO replace Canvas* with Canvas&
Drawing::Canvas canvas;
RSNodeStats::GetInstance().ClearNodeStats();
rootNodeDrawable_->OnDraw(canvas);
RSNodeStats::GetInstance().ReportRSNodeLimitExceeded();
RSMainThread::Instance()->PerfForBlurIfNeeded();
if (RSMainThread::Instance()->GetMarkRenderFlag() == false) {

View File

@ -55,6 +55,7 @@
#include "platform/common/rs_log.h"
#include "platform/common/rs_system_properties.h"
#include "platform/ohos/rs_jank_stats.h"
#include "platform/ohos/rs_node_stats.h"
#include "property/rs_properties_painter.h"
#include "property/rs_point_light_manager.h"
#include "render/rs_skia_filter.h"
@ -5339,6 +5340,9 @@ void RSUniRenderVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
// count processed canvas node
RS_TRACE_NAME_FMT("%s PureContainerNode/ProcessedNodes: %u/%u", node.GetName().c_str(),
processedPureContainerNode_, processedCanvasNodeInCurrentSurface_);
const RSNodeStatsType nodeStats = CreateRSNodeStatsItem(
processedCanvasNodeInCurrentSurface_, node.GetId(), node.GetName());
RSNodeStats::GetInstance().AddNodeStats(nodeStats);
processedCanvasNodeInCurrentSurface_ = 0; // reset
processedPureContainerNode_ = 0;
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2024 Huawei Device 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.
*/
#ifndef ROSEN_RENDER_SERVICE_BASE_RS_NODE_STATS_H
#define ROSEN_RENDER_SERVICE_BASE_RS_NODE_STATS_H
#include <cstdint>
#include <mutex>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>
#include "common/rs_common_def.h"
#include "nocopyable.h"
namespace OHOS {
namespace Rosen {
using RSNodeCount = uint32_t;
using RSNodeDescription = std::string;
using RSNodeStatsType = std::tuple<RSNodeCount, NodeId, RSNodeDescription>;
inline RSNodeStatsType CreateRSNodeStatsItem(RSNodeCount nodeCount, NodeId nodeId, RSNodeDescription nodeDesc)
{
RSNodeStatsType nodeStats{nodeCount, nodeId, nodeDesc};
return nodeStats;
}
enum class RSNodeStatsUpdateMode : size_t {
SIMPLE_APPEND = 0,
DISCARD_DUPLICATE = 1
};
class RSNodeStats {
public:
static RSNodeStats& GetInstance();
void AddNodeStats(const RSNodeStatsType& nodeStats,
RSNodeStatsUpdateMode updateMode = RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
void ClearNodeStats();
void ReportRSNodeLimitExceeded();
private:
RSNodeStats() = default;
~RSNodeStats() = default;
DISALLOW_COPY_AND_MOVE(RSNodeStats);
void SortNodeStats(bool isSortByNodeCountDescendingOrder = true);
std::pair<RSNodeDescription, RSNodeCount> GetNodeStatsToReportByIndex(size_t index) const;
RSNodeDescription CheckEmptyAndReviseNodeDescription(const RSNodeDescription& nodeDescription) const;
int64_t GetCurrentSystimeMs() const;
int64_t GetCurrentSteadyTimeMs() const;
static constexpr int64_t TIMESTAMP_INITIAL = -1;
static constexpr int64_t REPORT_INTERVAL_LIMIT = 10000; // 10s
static constexpr uint32_t RS_NODE_LIMIT = 500;
static constexpr uint32_t RS_NODE_REPORT_LIMIT = 750;
static inline const std::string RS_NODE_LIMIT_EXCEEDED_EVENT_NAME = "RS_NODE_LIMIT_EXCEEDED";
int64_t lastReportTime_ = TIMESTAMP_INITIAL;
int64_t lastReportTimeSteady_ = TIMESTAMP_INITIAL;
std::mutex mutex_;
std::vector<RSNodeStatsType> rsNodeStatsVec_;
std::unordered_set<NodeId> rsNodeIdSet_;
uint32_t rsNodeCountTotal_ = 0;
};
} // namespace Rosen
} // namespace OHOS
#endif // ROSEN_RENDER_SERVICE_BASE_RS_NODE_STATS_H

View File

@ -57,6 +57,7 @@ ohos_source_set("rosen_ohos_sources") {
"rs_jank_stats.cpp",
"rs_log.cpp",
"rs_marshalling_helper.cpp",
"rs_node_stats.cpp",
"rs_render_service_client.cpp",
"rs_render_service_connect_hub.cpp",
"rs_render_service_connection_proxy.cpp",

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2024 Huawei Device 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.
*/
#include "platform/ohos/rs_node_stats.h"
#include <algorithm>
#include <chrono>
#include <sys/time.h>
#include <unistd.h>
#include "hisysevent.h"
#include "rs_trace.h"
#include "platform/common/rs_log.h"
namespace OHOS {
namespace Rosen {
namespace {
constexpr size_t TOP1_INDEX = 0;
constexpr size_t TOP2_INDEX = 1;
constexpr size_t TOP3_INDEX = 2;
constexpr size_t EMPTY_NODE_DESCRIPTION_SIZE = 0;
constexpr RSNodeCount NONE_NODE_COUNT = 0;
const RSNodeDescription NONE_NODE_DESCRIPTION = "NaN";
const RSNodeDescription EMPTY_NODE_DESCRIPTION = "EmptyName";
}
RSNodeStats& RSNodeStats::GetInstance()
{
static RSNodeStats instance;
return instance;
}
void RSNodeStats::AddNodeStats(const RSNodeStatsType& nodeStats, RSNodeStatsUpdateMode updateMode)
{
std::lock_guard<std::mutex> lock(mutex_);
NodeId nodeId = std::get<NodeId>(nodeStats);
if (updateMode == RSNodeStatsUpdateMode::DISCARD_DUPLICATE && rsNodeIdSet_.find(nodeId) != rsNodeIdSet_.end()) {
return;
}
rsNodeIdSet_.insert(nodeId);
rsNodeStatsVec_.push_back(nodeStats);
rsNodeCountTotal_ += std::get<RSNodeCount>(nodeStats);
}
void RSNodeStats::ClearNodeStats()
{
std::lock_guard<std::mutex> lock(mutex_);
rsNodeIdSet_.clear();
rsNodeStatsVec_.clear();
rsNodeCountTotal_ = 0;
}
void RSNodeStats::ReportRSNodeLimitExceeded()
{
std::lock_guard<std::mutex> lock(mutex_);
if (rsNodeCountTotal_ < RS_NODE_REPORT_LIMIT) {
return;
}
int64_t curSysTime = GetCurrentSystimeMs();
int64_t curSteadyTime = GetCurrentSteadyTimeMs();
if (lastReportTime_ != TIMESTAMP_INITIAL && lastReportTimeSteady_ != TIMESTAMP_INITIAL &&
(curSysTime - lastReportTime_ <= REPORT_INTERVAL_LIMIT ||
curSteadyTime - lastReportTimeSteady_ <= REPORT_INTERVAL_LIMIT)) {
return;
}
SortNodeStats();
const auto nodeInfoTop1 = GetNodeStatsToReportByIndex(TOP1_INDEX);
const auto nodeInfoTop2 = GetNodeStatsToReportByIndex(TOP2_INDEX);
const auto nodeInfoTop3 = GetNodeStatsToReportByIndex(TOP3_INDEX);
RS_TRACE_NAME_FMT("RSNodeStats::ReportRSNodeLimitExceeded "
"nodeCount=%u, top1=%u [%s], top2=%u [%s], top3=%u [%s], timestamp=%" PRId64,
rsNodeCountTotal_, nodeInfoTop1.second, nodeInfoTop1.first.c_str(), nodeInfoTop2.second,
nodeInfoTop2.first.c_str(), nodeInfoTop3.second, nodeInfoTop3.first.c_str(), curSysTime);
HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::GRAPHIC,
RS_NODE_LIMIT_EXCEEDED_EVENT_NAME,
OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
"RS_NODE_LIMIT", RS_NODE_LIMIT,
"RS_ACTUAL_NODE", rsNodeCountTotal_,
"TIMESTAMP", static_cast<uint64_t>(curSysTime),
"RS_APP_WINDOW_TOTAL", static_cast<uint32_t>(rsNodeStatsVec_.size()),
"RS_TOP1_APP_NAME", nodeInfoTop1.first,
"RS_TOP1_APP_NODE", nodeInfoTop1.second,
"RS_TOP2_APP_NAME", nodeInfoTop2.first,
"RS_TOP2_APP_NODE", nodeInfoTop2.second,
"RS_TOP3_APP_NAME", nodeInfoTop3.first,
"RS_TOP3_APP_NODE", nodeInfoTop3.second);
lastReportTime_ = curSysTime;
lastReportTimeSteady_ = curSteadyTime;
}
void RSNodeStats::SortNodeStats(bool isSortByNodeCountDescendingOrder)
{
std::sort(rsNodeStatsVec_.begin(), rsNodeStatsVec_.end());
if (isSortByNodeCountDescendingOrder) {
std::reverse(rsNodeStatsVec_.begin(), rsNodeStatsVec_.end());
}
}
std::pair<RSNodeDescription, RSNodeCount> RSNodeStats::GetNodeStatsToReportByIndex(size_t index) const
{
if (index < rsNodeStatsVec_.size()) {
const RSNodeStatsType& nodeStats = rsNodeStatsVec_.at(index);
RSNodeDescription nodeDescription = std::get<RSNodeDescription>(nodeStats);
nodeDescription = CheckEmptyAndReviseNodeDescription(nodeDescription);
RSNodeCount nodeCount = std::get<RSNodeCount>(nodeStats);
return std::make_pair(nodeDescription, nodeCount);
}
return std::make_pair(NONE_NODE_DESCRIPTION, NONE_NODE_COUNT);
}
RSNodeDescription RSNodeStats::CheckEmptyAndReviseNodeDescription(const RSNodeDescription& nodeDescription) const
{
if (nodeDescription.size() == EMPTY_NODE_DESCRIPTION_SIZE) {
return EMPTY_NODE_DESCRIPTION;
}
return nodeDescription;
}
int64_t RSNodeStats::GetCurrentSystimeMs() const
{
auto curTime = std::chrono::system_clock::now().time_since_epoch();
int64_t curSysTime = std::chrono::duration_cast<std::chrono::milliseconds>(curTime).count();
return curSysTime;
}
int64_t RSNodeStats::GetCurrentSteadyTimeMs() const
{
auto curTime = std::chrono::steady_clock::now().time_since_epoch();
int64_t curSteadyTime = std::chrono::duration_cast<std::chrono::milliseconds>(curTime).count();
return curSteadyTime;
}
} // namespace Rosen
} // namespace OHOS

View File

@ -28,6 +28,7 @@ ohos_unittest("RSRenderServiceBasePlatformTest") {
"rs_innovation_test.cpp",
"rs_jank_stats_test.cpp",
"rs_log_test.cpp",
"rs_node_stats_test.cpp",
"rs_render_service_client_test.cpp",
"rs_render_service_connect_hub_test.cpp",
"rs_render_service_proxy_test.cpp",

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2024 Huawei Device 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, Hardware
* 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.
*/
#include <gtest/gtest.h>
#include "platform/ohos/rs_node_stats.h"
#include <chrono>
#include <sys/time.h>
#include <unistd.h>
using namespace testing;
using namespace testing::ext;
namespace OHOS {
namespace Rosen {
class RSNodeStatsTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
void SetUp() override;
void TearDown() override;
};
void RSNodeStatsTest::SetUpTestCase() {}
void RSNodeStatsTest::TearDownTestCase() {}
void RSNodeStatsTest::SetUp() {}
void RSNodeStatsTest::TearDown() {}
/**
* @tc.name: AddNodeStatsTest1
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, AddNodeStatsTest1, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(100, 1000, "Node1");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(200, 2000, "");
RSNodeStatsType nodeStats3 = CreateRSNodeStatsItem(300, 3000, "Node3");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::SIMPLE_APPEND);
}
/**
* @tc.name: AddNodeStatsTest2
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, AddNodeStatsTest2, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(400, 1000, "");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(500, 1000, "Node2");
RSNodeStatsType nodeStats3 = CreateRSNodeStatsItem(600, 3000, "");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
}
/**
* @tc.name: ClearNodeStatsTest
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, ClearNodeStatsTest, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
rsNodeStats.ClearNodeStats();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(700, 1000, "Node1");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(800, 2000, "Node2");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.ClearNodeStats();
}
/**
* @tc.name: ReportRSNodeLimitExceededTest1
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, ReportRSNodeLimitExceededTest1, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(350, 1000, "Node1");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(450, 2000, "Node2");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.ReportRSNodeLimitExceeded();
}
/**
* @tc.name: ReportRSNodeLimitExceededTest2
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, ReportRSNodeLimitExceededTest2, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(100, 1000, "Node1");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(200, 2000, "Node2");
RSNodeStatsType nodeStats3 = CreateRSNodeStatsItem(300, 3000, "");
RSNodeStatsType nodeStats4 = CreateRSNodeStatsItem(200, 4000, "Node4");
RSNodeStatsType nodeStats5 = CreateRSNodeStatsItem(100, 5000, "Node5");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats4, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats5, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.ReportRSNodeLimitExceeded();
}
/**
* @tc.name: ReportRSNodeLimitExceededTest3
* @tc.desc:
* @tc.type:FUNC
* @tc.require:
*/
HWTEST_F(RSNodeStatsTest, ReportRSNodeLimitExceededTest3, TestSize.Level1)
{
auto& rsNodeStats = RSNodeStats::GetInstance();
RSNodeStatsType nodeStats1 = CreateRSNodeStatsItem(100, 1000, "Node1");
RSNodeStatsType nodeStats2 = CreateRSNodeStatsItem(200, 1000, "");
RSNodeStatsType nodeStats3 = CreateRSNodeStatsItem(300, 3000, "Node3");
RSNodeStatsType nodeStats4 = CreateRSNodeStatsItem(200, 4000, "");
RSNodeStatsType nodeStats5 = CreateRSNodeStatsItem(100, 4000, "Node5");
rsNodeStats.AddNodeStats(nodeStats1, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats4, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.AddNodeStats(nodeStats5, RSNodeStatsUpdateMode::DISCARD_DUPLICATE);
rsNodeStats.ReportRSNodeLimitExceeded();
usleep(100000);
rsNodeStats.ReportRSNodeLimitExceeded();
rsNodeStats.ClearNodeStats();
rsNodeStats.ReportRSNodeLimitExceeded();
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats2, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats3, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats4, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.AddNodeStats(nodeStats4, RSNodeStatsUpdateMode::SIMPLE_APPEND);
rsNodeStats.ReportRSNodeLimitExceeded();
}
} // namespace Rosen
} // namespace OHOS