LWPF (LightWeight PerFormance) 是一个轻量级的, 避免级联编译的, 自动提供统计性结果的从核性能采样工具.
基于X-Macro, 弱符号, 内联汇编等技术实现了较低的噪声和LDM占用.
获取
位于psn的/home/export/online1/swmore/opensource/lwpf2
目录.
快速使用
STEP0
定义头文件作用:
#define CPE //for 从核
//或
#define MPE //for 主核
STEP1
定义从核kernel和unit.
#define CPE
#define LWPF_KERNELS K(A) K(B) K(C)
#define LWPF_UNIT U(TEST)
#include "lwpf2.h"
这样就在名为TEST的unit内定义了A, B, C三个kernel.
注意: 必须先define, 再include!!!!!!
STEP2
在从核入口函数进入和结束时添加同步性能计数器数据的代码:
int test(){
lwpf_enter(TEST); //将unit TEST的计数器数据取到LDM
//...中间是原来函数的代码
lwpf_exit(TEST); //将unit TEST的计数器数据写回主存
}
注意: 包含头文件必须在代码之前!!!
STEP3
对一个需要采样的代码段前后插入lwpf_start
和lwpf_stop
.
int test(){
lwpf_enter(TEST);
lwpf_start(A);
if (_MYID == 0){
int i;
for (i = 0; i < 10; i ++)
printf("%p\n", lwpf_local_counter);
}
lwpf_stop(A);
lwpf_exit(TEST);
}
其中lwpf_start(A)和lwpf_stop(A)表示对代码段A的开始统计和结束统计.
STEP4
在主核上定义unit列表并包含头文件.
#define MPE
#define LWPF_UNITS U(TEST) U(TEST_REINCLUDE) U(TEST_GRP)
#include "lwpf2.h"
STEP5
在主核上调用athread_spawn
之前且athread_init
之后的地方执行lwpf_init
, 参数为perf_config_t *
, 其中包括PCR0~2, PCRC的选项, 选项的具体含义可以参考:
/home/export/online1/swmore/opensource/lwpf2/pcrdef.h
int main(){
athread_init();
perf_config_t conf; //以下是初始化采样选项的代码
conf.pcrc = PCRC_ALL;
conf.pcr0 = PC0_CYCLE;
conf.pcr1 = PC1_CYCLE;
conf.pcr2 = PC2_CNT_GLD;
lwpf_init(&conf); //调用lwpf_init对计数器数据和选项进行初始化.
athread_spawn(test, 0);
athread_join();
//后面的更多代码
}
注意: 现在只支持cgsp 64的情况
STEP6
在需要的地方调用lwpf_report_xxx
输出各unit的统计数据:
int main(){
printf("%p\n", lwpf_global_counter_TEST);
printf("%x\n", lwpf_kernel_count_TEST);
athread_init();
perf_config_t conf;
conf.pcrc = PCRC_ALL;
conf.pcr0 = PC0_CYCLE;
conf.pcr1 = PC1_CYCLE;
conf.pcr2 = PC2_CNT_GLD;
lwpf_init(&conf);
athread_spawn(test, 0);
athread_join();
athread_spawn(test_caller, 0);
athread_join();
athread_spawn(test_reinclude, 0);
athread_join();
lwpf_report_summary(stdout, &conf); //输出较为紧凑的统计数据
lwpf_report_summary_wide(stdout, &conf); //输出较为宽松的统计数据
lwpf_report_detail(stdout, &conf); //输出最详细的数据
}
进阶使用
lwpf2_undef.h:
一个用于部分清除当前LWPF环境, 以支持在同一个文件中使用多个unit的头文件:
#define CPE
#define LWPF_KERNELS K(A) K(B) K(C)
#define LWPF_UNIT U(TEST)
#include "lwpf2.h"
int test(){
//......
}
#include "lwpf2_undef.h" //清除TEST的环境
#define LWPF_KERNELS K(AA) K(BB) K(CC) //重新定义TEST_REINCLUDE的环境
#define LWPF_UNIT U(TEST_REINCLUDE)
#include "lwpf2.h"
int test_reinclude(){
//......
}
多从核文件共享unit:
把unit定义相关代码写入到.h文件中, 然后不同的从核.c包含同一个.h文件:
lwpf_def_grp.h
:
#define LWPF_KERNELS K(ALL) K(A) K(B) K(C)
#define LWPF_UNIT U(TEST_GRP)
#include "lwpf2.h"
test_cpe_grp1.h
:
#include "lwpf_def_grp.h"
int test_caller(){
lwpf_enter(TEST_GRP);
lwpf_start(ALL);
lwpf_start(A);
if (_MYID == 0){
int i;
for (i = 0; i < 10; i ++)
printf("%p\n", lwpf_local_counter);
}
lwpf_stop(A);
lwpf_start(C);
test_callee();
lwpf_stop(C);
lwpf_stop(ALL);
lwpf_exit(TEST_GRP);
}
注意: 只需要在athread_spawn
的入口函数使用lwpf_enter
和lwpf_exit
关闭带颜色输出:
在主核上, 包含头文件前, 定义LWPF_NOCOLOR:
//...LWPF_UNITS的定义
#define LWPF_NOCOLOR
#include "lwpf2.h"
对于主核入口为Fortran时的建议:
写一个额外的主核C文件, 实现对lwpf_init和lwpf_report的调用:
lwpf_interface.c
:
#define MPE
#define LWPF_UNITS U(TEST) U(TEST_REINCLUDE) U(TEST_GRP)
#include "lwpf2.h"
perf_config_t conf;
void lwpf_init_(){
conf.pcrc = PCRC_ALL;
conf.pcr0 = PC0_CYCLE;
conf.pcr1 = PC1_CYCLE;
conf.pcr2 = PC2_CNT_GLD;
lwpf_init(&conf);
}
void lwpf_report_summary_(){
lwpf_report_summary(stdout, &conf);
lwpf_report_summary_wide(stdout, &conf);
}
main.f90
:
!.....
call athread_init()
call lwpf_init()
!....
call lwpf_report_summary()
对于MPI程序的建议:
输出到文件而不是stdout.
或者手动进行同步.
完整例子:
/home/export/online1/swmore/opensource/lwpf2/example
.
LDM用量:
由于采用弱符号实现, LDM占用量为kernel最多一个unit的kernel个数*32B.
作为代价, 不同的unit会复用LDM, 所以一个从核入口中只可以用一个unit, 或者通过lwpf_enter
和lwpf_exit
切换, 但这会导致较为严重的DMA开销(enter和exit使用DMA传输数据).