2014년 7월 11일 금요일

EFL : eina_safety_checks



efl 어플리케이션을 작성하다보면  error log중에

  ERR<24820>: elm_widget.c:964 _elm_widget_sub_object_add() safety check failed: obj == sobj is true

이런 메시지가 뜨는 에러가 있다.

safety check failed를 키워드로 검색하면 여러 파일이 나온다.

./efl/src/tests/eina/ 아래 파일에도 이러한 메시지들이 나오는데, tests 폴더 인것으로 보아 아마 더이상 쓰이지 않는 소스 같다.

이외 나오는 파일의 구현은 메시지를 커스터마이징 해서 쓰는 목적이 있어 따로 구현한 것으로 보이고 실질적인 구현은 ./efl/src/lib/eina/eina_safety_echeck.h에 되어 있다.

#ifdef를 통해 GCC확장을 이용하는 부분과 이용하지 않는 부분으로 구성되어 있다.

좀더 자세히 말하면 make 시점에 EINA_ARG_NONNULL의 define 여부에 따라 다르게 컴파일 되는데, 그 이유가 NULL체크를 아예 하지 않기 위해 그러는 것인지, GCC확장을 이용하지 않기 위해(또는 이용하지 못하는 환경을 위해)서 그런지는 확실치 않다.

주석에 no safety checks라 언급하고 있고, 구현부에 에러메시지를 나타내는 부분이 없는것으로 보아... 더 모르겠다.ㅜㅜ

./efl/src/lib/eina/eina_safety_echeck.h

#define EINA_SAFETY_ON_NULL_RETURN(exp)                                   \
  do                                                                      \
    {                                                                     \
       if (EINA_UNLIKELY((exp) == NULL))                                  \
         {                                                                \
            EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
            return;                                                       \
         }                                                                \
    }                                                                     \
  while (0)
 
  #define EINA_SAFETY_ON_NULL_RETURN(exp) \
  do { (void)(!(exp)); } while (0)

/////////////

#define EINA_SAFETY_ON_NULL_RETURN(exp) \
  do { (void)(!(exp)); } while (0)



그중 눈에 띄는 EINA_UNLIKELY의 원형은 다음과 같다.


#  define EINA_UNLIKELY(exp)    __builtin_expect((exp), 0)
#  define EINA_LIKELY(exp)      __builtin_expect((exp), 1)


컴파일러 지시자인 builtin_expect를 통해 분기문이 참이거나 거짓일 가능성이 높은 부분을 알려준다.

이는 성능을 위한 것으로, cpu의 분기 예측을 도와주어 파이프라인이 깨질 가능성을 낮춰주는데, 일반적인 Object의 NULL Check의 경우 NULL이 아닐 가능슷성이 높으므로 위 구문에서는 UNLIKELY를 써주었다.

__builtin_expect를 이용할 때 조심할 점은, 사용이 잘못 되더라도 error는 나지 않지만 성능 향상을 위해 쓴 기법이 오히려 성능 하락을 가져올 수 있으므로 조심하여야 한다.

리눅스 커널에는 동일한 구현이 unlikely()와 likely()라는 이름으로 구현되어 있으며,

gtk/Glib에는 boolean형을 int형으로 변환 하는 루틴이 추가되어 G_LIKELY()와 G_UNLIKELY()라는 이름으로 구현되어 있다.

댓글 없음:

댓글 쓰기