DXGI_ERROR_DEVICE_HUNG в результате метода C++AMP

Я пытаюсь реализовать функцию, которая вычисляет веса и абсциссы для метода численного интегрирования Гаусса-Лагерра с использованием C++AMP для распараллеливания процесса, и при его запуске я получаю ошибку DXGI_ERROR_DEVICE_HUNG.

Это мой вспомогательный метод для вычисления логарифма гамма-функции на графическом процессоре:

template <typename T>
T gammaln_fast( T tArg ) restrict( amp )
{
    const T tCoefficients[] = { T( 57.1562356658629235f ), T( -59.5979603554754912f ),
        T( 14.1360979747417471f ), T( -0.491913816097620199f ), T( 0.339946499848118887E-4f ),
        T( 0.465236289270485756E-4f ), T( -0.983744753048795646E-4f ), T( 0.158088703224912494E-3f ),
        T( -0.210264441724104883E-3f ), T( 0.217439618115212643E-3f ), T( -0.164318106536763890E-3f ),
        T( 0.844182239838527433E-4f ), T( -0.261908384015814087E-4f ), T( 0.386991826595316234E-5f ) };

    T y = tArg, tTemp = tArg + T( 5.2421875f );
    tTemp = (tArg + T( 0.5f )) * concurrency::fast_math::log( tTemp ) - tTemp;

    T tSer = T( 0.999999999999997092f );

    for( std::size_t s = 0; s < (sizeof( tCoefficients ) / sizeof( T )); ++s )
    {
        tSer += tCoefficients[s] / ++y;
    }

    return tTemp + concurrency::fast_math::log( T( 2.5066282746310005f ) * tSer / tArg );
}

А вот моя функция, которая вычисляет веса и абсциссы:

template <typename T>
ArrayPair<T> CalculateGaussLaguerreWeights_fast( const T tExponent, const std::size_t sNumPoints, T tEps = std::numeric_limits<T>::epsilon() )
{
    static_assert(std::is_floating_point<T>::value, "You can only instantiate this function with a floating point data type");
    static_assert(!std::is_same<T, long double>::value, "You can not instantiate this function with long double type"); // The long double type is not currently supported by C++AMP

    T tCurrentGuess, tFatherGuess, tGrandFatherGuess;
    std::vector<T> vecInitialGuesses( sNumPoints );
    for( std::size_t s = 0; s < sNumPoints; ++s )
    {
        if( s == 0 )
        {
            tCurrentGuess = (T( 1.0f ) + tExponent) * (T( 3.0f ) + T( 0.92f ) * tExponent) / (T( 1.0f ) + T( 2.4f ) * sNumPoints + T( 1.8f ) * tExponent);
        }
        else if( s == 1 )
        {
            tFatherGuess = tCurrentGuess;
            tCurrentGuess += (T( 15.0f ) + T( 6.25f ) * tExponent) / (T( 1.0f ) + T( 0.9f ) * tExponent + T( 2.5f ) * sNumPoints);
        }
        else
        {
            tGrandFatherGuess = tFatherGuess;
            tFatherGuess = tCurrentGuess;
            std::size_t sDec = s - 1U;
            tCurrentGuess += ((T( 1.0f ) + T( 2.55f ) * sDec) / (T( 1.9f ) * sDec) + T( 1.26f ) * sDec * tExponent
                / (T( 1.0f ) + T( 3.5f ) * sDec)) * (tCurrentGuess - tGrandFatherGuess) / (T( 1.0f ) + T( 0.3f ) * tExponent);
        }
        vecInitialGuesses[s] = tCurrentGuess;
    }

    concurrency::array<T> arrWeights( sNumPoints ), arrAbsciasses( sNumPoints, std::begin(vecInitialGuesses) );

    try {
        concurrency::parallel_for_each( arrAbsciasses.extent, [=, &arrAbsciasses, &arrWeights]( concurrency::index<1> index ) restrict( amp ) {
            T tVal = arrAbsciasses[index], tIntermediate;
            T tPolynomial1 = T( 1.0f ), tPolynomial2 = T( 0.0f ), tPolynomial3, tDerivative;
            std::size_t sIterationNum = 0;
            do {
                tPolynomial1 = T( 1.0f ), tPolynomial2 = T( 0.0f );

                for( std::size_t s = 0; s < sNumPoints; ++s )
                {
                    tPolynomial3 = tPolynomial2;
                    tPolynomial2 = tPolynomial1;
                    tPolynomial1 = ((2 * s + 1 + tExponent - tVal) * tPolynomial2 - (s + tExponent) * tPolynomial3) / (s + 1);
                }

                tDerivative = (sNumPoints * tPolynomial1 - (sNumPoints + tExponent) * tPolynomial2) / tVal;
                tIntermediate = tVal;
                tVal = tIntermediate - tPolynomial1 / tDerivative;
                ++sIterationNum;

            } while( concurrency::fast_math::fabs( tVal - tIntermediate ) > tEps || sIterationNum < 10 );

            arrAbsciasses[index] = tVal;
            arrWeights[index] = -concurrency::fast_math::exp( gammaln_fast( tExponent + sNumPoints ) - gammaln_fast( T( sNumPoints ) ) ) / (tDerivative * sNumPoints * tPolynomial2);
        } );
    }
    catch( concurrency::runtime_exception& e )
    {
        std::cerr << "Runtime error, code: " << e.get_error_code() << "; message: " << e.what() << std::endl;
    }

    return std::make_pair( std::move( arrAbsciasses ), std::move( arrWeights ) );
}

