2016-10-24 1 views
3

이것은 지나치게 구체적 일지 모르지만 여기에 게시하면 기본 SPEC 벤치 마크 하네스 외부에서 SPEC 2006 벤치 마크를 컴파일/실행하는 데 도움이 될 수 있습니다. (SPEC 하네스는 결과 코드의 성능에만 초점을 맞추는 반면, 이렇게하는 우리의 이유는 컴파일 전략과 코드 적용 범위를 비교하는 것입니다.)perlbench는 SPEC 2006 하네스 외의 segfault를 초래합니다

Program received signal SIGSEGV, Segmentation fault. 
0x00000000004f6868 in S_regmatch (prog=0x832144) 

    at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:3024 
3024   PL_reg_start_tmp[n] = locinput; 
(gdb) bt 
#0 0x00000000004f6868 in S_regmatch (prog=0x832144) 
    at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:3024 
#1 0x00000000004f22cf in S_regtry (prog=0x8320c0, startpos=0x831e70 "o") 
    at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:2196 
#2 0x00000000004eba71 in Perl_regexec_flags (prog=0x8320c0, stringarg=0x831e70 "o", strend=0x831e71 "", 
    strbeg=0x831e70 "o", minend=0, sv=0x7e2528, data=0x0, flags=3) 
    at <path-to-spec>/CPU2006/400.perlbench/src/regexec.c:1910 
#3 0x00000000004b33bb in Perl_pp_match() 
    at <path-to-spec>/CPU2006/400.perlbench/src/pp_hot.c:1340 
#4 0x00000000004fcde4 in Perl_runops_standard() 
    at <path-to-spec>/CPU2006/400.perlbench/src/run.c:37 
#5 0x000000000046bf57 in S_run_body (oldscope=1) 
    at <path-to-spec>/CPU2006/400.perlbench/src/perl.c:2017 
#6 0x000000000046b9f6 in perl_run (my_perl=0x7bf010) 
    at <path-to-spec>/CPU2006/400.perlbench/src/perl.c:1934 
#7 0x000000000047add2 in main (argc=4, argv=0x7fffffffe178, env=0x7fffffffe1a0) 
    at <path-to-spec>/CPU2006/400.perlbench/src/perlmain.c:98 

실행 환경은 64 비트 Linux과 행동이 최신 GCC와 그 소리를 모두 관찰 :

는 세그먼트 오류와 perlbench 벤치 마크 충돌의 심판 실행을 수행 할 때.

이 충돌의 원인은 무엇입니까?

+0

이것은 https://github.com/briandfoy/perlbench 다른 뭔가처럼 보이지만, 그렇지 않은 경우 다음을 수행 할 수 있습니다 그래서 여기 당신이 가고, 어쨌든 외부에서 accesible 것 같다 GitHub에서 문제를 만듭니다. –

+0

실제로는 다릅니다. 나는 https://github.com/briandfoy/perlbench에 대해 몰랐다. 이 질문 중 하나는 SPEC CPU 2006 벤치 마크 슈트의 일부이며 C 컴파일러 및/또는 하드웨어, OS 등의 벤치 마크로서 perl 인터프리터를 사용하고 있습니다. – stanm

답변

4

segfault는 가리키는 줄에 변수 n의 가비지 값으로 인해 발생합니다. 코드를 검사하는 값이 필드 arg1에서 형식의 개체의 오는 것을 보여줍니다

struct regnode_1 { 
    U8 flags; 
    U8 type; 
    U16 next_off; 
    U32 arg1; 
}; 

객체의 메모리 위치를 검사가 포장되지 않는다는 것을 보여줍니다, 즉 next_offarg1 사이의 32 비트 패딩이있다 :

(gdb) x/16xb scan 
0x7f4978:  0xde 0x2d 0x02 0x00 0x00 0x00 0x00 0x00 
0x7f4980:  0x00 0x11 0x0d 0x00 0x00 0x00 0x00 0x00 
(gdb) print/x n 
$1 = 0xd1100 

이것은 수상한 내용입니다. perlbench에 포인터 및 유형 변환이 있으므로 유형 크기 가정이 어딘가에서 실패합니다. multilib으로 컴파일하면 작동중인 벤치 마크가 생성되고 메모리를 검사하면 패딩이 없는지 확인됩니다.

struct regnode_1 { 
    U8 flags : 8; 
    U8 type : 8; 
    U16 next_off : 16; 
    U32 arg1 : 32; 
}; 
+0

C 언어의 GNU C 언어에서 동일한 효과를 얻으려면'__attribute __ ((packed))'를 사용할 수도 있습니다. 휴대용이 아닌 구문을 사용하지 않고 구조체 패킹을 얻으려면 비트 필드를 사용하는 흥미로운 방법. –

+0

먼저 __attribute __ ((packed))를 사용해 보았습니다. (GCC와 clang 모두에서 작동 할 예정이지만) 메모리 레이아웃을 변경하지 않았습니다. 그렇다면 우리는 비트 필드가 도움이되지 않는다고 가정 했으므로이 쉬운 방법을 시도하기 전에 많은 다른 방법을 시도해 보았습니다. 그러나 확실히 덕트 테이프입니다. – stanm

+0

