맨위로가기

인라인 확장

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

인라인 확장은 컴파일러가 함수 호출을 해당 함수의 본문으로 대체하여 코드의 성능을 향상시키는 최적화 기법이다. 컴파일러는 중간 표현 단계에서 인라인 확장을 수행하며, 링커나 런타임 시스템에서도 이를 수행할 수 있다. 인라인 확장은 함수 호출 오버헤드를 줄이고 추가적인 최적화를 가능하게 하지만, 코드 크기 증가와 캐시 성능 저하를 야기할 수 있다. 다양한 휴리스틱이 인라인 확장을 위해 연구되었으며, 프로그래머는 컴파일러 지시어를 통해 인라인 확장을 지정할 수 있다. C, C++, 하스켈 등 다양한 프로그래밍 언어에서 인라인 확장을 지원하며, 컴파일러는 성능 향상을 위해 자동으로 인라인을 수행하기도 한다.

2. 구현

컴파일러는 고수준 또는 저수준 중간 표현 단계에서 인라인 확장을 수행한다. 링커런타임 시스템도 인라인 확장을 수행할 수 있다.

일반적으로 함수가 호출되면 제어 흐름은 분기 또는 호출 명령어를 통해 함수의 정의로 전송된다. 인라인을 사용하면 분기 또는 호출 명령어 없이 제어가 함수에 대한 코드로 직접 넘어간다.

컴파일러가 특정 함수를 인라인하기로 결정하면, 인라인 연산 자체는 보통 간단하다. 컴파일러는 고수준 중간 표현 (예: 추상 구문 트리) 또는 저수준 중간 표현에서 인라인을 수행할 수 있다. 어느 경우든, 컴파일러는 단순히 매개변수를 계산하고, 이를 함수의 인수에 해당하는 변수에 저장한 다음, 호출 지점에 함수의 본체를 삽입한다.

링커도 함수 인라인을 수행할 수 있는데, 소스를 사용할 수 없는 함수 (예: 라이브러리 함수)를 인라인할 수 있다 (링크 타임 최적화 참조). 런타임 시스템도 함수를 인라인할 수 있으며, Java Hotspot 컴파일러와 같이 동적 프로파일링 정보를 사용하여 어떤 함수를 인라인할지에 대한 더 나은 결정을 내릴 수 있다.[3]

다음은 C 프로그래밍 언어에서 소스 수준에서 "수동으로" 수행되는 인라인 확장의 간단한 예이다.



int pred(int x)

{

if (x == 0)

return 0;

else

return x - 1;

}



''인라인 전:''



int func(int y)

{

return pred(y) + pred(0) + pred(y+1);

}



''인라인 후:''



int func(int y)

{

int tmp;

if (y == 0) tmp = 0; else tmp = y - 1; /* (1) */

if (0 == 0) tmp += 0; else tmp += 0 - 1; /* (2) */

if (y+1 == 0) tmp += 0; else tmp += (y + 1) - 1; /* (3) */

return tmp;

}



이것은 단지 예시일 뿐이다. 실제 C 응용 프로그램에서는 매개변수화된 매크로 또는 인라인 함수와 같은 인라인 언어 기능을 사용하여 컴파일러에게 이 방식으로 코드를 변환하도록 지시하는 것이 더 좋다.

2. 1. 어셈블리 매크로 확장을 통한 인라이닝

어셈블러 매크로는 명령어 시퀀스를 단일 매크로 소스 문(0개 이상의 매개변수 포함)에서 매크로 확장을 통해 일반적으로 인라인으로 생성할 수 있는, 인라인 방식의 대안을 제공한다. 매개변수 중 하나는 해당 시퀀스를 포함하는 일회성 서브루틴을 생성하고, 함수에 대한 인라인 호출로 처리하는 옵션일 수 있다.

예시:



MOVE FROM=array1,TO=array2,INLINE=NO


2. 2. 휴리스틱

인라인 확장을 위해 다양한 휴리스틱이 연구되어 왔다. 일반적으로 인라인 확장 알고리즘은 특정 코드 예산(프로그램 크기의 허용된 증가)을 가지며, 해당 예산을 초과하지 않으면서 가장 가치 있는 호출 지점을 인라인하는 것을 목표로 한다. 이러한 의미에서, 많은 인라인 확장 알고리즘은 일반적으로 배낭 문제를 모델로 한다.[4] 어떤 호출 지점이 더 가치 있는지 결정하기 위해, 인라인 확장 알고리즘은 그 이점, 즉 실행 시간의 예상 감소를 추정해야 한다. 일반적으로, 인라이너는 다른 코드 경로의 실행 빈도에 대한 프로파일링 정보를 사용하여 이점을 추정한다.[5]

