‘boost::bind를 맘 내키는 대로 써도 될까?’라는 의문에 각 경우의 속도를 비교해보기로 했다.
우선, 재물로 사용될 클래스를 만들고…
class test_class { public: test_class() : _i(10) {} void show(int i) { ++_i; } private: int _i; };// class test_class
아래는 테스트코드의 일부. TIME_DURATION은 포함되는 블록의 수행시간을 마이크로 초단위로 돌려준다.
const int repeat_num = 100000; hs_int64 d; test_class t; TIME_DURATION(d) { for (int i = 0; i < repeat_num; ++i) t.show(i); } cout << "direct call: " << d << endl; TIME_DURATION(d) { for (int i = 0; i < repeat_num; ++i) boost::bind(&test_class::show, &t, i)(); } cout << "boost.bind call: " << d << endl; boost::_bi::bind_t, boost::_bi::list2, boost::arg<1> > > t_mem_boost = boost::bind(&test_class::show, &t, _1); TIME_DURATION(d) { for (int i = 0; i < repeat_num; ++i) t_mem_boost(i); } cout << "boost.bind call via instance: " << d << endl; TIME_DURATION(d) { for (int i = 0; i < repeat_num; ++i) std::mem_fun(&test_class::show)(&t, i); } cout << "mem_fun call: " << d << endl; std::mem_fun1_t t_mem_stl = std::mem_fun(&test_class::show); TIME_DURATION(d) { for (int i = 0; i < repeat_num; ++i) t_mem_stl(&t, i); } cout << "mem_fun call via instance: " << d << endl;
결과
direct call: 658 boost.bind call: 9152 boost.bind call via instance: 4034 mem_fun call: 1972 mem_fun call via instance: 950
테스트를 반복해도 결과는 대동소이하다. boost::bind는 직접호출보다 10배 이상 느리다. 그나마 mem_fun이 좀 낮다.
따라서…
‘boost::bind를 맘 내키는 대로 써도 될까?’ -> 살살 쓰자
조금된 글이지만 잘못된 정보여서 리플 남기는데요
stl과 boost를 테스트할때 debug모드로 테스트해서 속도차이가 남다고 하는경우가 많은데 debug의경우 내부적으로 많은 디버그 코드가 들어 있기 때문에 느린게 당연합니다. 설마 배포시에도 debug로 빌드해서 배포하진 않겠죠?
또 Release로 빌드 해서 테스트 하더라도 위와같이 단순한 테스트는 특히 첫번째 테스트인 직접 호출의경우 show(i)가 백만번 호출되는데 show(i) 함수 내에서 1씩 더해 줍니다.
결과적으로보면 _i가 100만이 되는데 컴파일 과정에서 저렇게 유추가 가능한경우는 루프를 100만번 돌아서 i를 증가 시키는게 아니라 i에 그냥 100만을 넣어 줍니다.
첫번째 테스트는 함수호출비용은 전혀 계산되지 않고 i=백만 이결과의 속도인겁니다. 제가 위 코드를 수정해서 테스트를 몇번 해봤는데 별로 차이 bind가 약간더 느리긴하나 속도가 아주 중요한 부분이 아닌 일반적인 부분에선 충분히 사용해도 상관이 없을 정도 였습니다.
리눅스 커널버전 (2.6.26), Boost 버전 (1.39.0), GCC 버전 (4.3.2) 에서 최적화 옵션 빼고(default), 디버깅 옵션 빼고(default) 테스트 했습니다.
최적화 옵션을 켜고(-O3) 빌드해서 결과를 확인하니 그 차이가 많이 줄어드네요. 대부분의 경우에 direct call의 2배를 넘지 않는군요.
마지막으로, i를 증기시키는 부분은 컴파일러가 의미없는 함수콜에 대한 바이너리를 생성하지 않을 지도 몰라서 넣었습니다. 빼고 해봐도 결과는 대동소이하네요.
잘못된 부분이 있으면 또 알려주세요. 지적 감사합니다.