diff --git a/include/pcerrc.h b/include/pcerrc.h index 4151cfc5273b92977ddeb0f6f37346ba05fcb753..9d5f4f6777dc0bb4123393d4e0dca21e30526db9 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -122,6 +122,7 @@ extern "C" { #define LIBPERF_ERR_ENABLE_USER_ACCESS_FAILED 1075 #define LIBPERF_ERR_ALLOCATE_REGISTER_FAILED 1076 #define LIBPERF_ERR_CHECK_USER_ACCESS 1077 +#define LIBPERF_ERR_COUNTER_INDEX_IS_ZERO 1078 #define UNKNOWN_ERROR 9999 diff --git a/pmu/evt_list.cpp b/pmu/evt_list.cpp index c9a5dac44bc46e1e7d053f7ca778677be8d9c0d6..7e93c0db746550729aae80501b5bbfd4a8ca4c88 100644 --- a/pmu/evt_list.cpp +++ b/pmu/evt_list.cpp @@ -93,6 +93,9 @@ void KUNPENG_PMU::EvtList::AdaptErrInfo(int err, PerfEvtPtr perfEvt) pcerr::SetCustomErr(err, std::string{strerror(errno)}); } break; + case LIBPERF_ERR_COUNTER_INDEX_IS_ZERO: + pcerr::SetCustomErr(err, "There are too many open events. No registers are available."); + break; case UNKNOWN_ERROR: pcerr::SetCustomErr(err, std::string{strerror(errno)}); break; diff --git a/pmu/perf_counter.cpp b/pmu/perf_counter.cpp index b5784937dd23779c38264ba5a5a34c559130f5dc..cd00fc50ddd914e852a157d83eb8cb6593a72589 100644 --- a/pmu/perf_counter.cpp +++ b/pmu/perf_counter.cpp @@ -380,6 +380,9 @@ int KUNPENG_PMU::PerfCounter::Mmap() return LIBPERF_ERR_FAIL_MMAP; } this->countMmap->base = static_cast(currentMap); + if (this->countMmap->base->index == 0) { + return LIBPERF_ERR_COUNTER_INDEX_IS_ZERO; + } this->countMmap->fd = this->fd; return SUCCESS; } diff --git a/test/test_perf/test_api.cpp b/test/test_perf/test_api.cpp index a08152091c22a62f5ea5b23391a4c74324ee2c49..e81664222997993f1044a056727845ad5a3d17cf 100644 --- a/test/test_perf/test_api.cpp +++ b/test/test_perf/test_api.cpp @@ -14,6 +14,7 @@ ******************************************************************************/ #include #include +#include #include "util_time.h" #include "process_map.h" #include "common.h" @@ -735,3 +736,34 @@ TEST_F(TestAPI, InvalidCgroupNameListSPE) auto pd = PmuOpen(SPE_SAMPLING, &attr); ASSERT_EQ(pd, -1); } + +TEST_F(TestAPI, InvalidUserAccessAttr) +{ + if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) { + GTEST_SKIP(); + } + PmuAttr attr = {0}; + attr.enableUserAccess = 1; + char *evtList[1]; + evtList[0] = (char *)"cycles"; + attr.evtList = evtList; + attr.numEvt = 1; + int pidList[1] = {0}; + attr.pidList = pidList; + attr.numPid = 1; + int cpuList[1] = {-1}; + attr.cpuList = cpuList; + attr.numCpu = 1; + auto pd = PmuOpen(COUNTING, &attr); + ASSERT_NE(pd, -1); + PmuClose(pd); + pd = PmuOpen(SAMPLING, &attr); + ASSERT_EQ(pd, -1); + pidList[0] = 999; + pd = PmuOpen(COUNTING, &attr); + ASSERT_EQ(pd, -1); + pidList[0] = 0; + cpuList[0] = 2; + pd = PmuOpen(COUNTING, &attr); + ASSERT_EQ(pd, -1); +} diff --git a/test/test_perf/test_user_access.cpp b/test/test_perf/test_user_access.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e086e91281e700c2205b03283c6485cc0477a74b --- /dev/null +++ b/test/test_perf/test_user_access.cpp @@ -0,0 +1,182 @@ +/****************************************************************************** + * 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: yupan + * Create: 2025-08-04 + * Description: Unit test for counting. + ******************************************************************************/ +#include "test_common.h" +#include "common.h" +#include + +using namespace std; + +class TestUserAccessCount : public testing::Test { +public: + TestUserAccessCount() + { + attr.enableUserAccess = 1; + attr.pidList = pids; + attr.numPid = 1; + attr.cpuList = cpus; + attr.numCpu = 1; + } + +protected: + PmuAttr attr{0}; + int pids[1] = {0}; + int cpus[1] = {-1}; + std::vector events = {"branch-misses", + "bus-cycles", + "cache-misses", + "cache-references", + "cpu-cycles", + "instructions", + "stalled-cycles-backend", + "stalled-cycles-frontend", + "L1-dcache-loads", + "L1-dcache-load-misses", + "L1-icache-loads", + "L1-icache-load-misses", + "LLC-loads", + "LLC-load-misses", + "dTLB-loads", + "dTLB-load-misses", + "iTLB-loads", + "iTLB-load-misses", + "branch-loads", + "branch-load-misses", + "br_mis_pred", + "dTLB-load-misses" + "br_mis_pred_retired", + "br_pred", + "br_retired", + "br_return_retired", + "bus_access", + "bus_cycles", + "cid_write_retired", + "cpu_cycles", + "dtlb_walk", + "exc_return", + "exc_taken", + "inst_retired", + "inst_spec", + "itlb_walk", + "l1d_cache", + "l1d_cache_refill", + "l1d_cache_wb", + "l1d_tlb", + "l1d_tlb_refill", + "l1i_cache", + "l1i_cache_refill", + "l1i_tlb", + "l1i_tlb_refill", + "l2d_cache", + "l2d_cache_refill", + "l2d_cache_wb", + "l2d_tlb", + "l2d_tlb_refill", + "l2i_cache", + "l2i_cache_refill", + "l2i_tlb", + "l2i_tlb_refill", + "ll_cache", + "ll_cache_miss", + "ll_cache_miss_rd", + "ll_cache_rd", + "mem_access", + "memory_error", + "remote_access", + "remote_access_rd", + "sample_collision", + "sample_feed", + "sample_filtrate", + "sample_pop", + "stall_backend", + "stall_frontend", + "ttbr_write_retired", + "exe_stall_cycle", + "fetch_bubble", + "hit_on_prf", + "if_is_stall", + "iq_is_empty", + "l1d_cache_inval", + "l1d_cache_rd", + "l1d_cache_refill_rd", + "l1d_cache_wb_clean", + "l1d_cache_wb_victim", + "l1d_cache_wr", + "l1d_tlb_rd", + "l1d_tlb_refill_rd", + "l1d_tlb_refill_wr", + "l1d_tlb_wr", + "l1i_cache_prf", + "l1i_cache_prf_refill", + "l2d_cache_inval", + "l2d_cache_rd", + "l2d_cache_refill_rd", + "l2d_cache_wb_clean", + "l2d_cache_wb_victim", + "l2d_cache_wr", + "mem_stall_anyload", + "mem_stall_l1miss", + "mem_stall_l2miss", + "prf_req"}; +}; + +TEST_F(TestUserAccessCount, TestReadEvent) +{ + if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) { + GTEST_SKIP(); + } + attr.numEvt = 1; + char *evtList[1]; + for (int i = 0; i < events.size(); i++) { + evtList[0] = const_cast(events[i].data()); + attr.evtList = evtList; + int pd = PmuOpen(COUNTING, &attr); + if (pd == -1) { + printf("PmuOpen failed : %s\n", Perror()); + PmuClose(pd); + continue; + } + ASSERT_NE(pd, -1); + PmuEnable(pd); + PmuData *data = nullptr; + int len = PmuRead(pd, &data); + printf("==============\n"); + for (int i = 0; i < 2; i++) { + int k = 1e8; + while (k > 0) { + k--; + } + PmuDataFree(data); + len = PmuRead(pd, &data); + ASSERT_EQ(len, 1); + if (len > 0) { + for (int j = 0; j < len; j++) { + printf("event:%s pid=%d tid=%d cpu=%d groupId=%d comm=%s count=%llu countpercent=%lf\n", + data[j].evt, + data[j].pid, + data[j].tid, + data[j].cpu, + data[j].groupId, + data[j].comm, + data[j].count, + data[j].countPercent); + } + } else { + printf("%s\n", Perror()); + } + } + PmuDisable(pd); + PmuClose(pd); + } +} \ No newline at end of file