프로파일링 정보 외에도, 새로운 JIT 컴파일러는 다음과 같은 몇 가지 더 발전된 휴리스틱을 적용한다:[6]

  • 어떤 코드 경로가 실행 시간의 가장 큰 감소를 가져올지 예측하고(인라인 확장의 결과로 추가 컴파일러 최적화를 활성화함으로써) 그러한 경로의 예상 이점을 증가시킨다.
  • 컴파일 단위의 크기와 이미 인라인된 코드의 양에 따라 인라인 확장에 대한 비용 대비 이점 임계값을 적응적으로 조정한다.
  • 서브루틴을 클러스터로 그룹화하고, 단일 서브루틴 대신 전체 클러스터를 인라인한다. 여기서 휴리스틱은 클러스터의 적절한 부분 집합만 인라인하는 것이 아무것도 인라인하지 않는 것보다 더 나쁜 성능을 가져오는 메서드를 그룹화하여 클러스터를 추측한다.

3. 성능에 미치는 영향

인라인 확장은 함수 호출 오버헤드를 제거하여 시간 성능을 향상시키지만, 코드 크기 증가라는 직접적인 비용이 발생한다.[1] 주요 이점은 함수 경계를 넘는 최적화를 가능하게 하여 추가적인 성능 향상을 가져올 수 있다는 것이다.[1]

인라인 확장의 속도에 대한 궁극적인 영향은 메모리 시스템(주로 명령어 캐시)의 성능에 미치는 여러 가지 영향으로 인해 복잡하며, 이는 최신 프로세서의 성능을 지배한다. 특정 프로그램과 캐시에 따라 특정 함수를 인라인하면 성능이 증가하거나 감소할 수 있다.[1]

인라인의 영향은 추상화 정도에 따라 다르기 때문에 프로그래밍 언어와 프로그램에 따라 다르다. C 및 Fortran과 같은 하위 수준의 명령형 언어에서는 일반적으로 코드 크기에 미미한 영향을 미치면서 10–20%의 속도 향상이 발생하지만, 더 추상적인 언어에서는 인라인이 제거하는 계층 수로 인해 훨씬 더 중요할 수 있다. 극단적인 예로 Self의 한 컴파일러는 인라인을 통해 4~55배의 개선 효과를 보였다.[1]

메모리 시스템에 대한 인라인의 또 다른 이점은 분기를 제거하고 메모리에 함께 실행되는 코드를 유지하여 참조 지역성(공간적 지역성 및 명령어의 순차성)을 개선함으로써 명령어 캐시 성능을 향상시킨다는 것이다.[1]

인라인의 직접적인 비용은 각 호출 지점에서 함수 본문을 중복하므로 코드 크기가 증가하는 것이다. 그러나 매우 짧은 함수, 즉 함수 본문이 함수 호출의 크기(호출자, 인수 및 반환 값 처리를 포함)보다 작은 경우(예: 사소한 접근자 메서드 또는 변경자 메서드)나 한 곳에서만 사용되는 함수의 경우에는 중복되지 않으므로 코드 크기가 증가하지 않을 수 있다. 따라서 코드 크기에 대한 최적화를 하는 경우(예: 임베디드 시스템)에는 인라인이 최소화되거나 제거될 수 있다.

인라인은 코드 확산(중복)으로 인해 명령어 캐시 성능을 저하시켜 성능에 비용을 부과하기도 한다.[1] 이는 프로그램의 작업 집합(코드의 핫 섹션)이 확장 전에는 메모리 계층의 한 레벨(예: L1 캐시)에 적합했지만, 확장 후에는 더 이상 적합하지 않아 해당 레벨에서 빈번한 캐시 미스가 발생하는 경우 가장 중요하다. 계층의 여러 레벨에서 성능이 크게 다르기 때문에, 이는 성능에 상당한 악영향을 미친다. 최고 수준에서는 페이지 폴트 증가, 스래싱으로 인한 치명적인 성능 저하, 또는 프로그램 실행 실패로 이어질 수 있다. 이러한 현상은 일반적인 데스크톱 및 서버 응용 프로그램에서는 드물지만, 코드 크기가 사용 가능한 메모리에 비해 작은 임베디드 시스템과 같은 리소스가 제한된 환경에서는 문제가 될 수 있다. 이 문제를 완화하는 한 가지 방법은 함수를 더 작은 핫 인라인 경로(고속 경로)와 더 큰 콜드 비인라인 경로(저속 경로)로 분할하는 것이다.[1]