А вот полная трассировка из консоли отладки:

D3D11: Удаление устройства. ОШИБКА D3D11: ID3D11Device::RemoveDevice: Удаление устройства было инициировано по следующей причине (DXGI_ERROR_DEVICE_HUNG: Устройству потребовалось неоправданное количество времени для выполнения своих команд, или произошло сбой/зависание оборудования. В результате TDR (обнаружение тайм-аута и Recovery) был запущен. Текущий контекст устройства выполнял команды, когда произошло зависание. Приложение может захотеть перезапуститься и вернуться к менее агрессивному использованию аппаратного обеспечения дисплея). [ОШИБКА ВЫПОЛНЕНИЯ № 378: DEVICE_REMOVAL_PROCESS_AT_FAULT] ОШИБКА D3D11: ID3D11DeviceContext::Map: Возврат DXGI_ERROR_DEVICE_REMOVED, когда ресурс пытался сопоставить с READ или READWRITE. [ОШИБКА RESOURCE_MANIPULATION № 2097214: RESOURCE_MAP_DEVICEREMOVED_RETURN]

Приношу свои извинения за то, что не смог привести небольшой воспроизводимый пример; Я надеюсь, что это все еще приемлемый вопрос, так как я не могу решить его самостоятельно.


person Thomas Russell    schedule 19.08.2014    source источник


Ответы (1)


При использовании DirectCompute основная проблема заключается в написании вычислений, которые не превышают тайм-аут автоматического обнаружения «зависания графического процессора» Direct3D. По умолчанию система предполагает, что если шейдер занимает больше нескольких секунд, GPU фактически завис. Эта эвристика работает для визуальных шейдеров, но вы можете легко создать шейдер DirectCompute, выполнение которого занимает много времени.

Решение состоит в том, чтобы отключить обнаружение тайм-аута. Это можно сделать, создав устройство Direct3D 11 с помощью D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT См. Отключение TDR в Windows 8 для алгоритмов C++ AMP в блоге. Главное помнить, что для D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT требуется среда выполнения DirectX 11.1 или более поздней версии, которая включена в Windows 8.x и может быть установлена ​​в Windows 7 с пакетом обновления 1 с помощью KB2670838. См. DirectX 11.1. и Windows 7, Обновление DirectX 11.1 и Windows 7 и MSDN для некоторых предупреждений об использовании KB2670838.

person Chuck Walbourn    schedule 19.08.2014