From 9507590931489857b8dddef4faacbdfc15c8d5ed Mon Sep 17 00:00:00 2001 From: twwang <920347125@qq.com> Date: Fri, 20 Jun 2025 10:02:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81cgroup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/pcerrc.h | 1 + include/pmu.h | 4 ++ pmu/evt.h | 4 ++ pmu/perf_counter.cpp | 16 +++++-- pmu/pmu.cpp | 82 ++++++++++++++++++++++++++++++--- pmu/pmu_event.h | 2 + pmu/sampler.cpp | 15 +++++- python/modules/_libkperf/Pmu.py | 9 +++- python/modules/kperf/perror.py | 1 + 9 files changed, 122 insertions(+), 12 deletions(-) diff --git a/include/pcerrc.h b/include/pcerrc.h index 909ae4e..d8a1109 100644 --- a/include/pcerrc.h +++ b/include/pcerrc.h @@ -110,6 +110,7 @@ extern "C" { #define LIBPERF_ERR_NOT_SUPPORT_METRIC 1066 #define LIBPERF_ERR_INVALID_CPU_FREQ_PERIOD 1067 #define LIBPERF_ERR_PMU_DATA_NO_FOUND 1068 +#define LIBPERF_ERR_INVALID_CGROUP_LIST 1069 #define UNKNOWN_ERROR 9999 diff --git a/include/pmu.h b/include/pmu.h index 0873c0c..185c7f6 100644 --- a/include/pmu.h +++ b/include/pmu.h @@ -165,6 +165,9 @@ struct PmuAttr { unsigned includeNewFork : 1; // if the filtering mode is set, the branch_sample_stack data is collectd in sampling mode.By default,the filtering mode dose not take effect. unsigned long branchSampleFilter; + char** cgroupNameList; + // length of cgroup name + int numCgroup; }; enum PmuTraceType { @@ -254,6 +257,7 @@ struct PmuData { double countPercent; // event count Percent. when count = 0, countPercent = -1; Only available for Counting. struct PmuDataExt *ext; // extension. Only available for Spe. struct SampleRawData *rawData; // trace pointer collect data. + const char* cgroupName; // trace data sources from cgroup name }; struct PmuTraceData { diff --git a/pmu/evt.h b/pmu/evt.h index ca48e4e..9edcfd0 100644 --- a/pmu/evt.h +++ b/pmu/evt.h @@ -67,6 +67,10 @@ public: return pid; } + int GetCgroupFd() const { + return evt->cgroupFd; + } + virtual bool IsMainPid() const { if (procMap.find(pid) != procMap.end()) { diff --git a/pmu/perf_counter.cpp b/pmu/perf_counter.cpp index 7a212fe..da1ce64 100644 --- a/pmu/perf_counter.cpp +++ b/pmu/perf_counter.cpp @@ -82,6 +82,9 @@ int KUNPENG_PMU::PerfCounter::Read(vector &data, std::vectorsecond->pid; } + if(this->evt->cgroupName.size() != 0) { + current.cgroupName = this->evt->cgroupName.c_str(); + } return SUCCESS; } @@ -113,6 +116,13 @@ int KUNPENG_PMU::PerfCounter::MapPerfAttr(const bool groupEnable, const int grou attr.disabled = 1; attr.inherit = 1; + // support cgroup feature + unsigned flags = 0; + if (this->GetCgroupFd() != -1) { + flags = PERF_FLAG_PID_CGROUP | PERF_FLAG_FD_CLOEXEC; + this->pid = this->GetCgroupFd(); + } + /** * For now we set the format id bit to implement grouping logic in the future */ @@ -124,17 +134,17 @@ int KUNPENG_PMU::PerfCounter::MapPerfAttr(const bool groupEnable, const int grou * the child events will not start counting until the group leader is enabled. */ attr.disabled = 0; - this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, 0); + this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, flags); } else { #ifdef IS_X86 if (this->evt->pmuType == KUNPENG_PMU::UNCORE_TYPE && !StartWith(this->evt->name, "cpu/")) { - this->fd = PerfEventOpen(&attr, -1, this->cpu, groupFd, 0); + this->fd = PerfEventOpen(&attr, -1, this->cpu, groupFd, flags); #else if (this->evt->pmuType == KUNPENG_PMU::UNCORE_TYPE && !StartWith(this->evt->name, "armv8_")) { this->fd = PerfEventOpen(&attr, -1, this->cpu, groupFd, 0); #endif } else { - this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, 0); + this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, flags); } } this->groupFd = groupFd; diff --git a/pmu/pmu.cpp b/pmu/pmu.cpp index 30de9ef..3138b8d 100644 --- a/pmu/pmu.cpp +++ b/pmu/pmu.cpp @@ -168,6 +168,26 @@ static int CheckBranchSampleFilter(const unsigned long& branchSampleFilter, enum return SUCCESS; } +static int CheckCgroupName(unsigned numCgroup, char** cgroupName) +{ + if (numCgroup > 0 && cgroupName == nullptr) { + New(LIBPERF_ERR_INVALID_CGROUP_LIST, "Invalid cgroup name list: numcgroup is greater than 0, but cgroupName is null"); + return LIBPERF_ERR_INVALID_CGROUP_LIST; + } + + for (unsigned i = 0; i < numCgroup; i++) { + std::string cgroupPath = "/sys/fs/cgroup/perf_event/" + string(cgroupName[i]); + int cgroupFd = open(cgroupPath.c_str(), O_RDONLY); + if (cgroupFd < 0) { + New(LIBPERF_ERR_OPEN_INVALID_FILE, "open " + cgroupPath + " failed."); + return LIBPERF_ERR_OPEN_INVALID_FILE; + } + close(cgroupFd); + } + + return SUCCESS; +} + static int CheckCollectTypeConfig(enum PmuTaskType collectType, struct PmuAttr *attr) { if (collectType < 0 || collectType >= MAX_TASK_TYPE) { @@ -244,6 +264,12 @@ static int CheckAttr(enum PmuTaskType collectType, struct PmuAttr *attr) return err; } + err = CheckCgroupName(attr->numCgroup, attr->cgroupNameList); + if (err != SUCCESS) { + New(err); + return err; + } + return SUCCESS; } @@ -831,7 +857,17 @@ static void PrepareCpuList(PmuAttr *attr, PmuTaskAttr *taskParam, PmuEvt* pmuEvt } } -static struct PmuTaskAttr* AssignTaskParam(PmuTaskType collectType, PmuAttr *attr, const char* evtName, const int groupId) +int GetCgroupFd(std::string& cgroupName) { + std::string cgroupPath = "/sys/fs/cgroup/perf_event/" + cgroupName; + int cgroupFd = open(cgroupPath.c_str(), O_RDONLY); + if (cgroupFd < 0) { + New(LIBPERF_ERR_OPEN_INVALID_FILE, "open " + cgroupPath + " failed."); + return -1; + } + return cgroupFd; +} + +static struct PmuTaskAttr* AssignTaskParam(PmuTaskType collectType, PmuAttr *attr, const char* evtName, const int groupId, const char* cgroupName, int cgroupFd) { unique_ptr taskParam(CreateNode(), PmuTaskAttrFree); /** @@ -842,6 +878,7 @@ static struct PmuTaskAttr* AssignTaskParam(PmuTaskType collectType, PmuAttr *att for (int i = 0; i < attr->numPid; i++) { taskParam->pidList[i] = attr->pidList[i]; } + PmuEvt* pmuEvt = nullptr; if (collectType == SPE_SAMPLING) { pmuEvt = PfmGetSpeEvent(attr->dataFilter, attr->evFilter, attr->minLatency, collectType); @@ -878,23 +915,56 @@ static struct PmuTaskAttr* AssignTaskParam(PmuTaskType collectType, PmuAttr *att taskParam->pmuEvt->callStack = attr->callStack; taskParam->pmuEvt->blockedSample = attr->blockedSample; taskParam->pmuEvt->includeNewFork = attr->includeNewFork; + taskParam->pmuEvt->cgroupFd = cgroupFd; + taskParam->pmuEvt->cgroupName = cgroupName; + return taskParam.release(); } +bool InitCgroupFds(struct PmuAttr *attr, std::unordered_map& cgroupFds) { + for (int i = 0; i < attr->numCgroup; ++i) { + std::string cgroupName = attr->cgroupNameList[i]; + int fd = GetCgroupFd (cgroupName); + if (fd == -1) { + return false; + } + cgroupFds[cgroupName] = fd; + } + return true; +} + struct PmuTaskAttr* AssignPmuTaskParam(enum PmuTaskType collectType, struct PmuAttr *attr) { struct PmuTaskAttr* taskParam = nullptr; if (collectType == SPE_SAMPLING) { // evtList is nullptr, cannot loop over evtList. - taskParam = AssignTaskParam(collectType, attr, nullptr, 0); + taskParam = AssignTaskParam(collectType, attr, nullptr, 0, nullptr, -1); return taskParam; } - for (int i = 0; i < attr->numEvt; i++) { - struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[i], attr->evtAttr[i].groupId); - if (current == nullptr) { + if (attr->numCgroup > 0) { + std::unordered_map cgroupFds; + if (!InitCgroupFds(attr, cgroupFds)) { return nullptr; } - AddTail(&taskParam, ¤t); + + for (int i = 0; i < attr->numCgroup; ++i) { + std::string cgroupName(attr->cgroupNameList[i]); + for (int j = 0; j < attr->numEvt; j++) { + struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[j], attr->evtAttr[j].groupId, cgroupName.c_str(), cgroupFds[cgroupName]); + if (current == nullptr) { + return nullptr; + } + AddTail(&taskParam, ¤t); + } + } + } else { + for (int i = 0; i < attr->numEvt; i++) { + struct PmuTaskAttr* current = AssignTaskParam(collectType, attr, attr->evtList[i], attr->evtAttr[i].groupId, nullptr, -1); + if (current == nullptr) { + return nullptr; + } + AddTail(&taskParam, ¤t); + } } return taskParam; } diff --git a/pmu/pmu_event.h b/pmu/pmu_event.h index 6fc6a72..6bffab3 100644 --- a/pmu/pmu_event.h +++ b/pmu/pmu_event.h @@ -49,6 +49,8 @@ struct PmuEvt { }; unsigned useFreq : 1; unsigned includeNewFork : 1; // count new fork tid + int cgroupFd; + std::string cgroupName; }; namespace KUNPENG_PMU { diff --git a/pmu/sampler.cpp b/pmu/sampler.cpp index aa23978..3061a54 100644 --- a/pmu/sampler.cpp +++ b/pmu/sampler.cpp @@ -82,9 +82,14 @@ int KUNPENG_PMU::PerfSampler::MapPerfAttr(const bool groupEnable, const int grou if (groupEnable) { attr.pinned = 0; attr.disabled = 0; - } + } + unsigned flags = 0; + if (this->GetCgroupFd() != -1) { + flags = PERF_FLAG_PID_CGROUP | PERF_FLAG_FD_CLOEXEC; + this->pid = this->GetCgroupFd(); + } - this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, 0); + this->fd = PerfEventOpen(&attr, this->pid, this->cpu, groupFd, flags); DBG_PRINT("pid: %d type: %d cpu: %d config: %X myfd: %d groupfd: %d\n", this->pid, attr.type, cpu, attr.config, this->fd, groupFd); if (__glibc_unlikely(this->fd < 0)) { return MapErrno(errno); @@ -126,6 +131,9 @@ int KUNPENG_PMU::PerfSampler::Close() if (this->fd > 0) { close(this->fd); } + if (this->evt->cgroupFd > 0) { + close(this->evt->cgroupFd); + } return SUCCESS; } @@ -244,6 +252,9 @@ void KUNPENG_PMU::PerfSampler::RawSampleProcess( TraceParser::ParserRawFormatData(current, sample, event, this->evt->name); } ParseBranchSampleData(current, sample, event, extPool); + if (this->evt->cgroupName.size() != 0) { + current->cgroupName = this->evt->cgroupName.c_str(); + } } void KUNPENG_PMU::PerfSampler::ReadRingBuffer(vector &data, vector &sampleIps, diff --git a/python/modules/_libkperf/Pmu.py b/python/modules/_libkperf/Pmu.py index 7de1373..74e27e4 100644 --- a/python/modules/_libkperf/Pmu.py +++ b/python/modules/_libkperf/Pmu.py @@ -202,7 +202,9 @@ class PmuAttr: evFilter: int=0, minLatency: int=0, includeNewFork: bool=False, - branchSampleFilter: int=0) -> None: + branchSampleFilter: int=0, + cgroupName) -> None: + self.__c_pmu_attr = CtypesPmuAttr( evtList=evtList, pidList=pidList, @@ -220,6 +222,7 @@ class PmuAttr: minLatency=minLatency, includeNewFork=includeNewFork, branchSampleFilter=branchSampleFilter, + cgroupName=cgroupName ) @property @@ -394,6 +397,10 @@ class PmuAttr: def branchSampleFilter(self, branchSampleFilter: int) -> None: self.c_pmu_attr.branchSampleFilter = ctypes.c_ulong(branchSampleFilter) + @property + def cgroup_name(self): + return self.c_pmu_attr.cgroupName.decode(UTF_8) + @classmethod def from_c_pmu_data(cls, c_pmu_attr: CtypesPmuAttr) -> 'PmuAttr': pmu_attr = cls() diff --git a/python/modules/kperf/perror.py b/python/modules/kperf/perror.py index 20776de..6d3acad 100644 --- a/python/modules/kperf/perror.py +++ b/python/modules/kperf/perror.py @@ -109,6 +109,7 @@ class Error: LIBPERF_ERR_NOT_SUPPORT_METRIC = 1066 LIBPERF_ERR_INVALID_CPU_FREQ_PERIOD = 1067 LIBPERF_ERR_PMU_DATA_NO_FOUND = 1068 + LIBPERF_ERR_GROUP_AND_CGROUP_CONFLICT = 1069 UNKNOWN_ERROR = 9999 -- Gitee