2014-10-29 4 views
2

매우 일반적입니다 c++ 질문입니다. (그들은 같은 일을)은 다음 두 블록을 고려 :임시 변수가 포함 된 한 줄짜리 줄을 여러 줄로 나눠서 성능에 영향을 줄 수 있습니까?

v_od=((x-wOut*svd.matrixV().topLeftCorner(p,Q).adjoint()).cwiseAbs2().rowwise().sum()).array().sqrt(); 

MatrixXd wtemp=(x-wOut*svd.matrixV().topLeftCorner(p,Q).adjoint()); 
v_od=(wtemp.cwiseAbs2().rowwise().sum()).array().sqrt(); 

지금 첫 번째 구조 보다 효율적으로 느낀다. 그러나 사실, 또는 C++ 컴파일러 같은 것들을 컴파일 할 것이라고 (나는 컴파일러가 좋은 가정하고 모든 안전한 최적화 플래그가 설정되어 있습니다.) 인수에 대한 wtemp 가벼운 크기, 매트릭스 모든 100k 요소와 함께)?

나는 이것에 대한 일반적인 답은 '벤치마킹이며 다시 우리에게 와야한다'는 것을 알고있다. 하지만 나는 일반적인 대답을 원한다.

+1

"하지만 일반적인 답을 원합니다." 이 질문에 대한 일반적인 대답이 '벤치마킹 및 다시 돌아 오는 것'인 이유는 무엇입니까? – Borgleader

+0

나는 모든 관행을 벤치마킹 할 필요가 없다는 점을 채택 할 실천 지침을 찾고 있습니다. .. – user189035

+1

제목을 편집했습니다. 괜찮습니다. 나는 지금 그것이 훨씬 더 좋게 들리고 당신이 의미하는 바를 정확히 묻는 것 같아요. 동의하지 않으면 다시 편집 해주십시오. – quetzalcoatl

답변

3

두 번째 표현식이 귀하의 첫 번째 표현식보다 근본적으로 덜 효율적일 수있는 두 가지 경우가 있습니다.

첫 번째 경우는 MatrixXd 클래스의 작성자가 cwiseAbs2()에이 오버로드에 대한 값을 참조한 경우입니다. 첫 번째 코드에서 메서드를 호출하는 값은 임시이며, 두 번째 코드에서는 이 아니며이 아닙니다.우리는 단순히 두 번째 표현을 변경하여이 문제를 해결할 수 있습니다

를 rvalue 참조로 wtemp 캐스트, 그리고 기본적으로 행렬이 스크래치 공간으로 재사용 할 수 있습니다에 호출되는 cwiseAbs2() 알려줍니다
v_od=(std::move(wtemp).cwiseAbs2().rowwise().sum()).array().sqrt(); 

.MatrixXd 클래스의 작성자가이 특정 기능을 구현 한 경우에만 이 중요합니다.

두 번째 가능한 방법은 근본적으로 느릴 수 있습니다. MatrixXd 클래스의 작성자는 나열된 모든 작업에 대해 표현 템플릿을 사용하는 것입니다. 이 기술은 작업의 구문 분석 트리를 작성하고 결과를 끝에 값으로 할당 할 때만 모든 작업을 마무리합니다.

어떤 식 템플릿 같이 중간 객체에 저장 될 수있는 처리 기록 :

auto&& wtemp=(x-wOut*svd.matrixV().topLeftCorner(p,Q).adjoint()); 
v_od=(std::move(wtemp).cwiseAbs2().rowwise().sum()).array().sqrt(); 

여기서 제 저장 발현 템플릿 wtemp 아닌 행렬로 평가하고, 두 번째 행 첫 번째 중간 결과를 소비합니다. 위와 같은 것을하려고하면 다른 표현식 템플릿 구현이 무섭게 깨집니다.

표식 템플릿은 매트릭스 클래스 작성자가 특별히 구현해야하는 것입니다. 또한 다소 모호한 기술입니다. 버퍼를 확장하는 것이 문자열 추가와 같이 겉으로보기에는 값싼 작업으로 수행되는 상황에서 주로 사용됩니다.

이러한 두 가지 경우를 제외하면 성능의 차이는 완전히 "노이즈"가 될 것입니다. 컴파일러가 어느 정도 혼란스러워 할 것으로 예상하는 데는 선험적 인 이유가 없습니다.

