if문에 대한 성능 질문입니다.

kid1402의 이미지

함수에서 파라미터들의 Validity 체크를 할 때, if 문 하나에 한꺼번에 다 체크하는 것이 성능이 좋을지, 아니면 그냥 하나하나 체크해주는게 좋을 지 궁금합니다.(하나에 다 넣어도 컴파일러가 최적화 해주려나요?)

예를 들어

BOOL CRegistry::SetValue(LPCTSTR valueName, DWORD value)
{
	if( !valueName || !value || !mIsOpened)
	{
		return FALSE;
	}
 
....

BOOL CRegistry::SetValue(LPCTSTR valueName, DWORD value)
{
	if( !valueName)
	{
		return FALSE;
	}
 
        if( !value)
        {
                return FALSE;
        }
 
	if( !mIsOpened )
	{
		return FALSE;
	}
....

이 두 코드중 어떤것이 더 성능에 좋을까요?
혹은 성능에 끼치는 영향이 적을까요?

이와 관련해서 의견이 궁금합니다

sohn9086의 이미지

컴파일러 최적화를 사용하지 않는다고 가정하면, 첫번째 예가 나은 성능을 보여줄 것으로 생각됩니다. 왜냐면 두번째 예는 파라미터 체크가 끝날 때 까지 세 번의 점프 명령을 수행할 지도 모르기 때문입니다. 보통 점프 명령은 파이프라인에 들어있던 명령을 모두 버려야하기 때문에 페널티가 매우 큽니다.

생산적인 댓글을 달자

addnull의 이미지

제 생각에는 질문자께서 보여주신 첫 번째 경우가 short-circuit evaluation 조건에 의해서 컴파일러 옵션과 상관없이
두 번째 경우와 같은 성능을 나타낼 거라 생각됩니다.

sohn9086의 이미지

여기서 short-circuit이 먹힐려면 valueName이 NULL이여야 하는데 그건 아마 파라미터가 잘못들어왔을 때, 즉 비정상적인 호출을 받았을 때입니다.
이 함수가 얼마만큼의 빈도로 비정상적인 호출을 당할 지는 저도 잘 모르겠지만, 평소에는 정상적으로 호출될 것이며 어쩌다가 잘못된 파라미터가 들어올 때 FALSE로 빠질 것이라고 예측했습니다.
때문에 저는 첫번째 두번째 모두 FALSE로는 잘 빠지지 않고 그 아래의 원래 함수처리를 수행한다는 가정하에 말씀을 드렸습니다.

생산적인 댓글을 달자

addnull의 이미지

앞의 두 조건 "!valueName" 과 "!value" 이 거짓이라도
(즉 valueName 와 value 값이 "true" 일지라도)

첫 번째 경우와 두 번째 경우의 성능 차이는 거의 없을걸로 보입니다. (아래 gurugio 님의 답글에서 설명하신 것처럼...)

sohn9086 께서 말씀하신 jump 명령의 실행 횟수가 질문자께서 올린 첫 번째 경우와 두 번째 경우 같을 것 같습니다.

gurugio의 이미지


최적화보다 더 중요한 가독성을 생각했을 때는 첫번째 예의 방식으로 프로그래밍하는게 좋을것 같습니다.

제가 알기로는 컴파일러가 특정 statement를 한꺼번에 처리하느냐 한 부분씩 처리하느냐에 따라 다르기도합니다.
if (a & b & c)라는 문장을 처리할 때,

d = a & b & c;
if (d) ...

이렇게 처리할때는 기계어로

mov d, a
and d, b
and d, c

이렇게 될 수 있지만, 만약에 한 구문씩 처리한다면,

cmp a, NULL
je LABELA
cmp b, NULL
je LABELC
...

이렇게 컴파일될것 같습니다.

제가 알기로는 C 컴파일러는 두번째 방식으로 한 구문씩 처리한다고 들었습니다.
전체 문장을 모두 번역하지않고 하나의 조건만이라도 거짓이되면 다음 조건은 판단하지않고
바로 문장 전체를 거짓으로 판단한다고 들었습니다.

따라서 말씀하신 두 예제가 기계어로 변환되는 것도 원칙대로라면 비슷해야할것 같습니다.
그런데 최적화 기술이 적용될 것이니까 좀 다를 수는 있겠지요.
만약 첫번째 예제가 좀더 빠르다해도 그 차이가 아주 미미해서 결과적으로 드러나는 차이는 없을것 같습니다.

chadr의 이미지

요즘 컴파일러 성능도 매우 좋고 요즘 cpu의 분기예측 성능 또한 매우 좋습니다.

컴파일러 성능이 매우 안좋고 분기예측 기능이 없는 cpu를 쓴다면 고민을 해봐야할 사항이나 우리가 사용하는 컴퓨터에서는 굳이 고민하지 않아도 알아서 최적화 잘 해줍니다.

그런것 보다는 전체적인 디자인(설계)에 더 집중하시는 것을 추천합니다.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

sohn9086의 이미지

무슨 말씀이신지는 이해가 됩니다만 순수히 컴퓨터를 좀 더 알고싶은 사람들도 있으니 기왕이면 요즘 CPU의 분기예측이 어떠어떠하니까 이런거에 고민하지 말라거나 컴파일러의 최신 트렌드를 소개하는 등의 댓글을 달아주시면 고맙겠습니다.

Think low-level, write high-level 이라는 말도 있지않습니까?

태클아니니 오해마시기 바랍니다.

생산적인 댓글을 달자

chadr의 이미지

여기에 답글을 달기에는 너무 길구요. 그냥 구글링 하셔도 잘 나옵니다.

가볍게 읽어보실만한 서적은 "프로그래머가 몰랐던 멀티코어 cpu이야기"라는 서적을 보시면 요즘 cpu의 기능에 대해서 알기 쉽게 설명되어있습니다.

컴파일러에 대해서는 구글에서 "compiler optimization" 라고만 검색해도 많이 나옵니다.

http://en.wikipedia.org/wiki/Compiler_optimization 를 참고해보시면 괜찮을것 같네요.

Think low-level, write high-level 라는 말에 공감은 합니다만 제가 그정도까지 해야하는지에 대해서는 공감이 안되네요.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

익명 사용자의 이미지

보통은 성능보단 가독성에 더 좋은 쪽으로 소스를 쓰게되는데
그렇지 않고 이런 고민을 가지고 있다면 그냥 어셈코드를 생성해서 직접 보면 됩니다.
그게 정답이구요.
그냥 말로만 갑론을박 하는건
잘못된 이야기를 진실로 오해하게 만드는 위험이 있습니다.

jick의 이미지

이런 건 같은 시스템이라도 컴파일러 버전이나 컴파일 옵션에 따라 달라지기 때문에 직접 해보지 않고서는 알 수 없습니다.

그리고 해봐서 "아 이게 더 빠르구나"라고 최적화를 한다 해도, 어차피 컴파일러 버전이 바뀌면 언제 바뀔지 모르기 때문에 큰 의미가 없습니다.

gilgil의 이미지

(A)

	if( !valueName || !value || !mIsOpened)
	{
		return FALSE;
	}

위에서도 열거가 되었듯이 에 의해서 첫번째 조건이 만족하면 2번째와 3번째의 evaluation은 의미가 없기 때문에 그냥 statement를 수행하게 됩니다.
short-circuit evaluation 기능은 컴파일러 optimization의 얘기가 아니라 원래 그렇게 작동하도록 되어 있습니다(컴파일러 전통적인 기능임).
따라서 디버깅 모드에서도 short-circuit evaluation이 적용되게 됩니다.

(B)

	if( !valueName)
	{
		return FALSE; // 첫번째 처리 루틴(가)
	}
 
        if( !value)
        {
                return FALSE; // 두번째 처리 루틴(나)
        }
 
	if( !mIsOpened )
	{
		return FALSE; // 세번째 처리 루틴(다)
	}

(가), (나), (다) 코드가 다르다고 한다면 참 거짓을 연속적으로 판단하는 분기가 이루어 지겠지만,
컴파일러의 최적화에 의해서 (가)(나)(다)가 전부 같은 코드라고 컴파일러가 판단을 해서
컴파일 최적화에 의해서 (B)는 (A)와 동일하게 작동하지 않을까 생각을 해 봅니다.
다만, 이것은 컴파일러마다 다를 수 있으므로 직접 해 보는 수밖에 없다고 봅니다.

kid1402의 이미지

많은 분들이 다양한 의견을 내 주셨네요.
생각의 정리가 된 것 같습니다. 감사합니다

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.