2017-02-16 1 views
2

코드를 작성할 때 "모듈"을 생성하여 논리적으로 나누는 프로그램 부분을 별도로 유지하려고합니다. 이 작업을 수행하기 위해 NodeJS 또는 Python을 사용하는 Javascript와 같은 언어에서부터 쉽습니다. C를 사용하여 아래 예제를 제공 한 패턴으로이 작업을 수행하는 방법을 찾았습니다. const 선언 된 구조체를 사용하여 정적 메서드 선언을 사용하여 "모듈"을 만들어 내 코드를 구성합니다.컴파일러가 구조체에서 함수 호출을 최적화하도록 할 수 있습니까?

이 기술로 메서드를 호출하는 데 드는 비용은 일반적으로 호출 당 하나의 어셈블리 명령입니다. 대신

movl -8(%rbp), %edx 
movl -12(%rbp), %eax 
movl %edx, %esi 
movl %eax, %edi 
call my_add_method 

은 "모듈"기술은 이러한 모듈을 선언하는 방법을

movl $my_add_method, %ecx 
movl -8(%rbp), %edx 
movl -12(%rbp), %eax 
movl %edx, %esi 
movl %eax, %edi 
call *%rcx 

를 내가 찾으려는 것은 생성하지만 컴파일 된 출력을하는 것은 단지를 호출하는 동일합니다 방법은 즉각적인 이름입니다.

내가 알고 싶은 것은 : 결과 ASM이되도록

  1. , 중 플래그 또는 다른 구조를 선언하여 컴파일러 (GCC)을 사용하는 방법이 있나요 코드를 최적화 똑같다?

  2. 단순한 컴파일러가 최적화 할 수있는 방법이 없다면 왜 이런 종류의 최적화가 일반적으로 불가능합니까?


일반적인 경우
/** 
* File: main.c 
* Target: x86_64-linux-gnu 
* Compile: gcc main.c -S -o main 
*/ 
#include <stdio.h> 

typedef struct { 
    int (* const add_func)(int, int); 
} MY_MOD_T; 

static int my_add_method(int a, int b) { 
    return a+b; 
} 

const MY_MOD_T Module = { 
    .add_func = my_add_method 
}; 

int main(void) { 
    int a = 5; 
    int b = 6; 

    // substitute these two lines to see the different output like above 
    int result = Module.add_func(a, b); 
    //int result = my_add_method(a, b); 

    printf("%d + %d = %d\n", a, b, result); 
    return 0; 
} 
+0

성능 차이를 안정적으로 감지 할 수 있습니까? –

+2

최적화 플래그 (-O)를 사용해 보셨습니까? 출력은 매우 다를 것입니다. '-O0'에서 asm 출력을 최적화하려고 시도하는 것은 아마도 무의미한 연습 일 것입니다. – Jahaja

+0

아니요. 이것은 성능에 대한 우려가 아니며 단지 호기심입니다. 방금 컴파일러가 최적화 할 수있는 간단한 일이라고 생각했습니다. – MatUtter

답변

1

, 동일하게 명명 된 함수를 호출하는 함수 포인터 동작합니다 통해 함수 호출을 할 수 없다 (구조 모두 일정하고 정적 고려).

typedef struct { 
    int (* const add_func)(int, int); 
} MY_MOD_T; 

module_derived.h라는 다른 헤더 파일 :

#include "module_interface.h" 

extern const MY_MOD_T Module; 

module_derived.c에서 파생 된 모듈의 구현 :

#include "module_derived.h" 

static int my_add_method(int a, int b) { 
    return a+b; 
} 

const MY_MOD_T Module = { 
    .add_func = my_add_method 
}; 

int module_add_method(int a, int b) { 
    return my_add_method(a, b); 
} 

당신의 예에서

는, 헤더 파일 module_interface.h을 고려

그러면 주 프로그램이 같은 OOK : module_derived 공유 라이브러리가 실제로 경우

#include <stdio.h> 
#include "module_derived.h" 

extern int module_add_method(int a, int b); 

int main(void) { 
    int a = 5; 
    int b = 6; 

    // substitute these two lines to see the different output like above 
    int result = Module.add_func(a, b); 
    //int result = module_add_method(a, b); 

    printf("%d + %d = %d\n", a, b, result); 
    return 0; 
} 

, 정말 함수 포인터 값이 역 참조해야한다는 사실을 극복 할 수있는 최적화 레벨이 없다.-O3에서 :

# Calling named function
movl $6, %esi
movl $5, %edi
call module_add_method
# Calling through module
movl $6, %esi
movl $5, %edi
call *Module(%rip)

자세히 알 수 있듯이 모듈 메커니즘을 통과 할 때 여분의 오프셋 계산과 역 참조가 있습니다.

그러나 공유 라이브러리의 경우이 모듈 오버 헤드는 위치 독립적 코드 (PLT 및 GOT 오버 헤드)에 의해 부과 된 오버 헤드와 비슷합니다. 실제로 프로파일 링이 그렇지 않다면 오버 헤드는 걱정할만한 가치가 없습니다. 이 경우 핫 함수 호출을 인라인하는 방법을 찾아야합니다.

+0

'''-shared'''를 사용하는 이유는 -O가 사용되는 경우에도 다른 출력물을 보았던 이유입니다. 감사합니다! – MatUtter

관련 문제