간단한 함수의 측정 시간을 측정하는데 실행 시간이 0ms로 나옵니다;;
글쓴이: awidesky / 작성시간: 수, 2021/07/21 - 2:34오후
#include <cmath> #include <iostream> #include <chrono> float fsqrt_(float f) { int i = *(int *)&f; i = (i >> 1) + 0x1fbb67ae; float f1 = *(float *)&i; return 0.5F * (f1 + f / f1); } void my_test() { auto start = std::chrono::high_resolution_clock::now(); float max = 0.0F; for (int i = 0x00800000 ; i < 0x7f800000 ; i++) { float f = *(float*) &i; float re = fsqrt_(f); if(max < re) max = re; } auto end1 = std::chrono::high_resolution_clock::now(); auto diff = end1 - start; std::cout << "mysqrt : " << std::chrono::duration <double, std::milli> (diff).count() << " ms" << std::endl; } void lib_test() { auto start = std::chrono::high_resolution_clock::now(); float max = 0.0F; for (int i = 0x00800000 ; i < 0x7f800000 ; i++) { float f = *(float*) &i; float re = sqrtf(f); if(max < re) max = re; } auto end1 = std::chrono::high_resolution_clock::now(); auto diff = end1 - start; std::cout << "stdlib : " << std::chrono::duration <double, std::milli> (diff).count() << " ms" << std::endl; } int main() { std::cout << "warmup" << std::endl; for(int i = 0 ; i < 3 ; i++) { my_test(); lib_test(); } std::cout << "\ntest\n" << std::endl; for(int i = 0 ; i < 5 ; i++) { my_test(); lib_test(); } }
게임 퀘이크 3의 fast invsqrt 함수에서 영감을 받아 만든 sqrt함수의 실행시간을 측정해보려 합니다. 컴파일 및 실행 명령은 다음과 같습니다.
g++ --version g++ speed_test.cpp -O3 -o speed_test.exe speed_test.exe
측정 방법은 제가 만든 fsqrt_()와 cmath의 sqrtf 모두 동일한데, 이상하게 출력이 이렇게 나옵니다.
D:\development\gitRepos\MyPapers\fsqrt\code>g++ --version g++ (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. D:\development\gitRepos\MyPapers\fsqrt\code>g++ speed_test.cpp -O3 -o speed_test.exe D:\development\gitRepos\MyPapers\fsqrt\code>speed_test.exe warmup mysqrt : 0 ms stdlib : 1241.64 ms mysqrt : 0 ms stdlib : 1223.3 ms mysqrt : 0 ms stdlib : 1235.76 ms test mysqrt : 0 ms stdlib : 1229.85 ms mysqrt : 0 ms stdlib : 1240.04 ms mysqrt : 0 ms stdlib : 1235.71 ms mysqrt : 0 ms stdlib : 1266.09 ms mysqrt : 0 ms stdlib : 1247.12 ms D:\development\gitRepos\MyPapers\fsqrt\code>pause 계속하려면 아무 키나 누르십시오 . . .
제가 알지 못하는 사이에 최적화가 일어나기라도 한 건지;;; 반복 횟수를 늘려봐도 동일하게 나옵니다..
Forums:
혹시 최적화로 반복이나 함수 호출문이 없어졌나 해서 objdump로 덤프 해봤는데 그렇지는 않은 것 같습니다..
이진 코드는 잘 모르겠으나, 최적화에 의해서 루프가
이진 코드는 잘 모르겠으나, 최적화에 의해서 루프가 무시되는 것 같습니다.
cout 라인에 max 를 출력하도록 하면 시간이 정상적으로 나오네요.
감사합니다!
그런데 혹시 제가 만든 함수만 반복이 무시되는 이유를 알 수 있을까요?
함수 iteration 순서를 바꾸어도 똑같은 문제가 생기네요;;
라이브러리의 함수는 이미 컴파일되어 있기 때문에 코드가 있는 제 함수만 루프 최적화의 대상이 되는 것인가요?
전공자가 아니라 모르겠으나, 눈에 보이는 차이는,
전공자가 아니라 모르겠으나, 눈에 보이는 차이는,
직접 만든 함수의 경우 모든 코드를 컴파일러가 볼 수 있으니 side effect가 없다고 판단해서
루프를 무시하는 것이 아닐까요?
라이브러리의 함수는 함수 내용을 컴파일러가 모르니, side effecect가 있을 수 있으니,
루프를 돌아야하고요.
최적화 옵션을 왜 넣으셨나요
빌드할 때 -O3 옵션을 빼면 원하시는대로 출력이 되네요
컴파일러 최적화를 끄면 0 아닌 값이 나올 수는
컴파일러 최적화를 끄면 0 아닌 값이 나올 수는 있겠으나...
그렇게 해서 측정된 값이 내가 원래 측정하려던 값이 맞는지는 또 다른 문제이지요.
-O3 최적화는 코드 내용을 바꿔버리는 최적화인데요?
O3를 통해 실행한 코드가 내가 적은 코드가 아닌데
이런 코드 실행 시간을 측정하는 목적에서는 빼는게 맞죠
모든 최적화가 코드 내용을 바꾸는 최적화이죠.
모든 최적화가 코드 내용을 바꾸는 최적화이죠.
요점은 내가 의도한 프로그램의 동작을 유지하는 선에서 코드를 바꿔야 한다는 것인데...
-ffast-math처럼 명시적으로 프로그램의 동작을 바꿀 수 있는 옵션이 아니더라도, C/C++ 언어 표준은 교묘한 부분들이 좀 있어서 설령 적법한 최적화라 해도 내가 의도했던 동작이 최적화 과정에서 보존이 될지 확신하기 까다로운 경우들이 많지요.
-ffast-math는 -O3에서 켜지는 최적화는 아니긴 합니다만, 뭐 아무튼.
======
뭐 그런 의미에서 -O3의 사용은 좀 controversial 할 수 있어요. 비판하는 사람들은 -O2 대비 더 좋다는 보장도 없는데다가 위험천만하다고 그러더군요.
근데 그렇다고 -O3 빼고 돌리면 디폴트로 -O0이 들어갈 텐데, 그건 좀 아니지 않을까요.
아마 -O3 최적화가 해당 코드 자체가 필요없다고 빼
아마 -O3 최적화가 해당 코드 자체가 필요없다고 빼 버리는 것 같은데 my_test() 내에서 끝에 max, re 값 등을 출력해 보면 바뀌어 질 것 같네요. 변수 자체에 volatile을 쓰면 그 쪽 자체에 최적화가 빠지게 되니까 그건 참고하시고요.
댓글 달기