From 5d2fa024ea5a60560af411e34080676bb5d405fb Mon Sep 17 00:00:00 2001 From: Galaxy Date: Wed, 24 Apr 2024 01:51:05 -0700 Subject: [PATCH 1/2] Fix return code of PmuDisable --- pmu/evt.cpp | 2 +- pmu/pmu.cpp | 14 ++++++++++++-- test/test_perf/test_api.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/pmu/evt.cpp b/pmu/evt.cpp index 84fdeea..f459d2a 100644 --- a/pmu/evt.cpp +++ b/pmu/evt.cpp @@ -53,7 +53,7 @@ int KUNPENG_PMU::PerfEvt::Reset() int KUNPENG_PMU::PerfEvt::Disable() { - if (ioctl(this->fd, PERF_EVENT_IOC_DISABLE, 0)) { + if (ioctl(this->fd, PERF_EVENT_IOC_DISABLE, 0) == 0) { return SUCCESS; } return LIBPERF_ERR_FAILED_PMU_DISABLE; diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index 5c8d888..a7cc2f1 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -41,12 +41,22 @@ struct PmuTaskAttr* AssignPmuTaskParam(PmuTaskType collectType, struct PmuAttr * static int PmuCollectStart(const int pd) { - return KUNPENG_PMU::PmuList::GetInstance()->Start(pd); + auto err = KUNPENG_PMU::PmuList::GetInstance()->Start(pd); + if (err != SUCCESS) { + New(err); + return -1; + } + return SUCCESS; } static int PmuCollectPause(const int pd) { - return KUNPENG_PMU::PmuList::GetInstance()->Pause(pd); + auto err = KUNPENG_PMU::PmuList::GetInstance()->Pause(pd); + if (err != SUCCESS) { + New(err); + return -1; + } + return SUCCESS; } static int CheckCpuList(unsigned numCpu, int* cpuList) diff --git a/test/test_perf/test_api.cpp b/test/test_perf/test_api.cpp index 2b72cee..53f9c5e 100644 --- a/test/test_perf/test_api.cpp +++ b/test/test_perf/test_api.cpp @@ -349,4 +349,35 @@ TEST_F(TestAPI, RaiseNumFd) ASSERT_EQ(err, SUCCESS); err = RaiseNumFd(currentlim.rlim_max - 51); ASSERT_EQ(err, SUCCESS); +} + +TEST_F(TestAPI, NoDataBeforeEnable) +{ + auto attr = GetPmuAttribute(); + int pd = PmuOpen(SAMPLING, &attr); + PmuData *data = nullptr; + int len = PmuRead(pd, &data); + ASSERT_EQ(len, 0); + int err = PmuEnable(pd); + ASSERT_EQ(err, SUCCESS); + usleep(1000); + len = PmuRead(pd, &data); + ASSERT_GT(len, 0); + PmuDisable(pd); +} + +TEST_F(TestAPI, NoDataAfterDisable) +{ + auto attr = GetPmuAttribute(); + int pd = PmuOpen(SAMPLING, &attr); + int err = PmuEnable(pd); + ASSERT_EQ(err, SUCCESS); + usleep(1000); + PmuData *data = nullptr; + int len = PmuRead(pd, &data); + ASSERT_GT(len, 0); + err = PmuDisable(pd); + ASSERT_EQ(err, SUCCESS); + len = PmuRead(pd, &data); + ASSERT_EQ(len, 0); } \ No newline at end of file -- Gitee From 4f234dd5846ff962a3f620a52d17ec04c5d7b000 Mon Sep 17 00:00:00 2001 From: Galaxy Date: Wed, 24 Apr 2024 16:08:16 +0100 Subject: [PATCH 2/2] Add test cases. Add Unit test cases for: - branch pred miss - cache miss - last level cache miss --- pmu/pmu.cpp | 2 +- pmu/spe.cpp | 2 +- test/test_perf/case/CMakeLists.txt | 2 +- test/test_perf/case/bad_branch_pred.cpp | 36 ++++++++ test/test_perf/case/bad_cache_locality.cpp | 36 ++++++++ test/test_perf/case/cross_socket_access.cpp | 48 +++++++++++ test/test_perf/case/good_branch_pred.cpp | 36 ++++++++ test/test_perf/case/good_cache_locality.cpp | 36 ++++++++ test/test_perf/case/in_node_access.cpp | 48 +++++++++++ test/test_perf/test_api.cpp | 73 ++++++++++++++-- test/test_perf/test_count.cpp | 93 ++++++++++++++++++++- test/test_perf/test_pmu.cpp | 23 ++++- 12 files changed, 425 insertions(+), 10 deletions(-) create mode 100644 test/test_perf/case/bad_branch_pred.cpp create mode 100644 test/test_perf/case/bad_cache_locality.cpp create mode 100644 test/test_perf/case/cross_socket_access.cpp create mode 100644 test/test_perf/case/good_branch_pred.cpp create mode 100644 test/test_perf/case/good_cache_locality.cpp create mode 100644 test/test_perf/case/in_node_access.cpp diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index a7cc2f1..bfc45d7 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -489,7 +489,7 @@ int PmuRead(int pd, struct PmuData** pmuData) try { if (!PdValid(pd)) { New(LIBPERF_ERR_INVALID_PD); - return LIBPERF_ERR_INVALID_PD; + return -1; } auto& retData = KUNPENG_PMU::PmuList::GetInstance()->Read(pd); diff --git a/pmu/spe.cpp b/pmu/spe.cpp index 940147d..8470edd 100644 --- a/pmu/spe.cpp +++ b/pmu/spe.cpp @@ -405,7 +405,7 @@ static void SetTidByTimestamp(struct ContextSwitchData *dummyData, int *dummyIdx start->cpu = cpu; start->timestamp = recordTime; - if (start->tid != 0) { + if (start->tid != -1) { // In some kernel versions, tid is contained in spe packet, // which has been decoded in arm_spe_decoder.cpp. // Then we do not need dummy events to derive tid for this packet. diff --git a/test/test_perf/case/CMakeLists.txt b/test/test_perf/case/CMakeLists.txt index 092c611..bce7eda 100644 --- a/test/test_perf/case/CMakeLists.txt +++ b/test/test_perf/case/CMakeLists.txt @@ -1,4 +1,4 @@ -set(source_files simple.cpp test_12threads.cpp test_create_thread.cpp test_fork.cpp write_on_numa2.cpp pwritev_file.cpp) +file(GLOB source_files ./*.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") set(CMAKE_CXX_FLAGS_RELEASE "") diff --git a/test/test_perf/case/bad_branch_pred.cpp b/test/test_perf/case/bad_branch_pred.cpp new file mode 100644 index 0000000..74e27ec --- /dev/null +++ b/test/test_perf/case/bad_branch_pred.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: A loop with a random condition. + ******************************************************************************/ +#include +#include + +int main() +{ + int len = 10000000; + int *cond = new int[len]; + for (int i = 0; i < len; ++i) { + cond[i] = rand(); + } + int sum = 0; + for (int i = 0; i < 10000000;++i) + { + if (cond[i] % 4) { + sum++; + } else { + sum--; + } + } + + return 0; +} diff --git a/test/test_perf/case/bad_cache_locality.cpp b/test/test_perf/case/bad_cache_locality.cpp new file mode 100644 index 0000000..20cda9b --- /dev/null +++ b/test/test_perf/case/bad_cache_locality.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: A loop with a discontinuous read. + ******************************************************************************/ +int main() +{ + int len = 10000; + int **array = new int*[len]; + for (int i = 0;i < len; ++i) { + array[i] = new int[len]; + for (int j = 0;j < len;++j) { + array[i][j] = i + j; + } + } + + int sum = 0; + for (int i = 0;i < len; ++i) { + array[i] = new int[len]; + for (int j = 0;j < len;++j) { + // Discontinuous read. + sum += array[j][i]; + } + } + + return sum; +} \ No newline at end of file diff --git a/test/test_perf/case/cross_socket_access.cpp b/test/test_perf/case/cross_socket_access.cpp new file mode 100644 index 0000000..2a7d0a3 --- /dev/null +++ b/test/test_perf/case/cross_socket_access.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: Two threads running on different numa nodes. + ******************************************************************************/ +#include +#include +#include + +using namespace std; + +void func(int *val) +{ + while(1) { + (*val)++; + } +} + +int main() +{ + int *a = new int(); + pthread_t t1,t2; + pthread_create(&t1, NULL, (void* (*)(void*))func, a); + pthread_create(&t2, NULL, (void* (*)(void*))func, a); + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + pthread_setaffinity_np(t1, sizeof(cpu_set_t), &cpuset); + + cpu_set_t cpuset2; + CPU_ZERO(&cpuset2); + CPU_SET(numa_num_task_cpus() - 1, &cpuset2); + pthread_setaffinity_np(t2, sizeof(cpu_set_t), &cpuset2); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); + return 0; +} \ No newline at end of file diff --git a/test/test_perf/case/good_branch_pred.cpp b/test/test_perf/case/good_branch_pred.cpp new file mode 100644 index 0000000..527115c --- /dev/null +++ b/test/test_perf/case/good_branch_pred.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: A loop with a predictable condition. + ******************************************************************************/ +#include +#include + +int main() +{ + int len = 10000000; + int *cond = new int[len]; + for (int i = 0; i < len; ++i) { + cond[i] = i; + } + int sum = 0; + for (int i = 0; i < 10000000;++i) + { + if (cond[i] % 4) { + sum++; + } else { + sum--; + } + } + + return 0; +} diff --git a/test/test_perf/case/good_cache_locality.cpp b/test/test_perf/case/good_cache_locality.cpp new file mode 100644 index 0000000..b082444 --- /dev/null +++ b/test/test_perf/case/good_cache_locality.cpp @@ -0,0 +1,36 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: A loop with a continuous read. + ******************************************************************************/ +int main() +{ + int len = 10000; + int **array = new int*[len]; + for (int i = 0;i < len; ++i) { + array[i] = new int[len]; + for (int j = 0;j < len;++j) { + array[i][j] = i + j; + } + } + + int sum = 0; + for (int i = 0;i < len; ++i) { + array[i] = new int[len]; + for (int j = 0;j < len;++j) { + // Continuous read. + sum += array[i][j]; + } + } + + return sum; +} \ No newline at end of file diff --git a/test/test_perf/case/in_node_access.cpp b/test/test_perf/case/in_node_access.cpp new file mode 100644 index 0000000..b1baa68 --- /dev/null +++ b/test/test_perf/case/in_node_access.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + * libkperf licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + * Author: Mr.Gan + * Create: 2024-04-26 + * Description: Two threads running on the same numa node. + ******************************************************************************/ +#include +#include +#include + +using namespace std; + +void func(int *val) +{ + while(1) { + (*val)++; + } +} + +int main() +{ + int *a = new int(); + pthread_t t1,t2; + pthread_create(&t1, NULL, (void* (*)(void*))func, a); + pthread_create(&t2, NULL, (void* (*)(void*))func, a); + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(0, &cpuset); + pthread_setaffinity_np(t1, sizeof(cpu_set_t), &cpuset); + + cpu_set_t cpuset2; + CPU_ZERO(&cpuset2); + CPU_SET(1, &cpuset2); + pthread_setaffinity_np(t2, sizeof(cpu_set_t), &cpuset2); + + pthread_join(t1, NULL); + pthread_join(t2, NULL); + return 0; +} \ No newline at end of file diff --git a/test/test_perf/test_api.cpp b/test/test_perf/test_api.cpp index 53f9c5e..6c63e89 100644 --- a/test/test_perf/test_api.cpp +++ b/test/test_perf/test_api.cpp @@ -356,11 +356,13 @@ TEST_F(TestAPI, NoDataBeforeEnable) auto attr = GetPmuAttribute(); int pd = PmuOpen(SAMPLING, &attr); PmuData *data = nullptr; + // No data before PmuEnable. int len = PmuRead(pd, &data); ASSERT_EQ(len, 0); int err = PmuEnable(pd); ASSERT_EQ(err, SUCCESS); - usleep(1000); + sleep(1); + // Has data after PmuEnable. len = PmuRead(pd, &data); ASSERT_GT(len, 0); PmuDisable(pd); @@ -372,12 +374,73 @@ TEST_F(TestAPI, NoDataAfterDisable) int pd = PmuOpen(SAMPLING, &attr); int err = PmuEnable(pd); ASSERT_EQ(err, SUCCESS); - usleep(1000); + sleep(1); + err = PmuDisable(pd); + ASSERT_EQ(err, SUCCESS); PmuData *data = nullptr; + // Read data from buffer. int len = PmuRead(pd, &data); ASSERT_GT(len, 0); - err = PmuDisable(pd); - ASSERT_EQ(err, SUCCESS); + // No data after PmuDisable. len = PmuRead(pd, &data); ASSERT_EQ(len, 0); -} \ No newline at end of file +} + +TEST_F(TestAPI, AppendPmuDataToNullArray) +{ + auto attr = GetPmuAttribute(); + int pd = PmuOpen(SAMPLING, &attr); + int err = PmuEnable(pd); + ASSERT_EQ(err, SUCCESS); + + usleep(1000 * 100); + // Declare a null array. + PmuData *total = nullptr; + PmuData *data = nullptr; + // Append pmu data to null array, and they will have the same length. + int len1 = PmuRead(pd, &data); + int totalLen = PmuAppendData(data, &total); + ASSERT_EQ(len1, totalLen); + PmuDataFree(data); + + usleep(1000 * 100); + // Get another pmu data array. + int len2 = PmuRead(pd, &data); + // Append to again. + totalLen = PmuAppendData(data, &total); + ASSERT_EQ(len1 + len2, totalLen); + PmuDataFree(data); + PmuDataFree(total); +} + + +TEST_F(TestAPI, AppendPmuDataToExistArray) +{ + auto attr = GetPmuAttribute(); + int pd = PmuOpen(COUNTING, &attr); + int err = PmuEnable(pd); + ASSERT_EQ(err, SUCCESS); + + usleep(1000 * 100); + // Get one pmu data array. + PmuData *data1 = nullptr; + int len1 = PmuRead(pd, &data1); + + usleep(1000 * 100); + // Get another pmu data array. + PmuData *data2 = nullptr; + int len2 = PmuRead(pd, &data2); + // Append to ; + int totalLen = PmuAppendData(data2, &data1); + // The total length is sum of two data length. + ASSERT_EQ(len1 + len2, totalLen); + + // Check data of the second part of , + // which equals to . + for (int i = 0; i < len2; ++i) { + ASSERT_EQ(data1[i + len1].count, data2[i].count); + } + + PmuDataFree(data1); + PmuDataFree(data2); +} diff --git a/test/test_perf/test_count.cpp b/test/test_perf/test_count.cpp index 9b566c1..06231d3 100644 --- a/test/test_perf/test_count.cpp +++ b/test/test_perf/test_count.cpp @@ -32,10 +32,39 @@ public: } protected: + map CollectProcessEvent(const string &caseName, const vector &evtName) + { + appPid = RunTestApp(caseName); + int pidList[1] = {appPid}; + char **evtList = new char *[evtName.size()]; + for (int i = 0; i < evtName.size(); ++i) + { + evtList[i] = const_cast(evtName[i].c_str()); + } + PmuAttr attr = {0}; + attr.pidList = pidList; + attr.numPid = 1; + attr.evtList = evtList; + attr.numEvt = evtName.size(); + + pd = PmuOpen(COUNTING, &attr); + PmuCollect(pd, 4000, collectInterval); + KillApp(appPid); + int len = PmuRead(pd, &data); + map ret; + for (int i = 0; i < len; ++i) + { + ret[data[i].evt] += data[i].count; + } + delete[] evtList; + return ret; + } + int pd; pid_t appPid = 0; PmuData *data = nullptr; static const unsigned collectInterval = 100; + static constexpr float relativeErr = 0.01; }; TEST_F(TestCount, CountProcess) @@ -158,4 +187,66 @@ TEST_F(TestCount, PwritevFile) int len = PmuRead(pd, &data); ASSERT_EQ(len, 1); ASSERT_GT(data->count, 0); -} \ No newline at end of file +} + +TEST_F(TestCount, BranchMissRatio) +{ + // Check branch miss ratio of two cases. + // One case has bad condition and one case has a predictable condition. + string brMis = "branch-load-misses"; + string brPred = "branch-loads"; + vector branchEvts = {brMis, brPred}; + auto evtMap = CollectProcessEvent("bad_branch_pred", branchEvts); + auto missRatio1 = (double)evtMap[brMis]/evtMap[brPred]; + ASSERT_LT(missRatio1, 0.2); + evtMap = CollectProcessEvent("good_branch_pred", branchEvts); + auto missRatio2 = (double)evtMap[brMis]/evtMap[brPred]; + ASSERT_LT(missRatio2, 0.2); + ASSERT_GT(missRatio1, missRatio2); +} + +TEST_F(TestCount, BranchMissEvents) +{ + // Check event count of branch-load-misses and branch-misses. + // They should be very close. + vector branchEvts = {"branch-load-misses", "branch-misses", "br_mis_pred"}; + auto evtMap = CollectProcessEvent("bad_branch_pred", branchEvts); + ASSERT_EQ(evtMap.size(), branchEvts.size()); + ASSERT_NEAR(evtMap["branch-load-misses"], evtMap["branch-misses"], evtMap["branch-misses"] * relativeErr); + ASSERT_NEAR(evtMap["br_mis_pred"], evtMap["branch-misses"], evtMap["branch-misses"] * relativeErr); +} + +TEST_F(TestCount, L1CacheMissRatio) +{ + // Check cache miss ratio of two cases. + // One case has bad locality and one case has good locality. + string cacheMiss = "l1d_cache_refill"; + string cache = "l1d_cache"; + vector evts = {cacheMiss, cache}; + auto evtMap = CollectProcessEvent("bad_cache_locality", evts); + ASSERT_EQ(evtMap.size(), evts.size()); + auto missRatio1 = (double)evtMap[cacheMiss]/evtMap[cache]; + ASSERT_GT(missRatio1, 0.01); + evtMap = CollectProcessEvent("good_cache_locality", evts); + auto missRatio2 = (double)evtMap[cacheMiss]/evtMap[cache]; + ASSERT_LT(missRatio2, 0.01); + ASSERT_GT(missRatio1, missRatio2); +} + +TEST_F(TestCount, LLCacheMissRatio) +{ + // Check last level cache miss ratio of two cases. + // One case has two threads in the same node, + // and one case has two threads in different sockets. + string cacheMiss = "ll_cache_miss"; + string cache = "ll_cache"; + vector evts = {cacheMiss, cache}; + auto evtMap = CollectProcessEvent("cross_socket_access", evts); + ASSERT_EQ(evtMap.size(), evts.size()); + auto missRatio1 = (double)evtMap[cacheMiss]/evtMap[cache]; + ASSERT_GT(missRatio1, 0.2); + evtMap = CollectProcessEvent("in_node_access", evts); + auto missRatio2 = (double)evtMap[cacheMiss]/evtMap[cache]; + ASSERT_LT(missRatio2, 0.01); + ASSERT_GT(missRatio1, missRatio2); +} diff --git a/test/test_perf/test_pmu.cpp b/test/test_perf/test_pmu.cpp index 542ac70..7538f5f 100644 --- a/test/test_perf/test_pmu.cpp +++ b/test/test_perf/test_pmu.cpp @@ -160,4 +160,25 @@ TEST_F(TestPMU, PmuProcCollectSubProc) int len = PmuRead(pd, &data); ASSERT_TRUE(data != nullptr); ASSERT_TRUE(FoundAllChildren(data, len, appPid)); -} \ No newline at end of file +} + +TEST_F(TestPMU, NoDataAfterDisable) +{ + // Start a 12-thread process. + // Threads are created on startup. + appPid = RunTestApp("test_12threads"); + pid_t pidList[1] = {appPid}; + auto attr = GetProcAttribute(pidList, 1); + auto pd = PmuOpen(SAMPLING, &attr); + PmuEnable(pd); + sleep(1); + // Disable sampling. + PmuDisable(pd); + // Read data for current sampling. + int len = PmuRead(pd, &data); + ASSERT_GT(len, 0); + // Read again and get no data. + len = PmuRead(pd, &data); + ASSERT_EQ(len, 0); +} + -- Gitee