인라인이 성능을 저하시키는 것은 주로 여러 곳에서 사용되는 큰 함수에 대한 문제이지만, 인라인이 성능을 감소시키는 분기점은 결정하기 어렵고, 일반적으로 정확한 로드에 따라 다르므로 수동 최적화 또는 프로파일 안내 최적화의 대상이 될 수 있다.[2] 이는 루프 언롤링과 같은 다른 코드 확장 최적화와 유사한 문제이며, 처리되는 명령어 수는 줄이지만 더 나쁜 캐시 성능으로 인해 성능을 저하시킬 수 있다.

캐시 성능에 대한 인라인의 정확한 영향은 복잡하다. 작은 캐시 크기(확장 전 작업 집합보다 훨씬 작음)의 경우, 증가된 순차성이 우세하며 인라인은 캐시 성능을 향상시킨다. 인라인이 작업 집합을 확장하여 캐시에 더 이상 적합하지 않도록 캐시 크기가 작업 집합에 가까운 경우에는 캐시 성능이 감소한다. 캐시 크기가 작업 집합보다 큰 경우, 인라인은 캐시 성능에 미미한 영향을 미친다. 또한, 로드 포워딩과 같은 캐시 설계 변경으로 인해 캐시 미스 증가가 상쇄될 수 있다.[1]

3. 1. 장점

인라인 확장은 함수 호출 오버헤드를 줄이고 추가적인 최적화를 가능하게 하며, 참조 지역성을 개선하는 등 여러 장점을 가진다.

  • 함수 호출 오버헤드 제거: 함수 호출 및 반환 관련 명령어(예: 분기 명령어)를 제거하고, 레지스터 스필링을 감소시키며, 참조 호출을 불필요하게 만든다.[1]
  • 추가 최적화 활성화: 절차간 최적화를 가능하게 하여 상수 전파, 루프 불변 코드 이동, 레지스터 할당 개선 등 추가적인 최적화를 수행할 수 있게 한다.[1]
  • 참조 지역성 개선: 분기를 제거하고 코드의 순차성을 유지하여 명령어 캐시 성능을 향상시킨다.[1]


이러한 장점들은 코드 크기 증가를 어느 정도 감수하고라도 얻을 수 있는 성능 향상 효과이다. 특히, 자주 호출되는 작은 함수나 추상화 정도가 높은 언어(예: Self)에서 인라인 확장의 효과가 크다.[1]

3. 2. 단점

인라인 확장은 각 호출 지점에 함수 본문이 복제되어 코드 크기를 증가시킨다.[1] 이는 명령어 캐시 성능 저하를 유발할 수 있는데,[2] 특히 프로그램의 작업 집합이 확장 전에는 L1 캐시와 같은 메모리 계층의 한 레벨에 맞았지만, 확장 후에는 더 이상 맞지 않아 해당 레벨에서 빈번한 캐시 미스가 발생하는 경우 성능에 큰 영향을 미친다.

인라인 확장은 레지스터 부족 현상을 야기할 수도 있다. 인라인 확장된 부분에서 사용하는 변수가 늘어나면서 레지스터 소비가 증가하고, 경우에 따라 레지스터가 부족해져 새로운 메모리 액세스가 증가하여 성능이 저하될 수 있다.

코드 크기가 커지면 메모리 제한을 초과하여 스래싱을 일으키거나 실행 실패를 유발할 수 있다.[1] 이는 주로 임베디드 시스템과 같이 리소스가 제한된 환경에서 문제가 된다.

인라인 확장된 함수에는 브레이크 포인트를 설정할 수 없어 디버깅이 어려워진다는 문제점도 있다.

4. 한계

재귀 함수는 완전한 인라인 확장이 불가능하다. 재귀적으로 호출을 인라인 확장하면 종료되지 않기 때문이다. 이를 해결하기 위해 호출 그래프를 분석하고 특정 노드에서 루프를 끊는 방법(재귀 루프의 일부 간선을 확장하지 않음)과 같이 제한된 양만 확장하는 방법이 있다.[1] 재귀 확장이 종료되지 않는 문제는 C, C++ 등에서 재귀 매크로를 금지하여 해결하는 매크로 확장에서도 동일하게 발생한다.

5. 매크로와의 비교

