mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-23 07:29:42 +00:00
hiperf支持user模式
Signed-off-by: 张建 <zhangjian22@huawei.com> #I68M3K
This commit is contained in:
parent
a436cce44b
commit
f054a14f05
38
BUILD.gn
38
BUILD.gn
@ -340,6 +340,7 @@ ohos_executable("hiperf") {
|
||||
install_enable = true
|
||||
sources = [ "./src/main.cpp" ]
|
||||
deps = [
|
||||
":hiperf_etc",
|
||||
":hiperf_platform_common",
|
||||
":hiperf_platform_linux",
|
||||
]
|
||||
@ -369,6 +370,43 @@ ohos_executable("hiperf_host") {
|
||||
part_name = "hiperf"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("hiperf.para") {
|
||||
source = "etc/hiperf.para"
|
||||
install_images = [
|
||||
"system",
|
||||
"updater",
|
||||
]
|
||||
module_install_dir = "etc/param"
|
||||
part_name = "hiperf"
|
||||
subsystem_name = "developtools"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("hiperf.para.dac") {
|
||||
source = "etc/hiperf.para.dac"
|
||||
install_images = [
|
||||
"system",
|
||||
"updater",
|
||||
]
|
||||
module_install_dir = "etc/param"
|
||||
part_name = "hiperf"
|
||||
subsystem_name = "developtools"
|
||||
}
|
||||
|
||||
ohos_prebuilt_etc("hiperf.cfg") {
|
||||
source = "etc/hiperf.cfg"
|
||||
relative_install_dir = "init"
|
||||
subsystem_name = "developtools"
|
||||
part_name = "hiperf"
|
||||
}
|
||||
|
||||
group("hiperf_etc") {
|
||||
deps = [
|
||||
":hiperf.cfg",
|
||||
":hiperf.para",
|
||||
":hiperf.para.dac",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_source_set("hiperf_platform_host") {
|
||||
part_name = "hiperf"
|
||||
sources = [ "./src/hiperf_libreport.cpp" ]
|
||||
|
18
etc/hiperf.cfg
Normal file
18
etc/hiperf.cfg
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"jobs": [{
|
||||
"name": "param:security.perf_harden=0",
|
||||
"condition": "security.perf_harden=0",
|
||||
"cmds": [
|
||||
"write /proc/sys/kernel/perf_event_max_sample_rate ${hiviewdfx.hiperf.perf_event_max_sample_rate}",
|
||||
"write /proc/sys/kernel/perf_cpu_time_max_percent ${hiviewdfx.hiperf.perf_cpu_time_max_percent}",
|
||||
"write /proc/sys/kernel/perf_event_mlock_kb ${hiviewdfx.hiperf.perf_event_mlock_kb}"
|
||||
]
|
||||
}, {
|
||||
"name": "post-init",
|
||||
"cmds": [
|
||||
"setparam hiviewdfx.hiperf.perf_event_max_sample_rate 100000",
|
||||
"setparam hiviewdfx.hiperf.perf_cpu_time_max_percent 25",
|
||||
"setparam hiviewdfx.hiperf.perf_event_mlock_kb 516"
|
||||
]
|
||||
}]
|
||||
}
|
15
etc/hiperf.para
Normal file
15
etc/hiperf.para
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2023 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.
|
||||
hiviewdfx.hiperf.perf_event_max_sample_rate=100000
|
||||
hiviewdfx.hiperf.perf_cpu_time_max_percent=25
|
||||
hiviewdfx.hiperf.perf_event_mlock_kb=516
|
15
etc/hiperf.para.dac
Normal file
15
etc/hiperf.para.dac
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright (c) 2023 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.
|
||||
hiviewdfx.hiperf.perf_event_max_sample_rate=root:shell:0775
|
||||
hiviewdfx.hiperf.perf_cpu_time_max_percent=root:shell:0775
|
||||
hiviewdfx.hiperf.perf_event_mlock_kb=root:shell:0775
|
@ -205,23 +205,6 @@ struct read_format_no_group {
|
||||
__u64 id; /* if PERF_FORMAT_ID */
|
||||
};
|
||||
|
||||
/*
|
||||
2 allow only user-space measurements (default since
|
||||
Linux 4.6).
|
||||
1 allow both kernel and user measurements (default
|
||||
before Linux 4.6).
|
||||
0 allow access to CPU-specific data but not raw
|
||||
tracepoint samples.
|
||||
-1 no restrictions.
|
||||
*/
|
||||
enum PerfEventParanoid {
|
||||
NOLIMIT = -1,
|
||||
KERNEL_USER_CPU = 0,
|
||||
KERNEL_USER = 1,
|
||||
USER = 2,
|
||||
UNKNOW = 99,
|
||||
};
|
||||
|
||||
class PerfEvents {
|
||||
public:
|
||||
static constexpr uint64_t DEFAULT_SAMPLE_FREQUNCY = 4000;
|
||||
@ -411,12 +394,6 @@ private:
|
||||
};
|
||||
uint8_t eventSpaceType_ = EventSpaceType::UNKNOW;
|
||||
|
||||
PerfEventParanoid requestPermission_ = PerfEventParanoid::USER;
|
||||
bool CheckPermissions(PerfEventParanoid request = KERNEL_USER_CPU);
|
||||
bool CheckOhosPermissions();
|
||||
|
||||
static PerfEventParanoid perfEventParanoid_;
|
||||
|
||||
bool inherit_ = false;
|
||||
std::vector<pid_t> pids_;
|
||||
std::vector<pid_t> cpus_;
|
||||
|
@ -245,6 +245,9 @@ private:
|
||||
|
||||
size_t recordSamples_ = 0;
|
||||
size_t recordNoSamples_ = 0;
|
||||
|
||||
bool isNeedSetPerfHarden_ = false;
|
||||
|
||||
// callback to process record
|
||||
bool ProcessRecord(std::unique_ptr<PerfEventRecord>);
|
||||
bool SaveRecord(std::unique_ptr<PerfEventRecord>);
|
||||
@ -271,8 +274,11 @@ private:
|
||||
|
||||
bool CollectionSymbol(std::unique_ptr<PerfEventRecord> record);
|
||||
|
||||
bool SetPerfLimit(const std::string& file, const std::string& param, int value);
|
||||
bool SetPerfCpuMaxPercent();
|
||||
bool SetPerfMaxSampleRate();
|
||||
bool SetPerfEventMlock();
|
||||
bool SetPerfHarden();
|
||||
|
||||
bool TraceOffCpu();
|
||||
bool ParseCallStackOption(const std::vector<std::string> &callStackType);
|
||||
|
@ -45,17 +45,13 @@ static std::atomic_bool g_trackRunning = false;
|
||||
OHOS::UniqueFd PerfEvents::Open(perf_event_attr &attr, pid_t pid, int cpu, int group_fd,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (perfEventParanoid_ >= PerfEventParanoid::USER) {
|
||||
attr.exclude_kernel = true; // kernel restrict
|
||||
}
|
||||
OHOS::UniqueFd fd = UniqueFd(syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, flags));
|
||||
if (fd < 0) {
|
||||
HLOGEP("syscall perf_event_open failed. ");
|
||||
// dump when open failed.
|
||||
SubCommandDump::DumpPrintEventAttr(attr, std::numeric_limits<int>::min());
|
||||
}
|
||||
HLOGV("perf_event_open: got fd %d for pid %d cpu %d group %d flags %lu perfEventParanoid %d",
|
||||
fd.Get(), pid, cpu, group_fd, flags, perfEventParanoid_);
|
||||
HLOGV("perf_event_open: got fd %d for pid %d cpu %d group %d flags %lu", fd.Get(), pid, cpu, group_fd, flags);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -87,73 +83,6 @@ PerfEvents::~PerfEvents()
|
||||
ExitReadRecordBufThread();
|
||||
}
|
||||
|
||||
PerfEventParanoid PerfEvents::perfEventParanoid_ = PerfEventParanoid::UNKNOW;
|
||||
|
||||
bool PerfEvents::CheckOhosPermissions()
|
||||
{
|
||||
#if defined(CONFIG_HAS_SYSPARA)
|
||||
std::string perfHarden = "0";
|
||||
perfHarden = OHOS::system::GetParameter(PERF_DISABLE_PARAM, perfHarden);
|
||||
HLOGD("%s is %s", PERF_DISABLE_PARAM.c_str(), perfHarden.c_str());
|
||||
if (perfHarden == "1") {
|
||||
printf("param '%s' is disabled, try to enable it\n", PERF_DISABLE_PARAM.c_str());
|
||||
// we will try to set it as 0
|
||||
perfHarden = OHOS::system::SetParameter(PERF_DISABLE_PARAM, "0");
|
||||
// wait init config the param
|
||||
std::this_thread::sleep_for(1s);
|
||||
if (OHOS::system::GetParameter(PERF_DISABLE_PARAM, perfHarden) == "1") {
|
||||
printf("setparam failed. pls try setparam %s 0\n", PERF_DISABLE_PARAM.c_str());
|
||||
}
|
||||
}
|
||||
return perfHarden == "0";
|
||||
#else
|
||||
return true; // not ohos
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PerfEvents::CheckPermissions(PerfEventParanoid request)
|
||||
{
|
||||
// check the ohos param "security.perf_harden"
|
||||
|
||||
if (getuid() == 0) {
|
||||
// we are root perfEventParanoid as -1
|
||||
perfEventParanoid_ = PerfEventParanoid::NOLIMIT;
|
||||
printf("this is root mode, perfEventParanoid assume as -1\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string perfEventParanoid = ReadFileToString(PERF_EVENT_PARANOID);
|
||||
if (perfEventParanoid.empty()) {
|
||||
printf("unable to read %s, assume as 2\n", PERF_EVENT_PARANOID.c_str());
|
||||
perfEventParanoid_ = PerfEventParanoid::USER;
|
||||
} else {
|
||||
perfEventParanoid_ = static_cast<PerfEventParanoid>(stoi(perfEventParanoid));
|
||||
}
|
||||
|
||||
#if is_ohos
|
||||
// not root and in ohos
|
||||
if (!CheckOhosPermissions()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (perfEventParanoid_ == PerfEventParanoid::NOLIMIT) {
|
||||
return true;
|
||||
}
|
||||
printf("%s is %d\n", PERF_EVENT_PARANOID.c_str(), perfEventParanoid_);
|
||||
if (perfEventParanoid_ >= PerfEventParanoid::USER) {
|
||||
printf("allow only user-space measurements (default since Linux 4.6).\n");
|
||||
} else if (perfEventParanoid_ == PerfEventParanoid::KERNEL_USER) {
|
||||
printf("allow both kernel and user measurements (default before Linux 4.6).\n");
|
||||
} else if (perfEventParanoid_ == PerfEventParanoid::KERNEL_USER_CPU) {
|
||||
printf("allow access to CPU-specific data but not raw tracepoint samples.\n");
|
||||
} else if (perfEventParanoid_ <= PerfEventParanoid::NOLIMIT) {
|
||||
printf("unable to read anything\n");
|
||||
}
|
||||
printf("request level is %d\n", request);
|
||||
return perfEventParanoid_ <= request;
|
||||
}
|
||||
|
||||
bool PerfEvents::IsEventSupport(perf_type_id type, __u64 config)
|
||||
{
|
||||
HLOGV("enter");
|
||||
@ -302,10 +231,6 @@ bool PerfEvents::AddEvent(const std::string &eventString, bool followGroup)
|
||||
return false;
|
||||
}
|
||||
if (excludeUser) {
|
||||
if (requestPermission_ > PerfEventParanoid::KERNEL_USER) {
|
||||
requestPermission_ = PerfEventParanoid::KERNEL_USER;
|
||||
}
|
||||
|
||||
eventSpaceType_ |= EventSpaceType::KERNEL;
|
||||
} else if (excludeKernel) {
|
||||
eventSpaceType_ |= EventSpaceType::USER;
|
||||
@ -497,11 +422,6 @@ static void RecoverCaptureSig()
|
||||
bool PerfEvents::PrepareTracking(void)
|
||||
{
|
||||
HLOGV("enter");
|
||||
|
||||
if (!CheckPermissions(requestPermission_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1. prepare cpu pid
|
||||
if (!PrepareFdEvents()) {
|
||||
HLOGE("PrepareFdEvents() failed");
|
||||
@ -514,6 +434,7 @@ bool PerfEvents::PrepareTracking(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
HLOGV("success");
|
||||
prepared_ = true;
|
||||
return true;
|
||||
}
|
||||
@ -581,7 +502,9 @@ void PerfEvents::WaitRecordThread()
|
||||
|
||||
bool PerfEvents::StartTracking(bool immediately)
|
||||
{
|
||||
HLOGV("enter");
|
||||
if (!prepared_) {
|
||||
HLOGD("do not prepared_");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -713,12 +636,6 @@ void PerfEvents::SetSystemTarget(bool systemTarget)
|
||||
void PerfEvents::SetCpu(std::vector<pid_t> cpus)
|
||||
{
|
||||
cpus_ = cpus;
|
||||
|
||||
if (!cpus_.empty()) {
|
||||
if (requestPermission_ > PerfEventParanoid::KERNEL_USER_CPU) {
|
||||
requestPermission_ = PerfEventParanoid::KERNEL_USER_CPU;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PerfEvents::SetPid(std::vector<pid_t> pids)
|
||||
@ -907,10 +824,6 @@ bool PerfEvents::PrepareFdEvents(void)
|
||||
if (systemTarget_) {
|
||||
pids_.clear();
|
||||
pids_.push_back(-1);
|
||||
|
||||
if (cpus_.empty()) {
|
||||
PutAllCpus();
|
||||
}
|
||||
} else {
|
||||
if (trackedCommand_) {
|
||||
pids_.push_back(trackedCommand_->GetChildPid());
|
||||
@ -918,15 +831,10 @@ bool PerfEvents::PrepareFdEvents(void)
|
||||
if (pids_.empty()) {
|
||||
pids_.push_back(0); // no pid means use 0 as self pid
|
||||
}
|
||||
if (cpus_.empty()) {
|
||||
// new review . if perfEventParanoid_ < CPU, how should be CreateMmap work?
|
||||
if (perfEventParanoid_ <= PerfEventParanoid::KERNEL_USER_CPU) {
|
||||
// PERF_EVENT_IOC_SET_OUTPUT doesn't support using -1 as all cpu
|
||||
PutAllCpus();
|
||||
} else {
|
||||
cpus_.push_back(-1); // no cpu as all cpu
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cpus_.empty()) {
|
||||
PutAllCpus();
|
||||
}
|
||||
|
||||
// print info tell user which cpu and process we will select.
|
||||
@ -1138,6 +1046,9 @@ bool PerfEvents::CreateMmap(const FdItem &item, const perf_event_attr &attr)
|
||||
void *rbuf = mmap(nullptr, (1 + mmapPages_) * pageSize_, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
item.fd.Get(), 0);
|
||||
if (rbuf == MMAP_FAILED) {
|
||||
char errInfo[ERRINFOLEN] = {0};
|
||||
strerror_r(errno, errInfo, ERRINFOLEN);
|
||||
perror("errno:%d, errstr:%s", errno, errInfo);
|
||||
perror("Fail to call mmap \n");
|
||||
return false;
|
||||
}
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <poll.h>
|
||||
#if defined(CONFIG_HAS_SYSPARA)
|
||||
#include <parameters.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
@ -47,6 +50,10 @@ const std::string CONTROL_CMD_STOP = "stop";
|
||||
const std::string CONTROL_FIFO_FILE_C2S = "/data/local/tmp/.hiperf_record_control_c2s";
|
||||
const std::string CONTROL_FIFO_FILE_S2C = "/data/local/tmp/.hiperf_record_control_s2c";
|
||||
|
||||
const std::string PERF_CPU_TIME_MAX_PERCENT = "/proc/sys/kernel/perf_cpu_time_max_percent";
|
||||
const std::string PERF_EVENT_MAX_SAMPLE_RATE = "/proc/sys/kernel/perf_event_max_sample_rate";
|
||||
const std::string PERF_EVENT_MLOCK_KB = "/proc/sys/kernel/perf_event_mlock_kb";
|
||||
|
||||
// when there are many events, start record will take more time.
|
||||
const std::chrono::milliseconds CONTROL_WAITREPY_TOMEOUT = 2000ms;
|
||||
|
||||
@ -619,39 +626,66 @@ bool SubCommandRecord::ParseControlCmd(const std::string cmd)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SetPerfLimit(const std::string& file, const std::string& param, int value)
|
||||
{
|
||||
int originValue = 0;
|
||||
if (!ReadIntFromProcFile(file, originValue)) {
|
||||
printf("read %s fail.", file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (originValue == value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsRoot()) {
|
||||
return WriteIntToProcFile(file, value);
|
||||
}
|
||||
|
||||
if (!OHOS::system::SetParameter(param, std::to_string(value))) {
|
||||
printf("set parameter %s fail.", param.c_str());
|
||||
return false;
|
||||
}
|
||||
isNeedSetPerfHarden_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SetPerfCpuMaxPercent()
|
||||
{
|
||||
int percent = 0;
|
||||
if (ReadIntFromProcFile("/proc/sys/kernel/perf_cpu_time_max_percent", percent)) {
|
||||
if (percent == cpuPercent_) {
|
||||
return true;
|
||||
}
|
||||
if (!IsRoot()) {
|
||||
printf("root privillege is needed to change perf_cpu_time_max_percent\n");
|
||||
return false;
|
||||
}
|
||||
return WriteIntToProcFile("/proc/sys/kernel/perf_cpu_time_max_percent", cpuPercent_);
|
||||
}
|
||||
return false;
|
||||
return SetPerfLimit(PERF_CPU_TIME_MAX_PERCENT, "hiviewdfx.hiperf.perf_cpu_time_max_percent", cpuPercent_);
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SetPerfMaxSampleRate()
|
||||
{
|
||||
int rate = 0;
|
||||
if (ReadIntFromProcFile("/proc/sys/kernel/perf_event_max_sample_rate", rate)) {
|
||||
int frequency = frequency_ != 0 ? frequency_ : PerfEvents::DEFAULT_SAMPLE_FREQUNCY;
|
||||
if (rate >= frequency) {
|
||||
return true;
|
||||
}
|
||||
return WriteIntToProcFile("/proc/sys/kernel/perf_event_max_sample_rate", frequency);
|
||||
} else {
|
||||
if (!IsRoot()) {
|
||||
printf("root privillege is needed to change perf_event_max_sample_rate\n");
|
||||
} else {
|
||||
printf("please check if CONFIG_PERF_EVENTS enabed.\n");
|
||||
int frequency = frequency_ != 0 ? frequency_ : PerfEvents::DEFAULT_SAMPLE_FREQUNCY;
|
||||
return SetPerfLimit(PERF_EVENT_MAX_SAMPLE_RATE, "hiviewdfx.hiperf.perf_event_max_sample_rate", frequency);
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SetPerfEventMlock()
|
||||
{
|
||||
int mlock_kb = GetProcessorNum() * (mmapPages_ + 1) * 4;
|
||||
return SetPerfLimit(PERF_EVENT_MLOCK_KB, "hiviewdfx.hiperf.perf_event_mlock_kb", mlock_kb);
|
||||
}
|
||||
|
||||
bool SubCommandRecord::SetPerfHarden()
|
||||
{
|
||||
if (!isNeedSetPerfHarden_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string perfHarden = OHOS::system::GetParameter(PERF_DISABLE_PARAM, "1");
|
||||
if (perfHarden == "1") {
|
||||
if (!OHOS::system::SetParameter("security.perf_harden", "0")) {
|
||||
printf("set parameter security.perf_harden to 0 fail.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!OHOS::system::SetParameter("security.perf_harden", "1")) {
|
||||
printf("set parameter security.perf_harden to 1 fail.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubCommandRecord::TraceOffCpu()
|
||||
@ -749,6 +783,17 @@ bool SubCommandRecord::PrepareSysKernel()
|
||||
HLOGE("Fail to set perf event cpu limit to %d\n", cpuPercent_);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetPerfEventMlock()) {
|
||||
HLOGE("Fail to set perf event mlock limit\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetPerfHarden()) {
|
||||
HLOGE("Fail to set perf event harden\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offCPU_ && !TraceOffCpu()) {
|
||||
HLOGE("Fail to TraceOffCpu");
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user