* Copyright (c) Huawei Technologies Co., Ltd. 2025. 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: Wu
* Create: 2025-08-10
* Description: implementations for managing and interacting with performance events of EvtListBpf in the KUNPENG_PMU namespace
******************************************************************************/
#include <cstdio>
#include <unordered_set>
#include <fstream>
#include "cpu_map.h"
#include "pmu_event.h"
#include "pcerrc.h"
#include "pcerr.h"
#include "log.h"
#include "common.h"
#include "evt_list_bpf.h"
using namespace std;
int KUNPENG_PMU::EvtListBpf::Init(const bool groupEnable, const std::shared_ptr<EvtList> evtLeader)
{
for (auto& proc: pidList) {
if (proc->tid > 0) {
procMap[proc->tid] = proc;
}
}
for (unsigned int cpu = 0; cpu < numCpu; cpu++) {
PerfEvtPtr perfEvt =
std::make_shared<KUNPENG_PMU::PerfCounterBpf>(this->cpuList[cpu]->coreId, -1, this->pmuEvt.get(), procMap);
if (perfEvt == nullptr) {
continue;
}
int err = perfEvt->Init(groupEnable, -1, -1);
if (err != SUCCESS) {
return err;
}
this->cpuCounterArray.emplace_back(perfEvt);
}
this->allPids.resize(pidList.size());
for (size_t i = 0; i < pidList.size(); i++) {
this->allPids[i] = pidList[i]->tid;
}
PerfEvtPtr perfEvt =std::make_shared<KUNPENG_PMU::PerfCounterBpf>(-1, -1, this->pmuEvt.get(), procMap);
int err = std::dynamic_pointer_cast<KUNPENG_PMU::PerfCounterBpf>(perfEvt)->InitPidForEvent(allPids);
if (err != SUCCESS) {
return err;
}
this->pidCounterArray.emplace_back(perfEvt);
return SUCCESS;
}
int KUNPENG_PMU::EvtListBpf::CollectorTaskArrayDoTask(std::vector<PerfEvtPtr>& taskArray, int task)
{
std::unique_lock<std::mutex> lock(mutex);
for (auto evt: taskArray) {
auto err = CollectorDoTask(evt, task);
if (err != SUCCESS) {
return err;
}
}
this->prevStat = this->evtStat;
this->evtStat = task;
return SUCCESS;
}
int KUNPENG_PMU::EvtListBpf::Start()
{
return CollectorTaskArrayDoTask(this->cpuCounterArray, START);
}
int KUNPENG_PMU::EvtListBpf::Enable()
{
return CollectorTaskArrayDoTask(this->cpuCounterArray, ENABLE);
}
int KUNPENG_PMU::EvtListBpf::Stop()
{
return CollectorTaskArrayDoTask(this->cpuCounterArray, STOP);
}
int KUNPENG_PMU::EvtListBpf::Reset()
{
return CollectorTaskArrayDoTask(this->cpuCounterArray, RESET);
}
int KUNPENG_PMU::EvtListBpf::Pause()
{
return CollectorTaskArrayDoTask(this->cpuCounterArray, PAUSE);
}
int KUNPENG_PMU::EvtListBpf::Close()
{
auto ret = CollectorTaskArrayDoTask(this->cpuCounterArray, CLOSE);
if (ret != SUCCESS) {
return ret;
}
procMap.clear();
return SUCCESS;
}
int KUNPENG_PMU::EvtListBpf::Read(EventData &eventData)
{
std::unique_lock<std::mutex> lg(mutex);
auto perfEvt = this->pidCounterArray[0];
int err = perfEvt->BeginRead();
if (err != SUCCESS) {
return err;
}
auto cpuTopo = this->cpuList[0].get();
size_t oldSize = eventData.data.size();
if (pmuEvt->cgroupName.empty()) {
err = std::dynamic_pointer_cast<KUNPENG_PMU::PerfCounterBpf>(
this->pidCounterArray[0])->ReadBpfProcess(this->allPids, eventData.data);
} else {
err = std::dynamic_pointer_cast<KUNPENG_PMU::PerfCounterBpf>(
this->pidCounterArray[0])->ReadBpfCgroup(eventData.data);
}
if (err != SUCCESS) {
return err;
}
const char* evtName = pmuEvt->name.c_str();
uint64_t tsVal = this->ts;
for (size_t i = oldSize; i < eventData.data.size(); i++) {
auto& d = eventData.data[i];
DBG_PRINT("evt: %s pid: %d cpu: %d\n", evtName, d.pid, d.cpu);
d.cpuTopo = cpuTopo;
d.evt = evtName;
if (!d.comm) {
auto it = procMap.find(d.tid);
if (it != procMap.end()) {
d.comm = it->second->comm;
}
}
if (d.ts == 0) {
d.ts = tsVal;
}
}
err = perfEvt->EndRead();
if (err != SUCCESS) {
return err;
}
return SUCCESS;
}