그리고 둘 다 상대적으로 발전된/현대적인 기술입니다.

라이브러리 작성자가 명시 적으로 수행하지 않고 "컴파일러에서"구현하지 않습니다.

+0

시간을내어 교육적으로 설명하는 시간을 가져 주셔서 감사합니다 ... 모든 대답은 훌륭하지만이 설명은 일반적인 설명이 아닌 구체적인 설명에 의존합니다. – user189035

+0

@ user189035 ahem : "나는 일반적인 대답을 원합니다". – Baldrickk

+0

@Baldrickk : 미안하지만 나는 단어의 사용에 더욱주의를 기울여야했습니다. 내 질문에 비해 위의 내 의견에 다른 의미로 '일반'을 의미했습니다. 위의 내 의견에서 '가독성이 성과보다 중요합니다'와 같은 '일반 원칙'을 의미했습니다 ... 사실은 내 구체적인 질문을 언급하지 않는 맥심입니다.이와 대조적으로,이 답변의 요점은이 사례에서 왜 중요하지 않은지 더 정확하게 설명합니다 (예를 들어 내가 사용하고있는 도서관에서 두 경우가 맞는지 여부를 확인할 수 있습니다). – user189035

2

일반적으로 두 번째 경우가 훨씬 더 읽기 쉽기 때문에 선호됩니다. 그것은 명확하게 코드를 이해하는 데 도움이 임시 변수를 지정합니다. 게다가 디버깅하는 것이 훨씬 쉽습니다! 그래서 두 번째 옵션을 선택하는 것이 좋습니다.

나는 preformance 차이점에 대해별로 신경 쓰지 않을 것이다. 좋은 컴파일러는 두 예제 모두에서 동일한 코드를 만들 것이라고 생각한다. 가장 중요한 순서대로 코드의

+0

감사합니다 ...하지만 실적이 좋을 것이라고 기대하거나 Borgleader가 '알 방법이 없습니다. 항상 ' – user189035

+2

개인적으로 : 가독성과 유지 보수가 더 중요합니다. 일반적인 컴파일러에서는 전혀 차이가 없을 것으로 예상됩니다. 고대 또는 버그가 많은 컴파일러에서는 ** 눈에 띄는 ** 차이가 없을 것으로 기대합니다. 사용하면 히트 당 수 있습니다. 몇몇 임시 테이블은 나중에 코드에서'wtemp '를 좋아한다. 나중에 그것들을 참조 할 필요가 없도록 할 때, 때로는 여분의'{}'을 주입 할 것입니다 : int foo = 5, bar = 4; {int tmp = foo; foo = bar; bar = tmp;} zomg (foo, bar);'. 이상하게 보이지만 때로는 도움이됩니다. 그들의 범위가 많이 제한되어 있기 때문에, 그것은 거의 임시 변수와 비슷합니다. 컴파일러는 스택 공간을 재사용 할 수 있습니다. – quetzalcoatl

2

가장 중요한 측면 -> 덜 중요 :

  1. 올바른 코드
  2. 가 읽을 수있는 코드
  3. 빠른 코드 물론

,이 변경할 수 있습니다 (즉, 제한된 메모리 공간에서 성능의 모든 마지막 비트를 집어 넣어야하는 임베디드 장치에서)하지만 이는 일반적인 경우입니다.

따라서, 무시할 수있는 성능 향상 이상으로 읽기 쉬운 코드가 필요합니다.

나는 임시 저장에 대한 성능을 기대하지 않을 것입니다. 적어도 일반적인 경우는 아닙니다. 사실, 어떤 경우에는 더 빨리 나타날 수 있습니다. 즉, c_strings을 사용할 때 의 결과를 캐쉬합니다 (첫 번째 예제가 있음)

코드를 작성하고 올바른지 확인하십시오 코드 은 성능 문제를 발견 했으므로 프로파일 링에 대해 걱정할 필요가 없으며 더 빨리 수행 할 수 있어야합니다. 그러면 더 많은 유지 보수가 가능한/읽을 수있는 코드가 실제로 문제를 격리하는 데 도움이된다는 것을 알게 될 것입니다.

관련 문제