C와 같은 언어에서 전통적으로 인라인 확장은 소스 수준에서 매개변수화된 매크로를 사용하여 수행되었다. C99에서 사용 가능한 실제 인라인 함수는 매크로에 비해 다음과 같은 몇 가지 이점을 가진다.[1]


  • C에서 매크로 호출은 타입 검사를 수행하지 않거나 인수가 올바르게 구성되었는지조차 확인하지 않지만, 함수 호출은 일반적으로 수행한다.[1]
  • C에서 매크로는 함수와 동일한 의미로 `return` 키워드를 사용할 수 없다 (매크로를 종료하게 되며, 확장을 요청한 함수를 종료하는 것이 아니다). 즉, 매크로는 내부에서 호출된 마지막 표현식의 결과가 아닌 것을 반환할 수 없다.[1]
  • C 매크로는 단순한 텍스트 대체를 사용하기 때문에, 인수의 재평가 및 연산 순서로 인해 의도하지 않은 부작용과 비효율성이 발생할 수 있다.[1]
  • 매크로 내의 컴파일러 오류는 종종 이해하기 어려운데, 프로그래머가 입력한 코드가 아니라 확장된 코드를 참조하기 때문이다. 따라서 인라인 코드에 대한 디버깅 정보는 일반적으로 매크로 확장 코드의 정보보다 더 유용하다.[1]
  • 많은 구문은 매크로를 사용하여 표현하기 어렵거나 불가능하며, 또는 상당히 다른 구문을 사용한다. 인라인 함수는 일반 함수와 동일한 구문을 사용하며, 필요에 따라 쉽게 인라인 및 언인라인할 수 있다.[1]


많은 컴파일러는 일부 재귀 함수도 인라인 확장할 수 있지만, 재귀 매크로는 일반적으로 허용되지 않는다.[1]

비야네 스트롭스트루프는 C++의 설계자로서, 가능한 한 매크로를 피하고 인라인 함수를 광범위하게 사용할 것을 옹호한다.[1]

6. 선택 방법

많은 컴파일러는 이점이 있는 경우 함수를 적극적으로 인라인한다. 실행 파일이 커질 수 있지만, 메모리 용량이 CPU 속도보다 빠르게 증가함에 따라 공격적인 인라인이 점점 더 바람직해지고 있다. 인라인은 함수형 프로그래밍 언어와 객체 지향 프로그래밍 언어에서 중요한 최적화 기법이며, 일반적으로 작은 함수에 충분한 컨텍스트를 제공하여 고전적인 최적화를 효과적으로 만드는 데 의존한다.[1]

7. 언어 지원

자바와 같은 함수형 프로그래밍 언어는 명시적인 인라인 함수 구성 요소를 제공하지 않지만, 컴파일러/인터프리터가 공격적인 인라인 확장을 수행한다.[6] 다른 언어들은 일반적으로 컴파일러 지시어 (프래그마) 형태로 명시적인 힌트를 제공한다.

언어사용법
에이다`pragma Inline`을 제공한다.[6]
공통 리스프`inline` 선언을 사용한다.[8]
하스켈 (GHC)`{-# INLINE #-}` 프래그마를 사용한다.[9]
C/C++:`inline` 키워드를 사용한다. (주 목적은 함수의 가시성 및 링크 동작 변경)[6]


참조

[1] 웹사이트 Unusual speed boost: size matters https://www.webkit.o[...] 2013-08-08
[2] 웹사이트 Adaptive Optimization System https://web.archive.[...] 2011-08-09
[3] 논문 An_Optimization-Driven_Incremental_Inline_Substitution_Algorithm_for_Just-in-Time_Compilers https://www.research[...]
[4] 논문 Scheifler, An Analysis of Inline Substitution for a Structured Programming Language https://dl.acm.org/c[...]
[5] 논문 Matthew Arnold, Stephen Fink, Vivek Sarkar, and Peter F. Sweeney, A Comparative Study of Static and Profile-based Heuristics for Inlining https://dl.acm.org/c[...]
[6] 간행물 Prokopec et al., An Optimization Driven Incremental Inline Substitution Algorithm for Just-In-Time Compilers, CGO'19 publication about the inliner used in the Graal compiler for the JVM https://www.research[...]
[7] 웹사이트 Inlining Semantics for Subroutines which are Recursive https://web.archive.[...] Henry G. Baker
[8] 웹사이트 Declaration INLINE, NOTINLINE http://www.lispworks[...]
[9] 웹사이트 7.13.5.1. INLINE pragma http://www.haskell.o[...] Chapter 7. GHC Language Features
[10] 웹사이트 https://en.cpprefere[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com