Разница во времени между сборками Release и Debug - PullRequest
2 голосов
/ 25 октября 2011

Моя программа должна вызывать событие каждые 180 секунд.

mFoodSpawnTime += dt;
if (mFoodSpawnTime > mFoodSpawnCycleLength)
{
       ..... etc;
}

mFoodSpawnCycleLength = 180.0f, а mFoodSpawnTime - это другое число с плавающей запятой, которое накапливает время в каждом цикле.

Моя проблема в том, что если mFoodSpawnCycleLength составляет около 180.0f, то при сборке релиза он, кажется, никогда не прибывает, и mFoodSpawnTime занимает более 10 минут, чем mFoodSpawnCycleLength! Я рассчитал отладочную сборку, и она выполняет цикл через 180 секунд, и я проверил с помощью секундомера. Вернемся к сборке релиза: пока mFoodSpawnCycleLength не приближается к 180.0f, он также совпадает с секундомером и выполняет код. Однажды я установил его на 120.0f, и когда он запустил секундомер, прочитал 2 минуты 30 секунд. Нет кода #ifdef DEBUG, который может быть причиной этого. Итак, я говорю следующее: чем ближе к значению mFoodSpawnCycleLength 180.0f, тем менее точным становится время, но только при выпуске сборки!

Я только что распечатал mFoodSpawnTime, и когда мои часы показывали 3 минуты, их время составляло всего около 160 секунд, и я обнаружил, что, когда таймер приближается к 150 секундам, увеличение времени просто замедляется до полной остановки. Я отслеживал dt в каждом цикле, и, похоже, он ничем не отличается от того, что было в начале.

Может ли все это быть вызвано навязчивой оптимизацией компилятора? 32-битная ошибка с плавающей точкой? Я буду продолжать изучать это, но любая помощь приветствуется.

Я все еще учусь, поэтому использую книгу DirectX. Я использую временной код из демонстрации, которую предоставила книга:

int D3DApp::run()
{
MSG  msg;
msg.message = WM_NULL;

__int64 cntsPerSec = 0;
QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec);
float secsPerCnt = 1.0f / (float)cntsPerSec;

__int64 prevTimeStamp = 0;
QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp);

while(msg.message != WM_QUIT)
{
    // If there are Window messages then process them.
    if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    // Otherwise, do animation/game stuff.
    else
    {   

        if( mTimeReset )
        {
            QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp);
            mTimeReset = false;
        }

        if( !isDeviceLost() )
        {
            static float frameLimit = 0.0f;
            __int64 currTimeStamp = 0;
            QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp);
            float dt = (currTimeStamp - prevTimeStamp)*secsPerCnt;

            if (dt > 2.0f) dt = 0.0f;

            frameLimit +=dt;

            updateScene(dt);
            if (frameLimit > 0.0167f)
            {
                drawScene();
                frameLimit = 0.0f;
            }

            // Prepare for next iteration: The current time stamp 
            // the previous time stamp for the next iteration.
            prevTimeStamp = currTimeStamp;
                    }
         }
    }
return (int)msg.wParam;
}

1 Ответ

5 голосов
/ 26 октября 2011

Возможно, вы захотите использовать здесь double, а не float. Разница в производительности в этом случае будет минимальной, и я подозреваю, что вы можете столкнуться с проблемой, когда вы добавляете очень маленькое число к большому числу - оставляя значение с плавающей запятой большого числа неизменным.

Плавающие дают вам только шесть цифр точности. Если период счетчика производительности имеет порядок ns, вы начнете сталкиваться с проблемами, когда frameLimit достигает нескольких мс.

Режим отладки будет работать медленнее, что приведет к большим приращениям, поэтому, возможно, вы не видите проблемы там.

...