gcc는 적어도'-Wall'로 활성화 된'struct __attribute ((packed)) regnode_1' 대신에'struct' 키워드 앞에 넣어두면 경고 메시지를 표시합니다. BTW, x86-64 SystemV ABI에서 일반적인 정의만으로 패딩이 보이지 않습니다. Windows ABI 구조체 레이아웃 규칙에 따라이 구조체에 패딩이 적용됩니까? [Godbolt] (https://godbolt.org/g/CTmfef)에서 기본적으로 x86-64 Linux를 대상으로합니다 (System V ABI). 나는 그것이 packed/non-packed 구조체에 다른 효과를 가지고 있다는 것을 보여주기 위해 주석 처리되지 않은'unsigned : 1' 익명의 패딩을 넣었습니다. –

2

이것은 우리의 작은 조사가 진행 방법은 다음과 같습니다 :

먼저 우리가 어떤 패딩 문제라고 생각에서, 64 비트 컴파일을 수행 할 때 비트 필드에 구조를 강제

는 충돌을 해결합니다 그러나 Peter가 Godbolt을 지적 했으므로 그러한 일은 발생하지 않습니다. 그래서, 패킹 또는 구조의 아무것도 변경되지 않았습니다.

그런 다음 Perl이 포인터를 처리한다는 (분명히 비틀어 진) 의심 스러웠습니다. 대부분의 캐스트가 표준에서 정의한 엄격한 앨리어싱을 위반하고 있습니다. 분할 오류, 즉 포인터 캐스트에 일어난 이후 :

struct regnode { 
    U8 flags; 
    U8 type; 
    U16 next_off; 
}; 

그러나

struct regnode_1 { 
    U8 flags; 
    U8 type; 
    U16 next_off; 
    U32 arg1; 
}; 

에을의 -fstrict-aliasing 플래그를 가능하게 아무것도 변경하지 않았다. 정의되지 않은 비헤이비어로 규정되지만 현재 구문 분석중인 정규 표현식의 요소/노드가 메모리에 별도로 배치되므로 메모리에 중복이 없습니다.

깊은가는 문제의 switch 블록의 LLVM IR을 확인, 나는 C에서 포인터 것을 의미한다 64 비트 정수를 사용하는

; truncated 
%876 = load %struct.regnode*, %struct.regnode** %scan, align 8, !dbg !8005 
%877 = bitcast %struct.regnode* %876 to %struct.regnode_1*, !dbg !8005 
%arg11715 = getelementptr inbounds %struct.regnode_1, %struct.regnode_1* %877, i32 0, i32 3, !dbg !8005 
%878 = load i64, i64* %arg11715, align 8, !dbg !8005 
store i64 %878, i64* %n, align 8, !dbg !8006 
; truncated 

로드/저장 명령 regexec.ll이있어 (4 대신) 8 바이트 정수를 가리키는 것으로 해석됩니다.따라서 arg1 값을 계산하기 위해 현재 정규 표현식 노드 struct 바깥 쪽 2 바이트를 수집합니다. 이 값은 배열 인덱스로 사용되어 결국 배열 범위를 벗어나면 segfault 크래시가 발생합니다.

추적으로 돌아 가기 U32은 64 비트 부호없는 정수로 해석됩니다. 파일 spec_config.h를 찾고, 주변 지역의 코드 주석에 따르면, ILP32 데이터에 대응하도록되어있는

#elif !defined(SPEC_CPU_GOOFY_DATAMODEL) 

로 시작하는 전처리 블록 (내 컴퓨터에 적어도) 조건부 컴파일 리드 모델 (this 참조). 그러나 U32TYPE은 내 컴퓨터에서 64 비트 인 unsigned long으로 정의됩니다. (지원되는 경우)

그래서 수정 this에 명시된 바와 같이

#define U32TYPE uint32_t 

로 정의를 변경하는 것, 정확히 32 비트 인 것이 보증된다.

1

다른 답변을 보완하기 위해 -DSPEC_CPU_LP64을 segfault (CPU2017의 -DSPEC_LP64)를 해결하는 것으로 충분하다고 말하면서 보완하고 싶습니다. SPEC 그룹이 FAQ에 이것을 추가하면 좋을 것입니다. 이는 gcc, cactusADM, povraywrf에도 적용되는 것으로 보입니다.

우리는 우리를 위해 설정 파일을 생성하는 파이썬 스크립트를 가지고 있는데, 사람들과 이야기하고 지금까지 가지고있는 것을 우리의 컴파일러에서 실행하도록 공유 할 수 있는지를 살펴볼 것입니다.

편집 : spec.py

+0

필자는 관련 전처리 기 def를 찾을 수 없다는 것을 맹세 하겠지만 분명히 벤치마킹 플래그 구성 파일에서 뭔가를 놓쳤을 것입니다. 나는 시간이 허락 할 때 당신의 제안을보고 또 다시보고 할 것이다. – compor

+0

글쎄, 나는 그 segfault를 쳤을 때 주로 CPU2017의 스크립트를 준비하고 있었는데, 2006 년에 그것을 조정하면서 겉으로는 나 같은 남자와 닮았습니다. 나는 파란에서 올바른 플래그를 어떻게 추측 했어야하는지 잘 모릅니다. –