众所周知,perf
是获取程序CPU性能计数器的工具,例如cache-miss
,cache-reference
,instruction executed
等。
问题:
如何在c
或c++
的一个程序中仅为一段代码(例如函数)获取这些性能计数器。
例如,我的程序首先进行一些初始化,然后完成工作,然后完成,我只想获得工作的性能计数器,例如函数do_something_1
。
int main(int argc, char ** argv) {
do_initialize();
for (int i = 0;i < 100 ;i ++) {
/* begin profile code */
do_something_1();
/* end profile code */
do_something_2();
}
do_finalize();
}
答案 0 :(得分:2)
最后,我找到了一个库来获取一段代码的计数器。
例如,如果要为某段代码测量L3数据缓存读取。
#include "papi.h"
#include <iostream>
#include <glog/logging.h>
#define ASIZE 2684354560
#define event_count (1) // the number of event you want to trace
int main(int argc, char ** argv) {
int events[event_count] = {PAPI_L3_DCR}; // L3 Data Cache Read
int ret;
long long int values[event_count]; // result
int* array = new int [ASIZE ];
/* start counters */
ret = PAPI_start_counters(events, event_count);
CHECK_EQ(ret, PAPI_OK);
size_t tot_cnt = 1;
for(size_t cnt = 0; cnt < tot_cnt; cnt ++) {
for(size_t i = 0;i < ASIZE ;i ++) {
array[i] = i;
}
}
/* read counters */
ret = PAPI_read_counters(values, event_count);
CHECK_EQ(ret, PAPI_OK);
for(size_t i = 0;i < event_count ;i ++) {
LOG(INFO) << " " << values[i];
}
return 0;
}
Makefile:
CXX?=g++
INC?=-I<path to where papi is installed>/include/
LIB?=-L<path to where papi is installed>/lib/ -lpapi -lglog
main : main.cpp
${CXX} -O3 ${INC} -o $@ $< ${LIB}
all : main
.PHONY:
clean :
rm -f main
答案 1 :(得分:1)
我确实做了一些调查来解决我项目中的同样问题。我找到了另一个名为SkyPat(https://skypat.skymizer.com)的框架,它可以获得像PAPI这样的代码的PMU计数器。
我已经尝试过PAPI和SkyPat来获取功能的PMU计数器。我认为它们之间的区别在于SkyPat结合了单元测试和perf_evnet。它引用了Google Test的概念,并提供了访问PMU的界面,因此很容易与Google Test集成。
例如,如果要测量函数的缓存引用和缓存。
#include <unistd.h>
#include "pat/pat.h"
#include "test.h"
PAT_F(MyCase, my_test)
{
int result = 0;
COUNT(pat::CONTEXT_SWITCHES) {
test(10);
}
COUNT(pat::CPU_CLOCK) {
test(10);
}
COUNT(pat::TASK_CLOCK) {
test(10);
}
COUNT(pat::CACHE_REFERENCES) {
test(10);
}
COUNT(pat::CACHE_MISSES) {
test(10);
}
}
int main(int argc, char* argv[])
{
pat::Test::Initialize(&argc, argv);
pat::Test::RunAll();
}
SkyPat的结果日志。
[ pat ] Running 1 tests from 1 cases.
[----------] 1 test from MyCase.
[ RUN ] MyCase.my_test
[ TIME (ns)] 2537 1000 843 1855 1293
[EVENT TYPE] [CTX SWITCH] [CPU CLOCK] [TASK CLOCK] [CACHE REF] [CACHE MISS]
[RESULT NUM] 0 982 818 2 0
[==========] 1 test from 1 cases ran.
[ PASSED ] 1 test.
答案 2 :(得分:0)
听起来你在寻找分析。
如你所说,你在Linux下,所以看看gprof工具链。您只需要使用一些编译器选项编译您的prog并启动您的程序。 gprof之后检查生成的分析数据并提供包含每个代码块的信息的结果。
首先:使用其他选项编译你的编程:
g++ <source> -c -g -pg
...
第二:链接,你还需要这些选项!
g++ <object1> <object2> ... <objectn> -g -pg -o <target>
第三:运行你的前卫
./<target>
之后,获取统计数据:
gprof <target>
答案 3 :(得分:0)
您可以使用operf(oprofile)。
简而言之:
# Build you program with debugging information
# Start up the profiler
operf /path/to/mybinary
# generate a profile summary
opreport --symbols
# produce some annotated source
opannotate --source --output-dir=/path/to/annotated-source
示例注释输出:
$ opannotate --source --output-dir=/home/moz/src/annotated `which oprofiled`
$ vi /home/moz/src/annotated/home/moz/src/oprofile/daemon/opd_image.c # the annotated source output
...
:static uint64_t pop_buffer_value(struct transient * trans)
254 2.4909 :{ /* pop_buffer_value total: 2105 20.6433 */
: uint64_t val;
:
160 1.5691 : if (!trans->remaining) {
: fprintf(stderr, "BUG: popping empty buffer !\n");
: exit(EXIT_FAILURE);
: }
:
: val = get_buffer_value(trans->buffer, 0);
123 1.2062 : trans->remaining--;
65 0.6374 : trans->buffer += kernel_pointer_size;
: return val;
230 2.2556 :}
答案 4 :(得分:0)
我面临与你相同的情况,我对此做了一些研究。这是我学到的。首先,perf作为内核的一部分包含在内,您可以在
中检查其标题 /usr/src/kernels/$VERSION/include/linux/perf_regs.h
/usr/src/kernels/$VERSION/include/linux/perf_event.h
/usr/src/kernels/$VERSION/include/uapi/linux/perf_event.h
我认为核心文件是perf_event.h 您还可以查看其github网站,其中有一些关于如何使用它的说明。但目前尚不清楚,现在我仍然有很多困惑。
此外,我发现了一个非常有用的库pfmlib,它是一个用于编程perf事件的辅助库。它有示例和perf_examples,用于指示如何在代码级别执行此操作。我还在努力。希望这对你有所帮助。如果您有一些问题,我们可以互相学习。
pfmlib的网站是http://perfmon2.sourceforge.net。