哪个数组的大小?
swmore
@swmore
swmore 发布的帖子
-
关于sw5cc的inline-asm定义%=的问题
刚刚发现sw5cc的
%=
是不管用的, 会在生成的汇编里仍然是%=
, 而不是一个无冲突的标签.
比如:asm volatile("ldi %0, -5($31)\n\t" "ldi %1, 0($31)\n\t" "ale0%=:\n\t" "ldi %0, 1(%0)\n\t" "ldi %1, 1(%1)\n\t" "ble %0, ale0%=\n\t" : "=r"(a), "=r"(b));
应生成(使用gcc -S确实能生成, 虽然过不了汇编器):
ldi %rdx, -5($31) ldi %rax, 0($31) ale08: ldi %rdx, 1(%rdx) ldi %rax, 1(%rax) ble %rdx, ale08
其中
%=
被替换成了一个唯一index. 至于%rdx
啥的是因为寄存器号是x86格式.
而sw5cc不会替换%=
:ldi $17, -5($31) ldi $18, 0($31) ale0%=: ldi $17, 1($17) ldi $18, 1($18) ble $17, ale0%=
导致汇编器不过.
查了一会发现有一个方法是使用临时标签.
其定义方式为N:
(N为任意数).
这是汇编器的特性而不是编译器的特性, 所以兼容性会好很多.
比如:asm volatile("ldi %0, -5($31)\n\t" "ldi %1, 0($31)\n\t" "1:\n\t" "ldi %0, 1(%0)\n\t" "ldi %1, 1(%1)\n\t" "ble %0, 1b\n\t" "bgt %0, 1f\n\t" "1:\n\t" : "=r"(a), "=r"(b));
其中
1:
就是临时标签, 跳转到临时标签需要额外声明是向前跳转还是向后跳转, 比如ble %0, 1b\n\t
中的1b
是跳转到前一个1:
, 相对的1f
就是跳转到后一个1:
生成的.s文件中为:ldi $17, -5($31) ldi $18, 0($31) 1: ldi $17, 1($17) ldi $18, 1($18) ble $17, 1b bgt $17, 1f 1:
可见这种写法并没有在编译器层面被处理, 而通过汇编器然后反汇编得到的结果是:
10: fb ff 3f fa ldi a1,-5 14: 00 00 5f fa ldi a2,0 18: 01 00 31 fa ldi a1,1(a1) 1c: 01 00 52 fa ldi a2,1(a2) 20: fd ff 3f ce ble a1,18 <.LCFI_main_store26+0x8> 24: 00 00 20 d2 bgt a1,28 <.BB2_main>
可以看出在使用临时标签的.s文件在经过汇编器处理后会丢弃其中的临时标签, 这样可以避免标签名冲突.
-
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传输数据). -
RE: 求助,terminated by sig 4
@wakawaka sig4是Illegal Instruction...有没有用函数指针的情况? 感觉这个好像目前只好插打印调试了...程序长吗?