英特尔 IPP ippsFree() 崩溃

Posted

技术标签:

【中文标题】英特尔 IPP ippsFree() 崩溃【英文标题】:Intel IPP ippsFree() crashes 【发布时间】:2017-01-02 14:10:55 【问题描述】:

我尝试使用以下代码检查英特尔 IPP 调整图像大小/转换图像的速度有多快,但它最后一直在 ippsFree(pSpec) 崩溃,我不知道为什么。

#include <stdint.h>
#include <memory>
#include <Windows.h>
#include <time.h>

#include "ipp.h"

int main(...) 
    srand(time(NULL));

    int width = 640;
    int height = 480;
    int channels = 2;
    IppiResizeYUV422Spec* pSpec;
    IppiSize dstSize, srcSize;
    IppiPoint dstOffset =  0, 0 ;
    srcSize.width = width;
    srcSize.height = height;
    dstSize.width = 2 * width;
    dstSize.height = 2 * height;
    std::unique_ptr<unsigned char[]> sourceData;
    std::unique_ptr<unsigned char[]> destinationData;
    std::unique_ptr<unsigned char[]> destinationDataRGB;
    std::unique_ptr<unsigned char[]> workBuffer;

    sourceData.reset(new unsigned char[srcSize.width * srcSize.height * channels]);
    destinationData.reset(new unsigned char[dstSize.width * dstSize.height * channels]);
    destinationDataRGB.reset(new unsigned char[dstSize.width * dstSize.height * 3]);
    workBuffer.reset(new unsigned char[dstSize.width * dstSize.height * channels]);

    memset(sourceData.get(), 0, srcSize.width * srcSize.height * channels);
    memset(destinationData.get(), 0, dstSize.width * dstSize.height * channels);
    memset(workBuffer.get(), 0, dstSize.width * dstSize.height * channels);

    IppStatus error;
    int specSize = 0, initSize = 0, buffSize = 0;
    error = ippiResizeGetSize_8u(srcSize, dstSize, IppiInterpolationType::ippNearest, 0, &specSize, &initSize);

    pSpec = (IppiResizeYUV422Spec*) ippsMalloc_8u(specSize);
    error = ippiResizeYUV422NearestInit(srcSize, dstSize, pSpec);

    IppiRect srcRoi =  0, 0, srcSize.width, srcSize.height ;

    int64_t timerIPP9 = 0;
    LARGE_INTEGER start, end;
    LARGE_INTEGER tps;
    QueryPerformanceFrequency(&tps);

    for (unsigned int index = 0; index < 100; ++index) 
        for (unsigned int imageIdx = 0; imageIdx < srcSize.width * srcSize.height * channels; ++imageIdx) 
            sourceData.get()[imageIdx] = (rand() & 0xFF);
        

        QueryPerformanceCounter(&start);
        error = ippiResizeYUV422Nearest_8u_C2R(
            sourceData.get(),
            srcSize.width * channels,
            destinationData.get(),
            dstSize.width * channels,
            dstOffset,
            dstSize,
            pSpec,
            workBuffer.get());
        QueryPerformanceCounter(&end);

        timerIPP9 += end.QuadPart - start.QuadPart;

        QueryPerformanceCounter(&start);
        ippiYCbCr422ToRGB_8u_C2C3R(destinationData.get(), dstSize.width * channels, destinationDataRGB.get(), dstSize.width * 3, dstSize);
        QueryPerformanceCounter(&end);

        timerIPP9 += end.QuadPart - start.QuadPart;
        printf("Test: %d, time: %d ms\r", index, timerIPP9 * 1000 / tps.QuadPart);
    

    ippsFree(pSpec);
    printf("\n");
    printf("Time taken: %d ms\n", timerIPP9 * 1000 / tps.QuadPart);
    system("Pause");
    return 0;

我只是将随机数据输入转换器,但它应该能够处理噪声(因为它仍然是有效图像)。

【问题讨论】:

我使用的是最新的 Intel IPP 2017.1.143 你试过分配后立即释放吗?而且看起来您并没有检查错误响应。 (免责声明:我从未使用过英特尔 IPP) 我也从未使用过英特尔 IPP。问题可能是您以某种方式在pSpec 缓冲区之外写入,然后在调用ippsFree 时注意到它? 我为 pSpec 分配了大约 9000 字节,后来运行时说堆是 2444 字节,所以出了点问题,我只是不知道在哪里。 【参考方案1】:

我想我解决了这个难题......

您需要做的就是替换以下类似的代码:

error = ippiResizeGetSize_8u(srcSize, dstSize, IppiInterpolationType::ippNearest, 0, &specSize, &initSize);

用下面的一个:

error = ippiResizeYUV422GetSize(srcSize, dstSize, IppiInterpolationType::ippNearest, 0, &specSize, &initSize);

根据 IPP 文档:

说明 此函数使用最近邻插值法初始化调整大小算法的 IppiResizeYUV422Spec 结构。 计算spec结构对象的大小,调用ippiResizeYUV422GetSize函数。

见:http://hpc.ipp.ac.cn/wp-content/uploads/2015/12/documentation_2016/en/ipp/common/ipp_manual/GUID-15B51AB0-7F73-4E13-AC81-753259CE0E2C.htm

执行ippiResizeYUV422GetSize时,specSize的值等于11776。 执行ippiResizeGetSize_8u时,specSize的值等于9240。 较小的分配大小会导致堆损坏。

【讨论】:

以上是关于英特尔 IPP ippsFree() 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

结合英特尔 IPP 和 TBB

英特尔性能原语 (IPP) 运行时错误

如何为已弃用的英特尔 IPP API 找到替代 API?

如果我发布使用 IPP 库的 DLL,我是不是也应该发布 IPP DLL?

如何使用 IPP 将 8 位灰度图像转换为 NV12(有限范围)色彩空间

允许 automake 生成可选的编译规则