LWPF2: 轻量级从核性能插桩采样工具
-
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传输数据).
-
前排占坑666,非常适合从核深度优化(比如GROMACS)
-
@段晓辉 666 , 为研究科学家打call。。。。
-
@jflfy 你暴露了。。。多才多艺的。。。
-
可以,以后就可以用这个了