테스트 조건 및 성능 / 메모리 사용량 비교 방법

앞으로 "if vs switch 뭐가 더 빠를까?" 와 같은 주제로 포스팅을 여러 개 하려고 한다. C 코드를 컴파일하여 생성된 RISC-V 어셈블리(assembly) 코드로 성능 / 메모리 사용량을 비교하며, CPU architecture, 컴파일러 옵션 등에 따라 결과가 달라지므로 이 포스팅에 비교 조건을 명시하겠다.

먼저 이런 주제로 포스팅을 쓰게 된 계기를 말하자면, 임베디드 업무를 하다 보니 궁금해졌기 때문이다. 임베디드 업무를 하다 보면 성능 path는 조금이라도 더 빠르게 최적화해야 하는 경우가 있고, 메모리가 부족해서 메모리 사용량을 줄여야 하는 경우가 있다. 그러다 보니 if vs switch 뭐가 더 빠를까? int와 char가 성능 차이가 날까? 이런 게 평소에 궁금했고, 궁금한 것들에 대해서 성능 / 메모리 사용량을 비교하고 내용을 정리하려고 한다.

매우 오래된 글이지만 C 코드 최적화 관련하여 아래 link는 참고할 만하다.

테스트 조건

  • CPU
    • single cycle CPU : load / store를 포함해서 모든 명령어가 1cycle에 수행된다.
    • ISA(Instruction Set Architecture) : RISC-V RV32I (RV는 RISC-V를 의미하고 32는 32bit address를 지원함을 의미하고 I는 무조건 포함해야 하는 base integer instruction set을 지원함을 의미한다. 이 외에도 여러 개의 optional instruction set이 있으나, 여기서는 지원하지 않는다.)
  • 메모리
    • code와 data 모두 RAM에 위치하고 cache는 없다.
  • 컴파일러
  • 컴파일러 옵션
    • -march=rv32i : 지원하는 RISC-V instruction set 이며, RV32I로 지정
    • -mabi=ilp32 : ABI를 지정하며, int, long, pointer 크기가 32bit이며 long long은 64bit, char는 8bit, short은 16bit이다.
    • -O2 : 컴파일러 최적화 옵션

성능 / 메모리 사용량 비교 방법

bool 변수와 char 변수에 각각 int 변수를 대입하는 것을 예로 들어 비교하면서 비교 방법을 설명하겠다. C 코드를 컴파일하여 생성된 어셈블리 코드와 symbol table을 보고 속도와 메모리 사용량을 비교한다. 

<C 코드>
#include <stdbool.h>

bool bool1;
char char1;

int int2 = 1;

void assign_int_to_bool(void)
{
    bool1 = int2;
}

void assign_int_to_char(void)
{
    char1 = int2;
}

<symbol table>
location                  size     name
10000008 g     O .sbss 00000001 char1
10000009 g     O .sbss 00000001 bool1
10020000 g     O .sdata 00000004 int2

각 symbol(함수, 변수 등)의 메모리 위치와 크기가 나와 있다. 예컨대 char1 변수는 0x10000008 번지에 위치하고 크기는 1byte다.

<어셈블리 코드>
00000000 <assign_int_to_bool>:
   0:	100207b7          	lui	a5,0x10020
   4:	0007a783          	lw	a5,0(a5) # 10020000 <int2>
   8:	10000737          	lui	a4,0x10000
   c:	00f037b3          	snez	a5,a5
  10:	00f704a3          	sb	a5,9(a4) # 10000009 <bool1>
  14:	00008067          	ret

00000018 <assign_int_to_char>:
  18:	100207b7          	lui	a5,0x10020
  1c:	0007a703          	lw	a4,0(a5) # 10020000 <int2>
  20:	100007b7          	lui	a5,0x10000
  24:	00e78423          	sb	a4,8(a5) # 10000008 <char1>
  28:	00008067          	ret

예컨대 <assign_int_to_bool>는 함수 이름이며, "0:, 4:, 8:, c:, 10:, 14:"는 코드의 메모리 위치이다. "14:"는 0x14 번지를 의미하며 "00008067"이라는 기계어가 위치하며 해당하는 어셈블리 코드는 "ret" 이다. "00008067"은 16진수이며 크기는 4byte다. 기계어를 보면 모든 명령어가 4byte인 것을 알 수 있다.
그리고 컴파일 옵션을 [-march=rv32i]로 하지 않고 [-march=rv32ic]로 하면 compressed insturction이 추가되어 일부 명령어가 동작은 동일하지만 4byte가 아닌 2byte로 변경된다. 하지만 여기서는 code 크기 계산의 단순화를 위해 compressed instruction을 추가하지는 않았고, compressed instruction이 궁금하면 RISC-V SPEC을 찾아보기 바란다.

성능 비교

single cycle CPU이므로 수행한 명령어 개수가 성능을 나타낸다. assign_one_to_bool 함수는 명령어가 6개이고 assign_int_to_char 함수는 명령어이기 5개이므로 assign_int_to_char 함수가 더 빠르다.

char > bool

메모리 사용량 비교

code와 data가 모두 RAM에 있고 메모리 사용량은 code 크기와 data 크기를 합한 값이다.
data 크기는 symbol table을 보면 char1은 1byte고 bool1은 1byte다. 그리고 모든 명령어가 4byte이기 때문에 code 크기는 "명령어 개수 * 4byte" 이다. assign_int_to_bool 함수는 명령어가 6개이므로 24byte이며 assign_int_to_char 함수는 명령어가 5개이므로 20byte다. 메모리 사용량은 아래와 같고 char에 int를 대입한 경우가 더 작다.

                data size  code size  total
bool               1byte    24byte   25byte
char               1byte    20byte   21byte

char < bool

테스트 조건 선정 배경

single cycle CPU

여기서는 가상의 single cycle CPU를 사용하지만, ARM Cortex 시리즈나 SiFive RISC-V 시리즈를 보면 적어도 2단계 파이프라인(pipeline)을 가지고 있고 보통 더 많은 파이프라인 단계를 가지고 있다. 보통 파이프라인 단계가 많아질수록 clock을 높이기 쉬워서 성능을 높일 수 있기 때문이다. 하지만 여기서는 성능 비교를 단순화하기 위해서 single cycle CPU를 선택했다. 그렇다 하더라도 간단한 것을 비교하기 때문에 보통은 파이프라인 단계가 많은 CPU와도 비슷한 결과가 나올 것이다. 그리고 C 코드가 어셈블리 코드로 어떻게 변환되는지 보고 CPU가 어떻게 동작하는지 이해하면, 다른 CPU를 이해하는데도 도움이 될 것이다. 포스팅에 별도의 언급이 없으면 single cycle CPU를 사용하는 것이며, 파이프라인 해저드(pipeline hazard), 분기 예측(branch prediction) 등의 설명이 필요해서 pipelined CPU를 사용하는 경우에는 포스팅에 따로 언급하겠다.

RISC-V ISA(Instruction Set Architecture)

산업계에서 ARM이 널리 쓰이고 있고 RISC-V는 시장 점유율이 ARM과 비교할 수 없을 정도로 떨어진다. 하지만 시장에서 ARM의 강력한 경쟁자로 여겨지고 있고 미래에 시장 점유율이 많이 올라갈 것으로 예상하고 있다. 또한 명령어 개수가 적고 명령어 동작이 simple 해서 여기서 다루는 주제를 가지고 study 하기에 적합해서 RISC-V ISA를 선택했다.

* Feedback은 언제나 환영합니다.

Comments