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_startlwpf_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_enterlwpf_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_enterlwpf_exit切换, 但这会导致较为严重的DMA开销(enter和exit使用DMA传输数据).



  • 前排占坑666,非常适合从核深度优化(比如GROMACS)



  • @段晓辉 666 , 为研究科学家打call。。。。



  • @jflfy 你暴露了。。。多才多艺的。。。



  • 可以,以后就可以用这个了


登录后回复