짧아진 코드에 체크하기 전에
Table of Contents
ARM32용 C 코드의 최적화를 판단할 때 나는 대상 프로세서, 줄이려는 비용, 대신 늘어날 비용부터 확인하려 한다. 소스가 짧아졌다는 사실만으로는 어느 항목에도 체크할 수 없다. 같은 일을 하는 코드라도 명령어와 레지스터를 어떻게 쓰는지에 따라 결과가 달라지기 때문이다.
내가 붙잡는 판단은 하나다. 최적화가 됐다는 말에는 어떤 조건에서 무엇이 나아졌는지가 따라와야 한다. 아래 항목은 좋은 코드를 골라내는 만능 기준이 아니다. ARM32의 특성을 고려해 C 코드를 바꾸려 할 때, 변경을 받아들일 근거가 있는지 확인하는 순서다.
1. 대상이 충분히 좁혀졌는가
조건을 붙이려면 먼저 코드가 실행될 대상을 알아야 한다. ARM32라는 이름 아래에서도 사용할 수 있는 명령어와 실행 특성이 모두 같지는 않다. 어느 프로세서를 기준으로 판단하는지 빠져 있으면, 효율적이라는 설명의 적용 범위부터 불분명해진다.
나는 여기서 소스의 모양에 대한 평가를 잠시 멈추려 한다. C로 같은 계산을 적을 수 있다는 것과, 그 계산이 대상에서 같은 비용으로 실행된다는 것은 별개다. 대상이 정해져야 코드의 형태와 실제 실행 사이를 확인할 수 있다. 그다음에야 무엇을 줄일지 고를 차례다.
2. 줄이려는 비용을 하나 골랐는가
대상을 알아도 목표가 모호하면 변경의 좋고 나쁨을 판단하기 어렵다. 실행 지연을 줄이려는지, 코드 크기를 줄이려는지부터 구분해야 한다. 둘을 한꺼번에 좋아졌다고 묶으면 한쪽의 손해가 쉽게 가려진다.
임베디드 소프트웨어에서는 전력과 메모리 비용도 고려해야 하지만, 한 번의 변경으로 모든 항목이 개선된다고 기대할 근거는 없다. 나는 우선 이번 변경을 받아들일 이유가 되는 항목 하나를 정하고 싶다. 다른 비용은 무시하는 대신, 그 목표를 위해 어디까지 늘어나도 되는지 확인한다.
3. 목표를 위해 늘어난 비용도 봤는가
허용할 증가분을 정했다면, 변경 뒤에는 그 항목도 함께 봐야 한다. 함수를 인라인으로 풀어 쓰는 선택이 여기에 해당한다. 호출에 드는 일을 줄일 여지는 있지만, 함수 본문이 여러 호출 지점에 들어가면 코드 크기가 늘어날 수도 있다. 호출을 줄였다는 설명만으로 변경을 승인하기 어려운 이유다.
실행 지연이 목표라면 실제로 지연이 줄었는지를 보고, 늘어난 코드가 허용한 크기 안에 있는지도 확인해야 한다. 반대로 코드 크기가 목표였다면 호출이 사라졌다는 사실은 충분한 성과가 아니다. 인라인이라는 표시는 선택한 방법을 알려줄 뿐, 목표를 달성했다는 결과까지 알려주지는 않는다.
여기서 나는 인라인을 권하거나 피하자는 결론을 내리지 않는다. 이 선택이 보여 주는 것은 하나다. 이득을 설명하는 항목만 체크하면, 그 이득 때문에 지불한 비용을 놓칠 수 있다. 확인할 것은 기법의 평판보다 이번 변경의 결과다.
4. 확인한 결과의 범위를 지켰는가
결과를 확인했더라도 처음 정한 대상 밖으로 판단을 넓히지는 말아야 한다. 특정 ARM32 환경에서 유리했던 코드 형태가 다른 대상에서도 유리하다고 말하려면 다시 확인할 근거가 필요하다. 실행 가능성을 유지하는 것과 성능상의 이점을 유지하는 것도 같은 조건은 아니다.
이 점검 순서는 오래된 ARM32의 명령어와 실행 특성을 고려하는 최적화에 한정한다. 그 범위에서 얻은 설명을 오늘의 다른 프로세서에 곧바로 적용할 수는 없다. 나는 변경을 받아들이기 전에 마지막으로 적용 대상을 다시 적어 보려 한다. 처음 확인한 프로세서와 비용 조건에서 나온 결과인지, 대상이 달라져 다시 확인해야 하는지를 남겨 둔다.