- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个实时视频流管道,可以将 RGB32 帧编码为 H.264。我的目标是 NVIDIA 硬件,因此我计划使用 CUDA 来执行从 RGB32 到 NV12 的色彩空间转换。我查找了执行类似任务的内核的示例,一切似乎都很好。然而,由于很多人提到数据传输速度是 CPU 到 GPU 通信的最关键点,我想知道是否有人有过将 RGB32 数据馈送到 CUDA 内核的更好方法的经验:
cudaMemcpy()
(至少 this 主题指出 cudaMemcpy()
的性能优于操作系统图形堆栈Map()
从用户空间代码更新的动态 Direct3D11 资源如果有人有这方面的经验,那么我很高兴听到它,否则 - 基准测试是:)
最佳答案
由于我没有擅自进行基准测试,因此我将把所有内容留在这里,以便任何人都可以使用它们或对改进发表评论。
我比较了 1000 次迭代的时间:
映射
/memcpy
到动态Direct3D 11纹理上的映射内存/取消映射
- 每次调用3毫秒Map
/Unmap
(以了解 Map/Unmap 的开销) - 每次调用 1.4 毫秒UpdateSubresource
(根据我的阅读,如果每帧有多个更新,这应该比动态表面慢) - 每次调用 2.13 毫秒cudaMemcpy
在每次迭代中从用 new
分配的临时指针到 cudaMalloc
分配的设备内存指针 - 每次调用 1.3ms cudaMemcpyAsync
从使用 new
分配的临时指针到每次迭代中分配的 cudaMalloc
设备内存指针以及 cudaDeviceSynchronize
> 最后一次迭代后 - 每次调用 1.25 毫秒cudaMemcpyAsync
在每次迭代中从 cudaMalloc
分配的主机内存指针指向 cudaMalloc
分配的设备内存指针以及 cudaDeviceSynchronize
最后一次迭代后 - 每次调用 0.250 毫秒基本上,我似乎应该坚持使用 Cuda,因为它比使用 Direct3D 11 表面将数据从系统内存传输到 GPU 内存更快。
此外,在 Map 更新非常频繁的情况下,
/Map
/Unmap
方法似乎胜过了默认表面和 UpdateSubresource
Unmap
本身很少被调用。
我将在下面发布基准代码(它也可以在 GitHub 上找到) - 我将非常高兴获得任何反馈,因为基准可能存在问题,这可能会影响结果,因为我是新手Direct3D 11 和 Cuda。
// STL
#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
// ATL
#include <atlbase.h>
// CUDA
#include "cuda.h"
#include "cuda_runtime_api.h"
#pragma comment(lib, "cudart.lib")
// DXGI
#include <dxgi.h>
#pragma comment(lib, "dxgi.lib")
// D3D11
#include <d3d11.h>
#pragma comment(lib, "d3d11.lib")
int main(int argc, char** argv)
{
std::string sDeviceName("GeForce GTX 750 Ti");
std::wstring sDeviceNameWide(sDeviceName.begin(), sDeviceName.end());
const size_t nWidth = 1920, nHeight = 1080, nIterations = 1000;
#pragma region Direct3D 11
CComPtr<IDXGIFactory1> pDXGIFactory1;
ATLENSURE_SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&pDXGIFactory1)));
ULONG nAdapterIndex = 0;
CComPtr<IDXGIAdapter1> pDXGIAdapter1;
DXGI_ADAPTER_DESC1 DXGIAdapterDescription1 = {};
bool bD3D11AdapterFound = false;
while (SUCCEEDED(pDXGIFactory1->EnumAdapters1(nAdapterIndex++, &pDXGIAdapter1)))
{
ATLENSURE_SUCCEEDED(pDXGIAdapter1->GetDesc1(&DXGIAdapterDescription1));
std::wstring sDescription(DXGIAdapterDescription1.Description);
if (sDescription.find(sDeviceNameWide) != std::string::npos)
{
bD3D11AdapterFound = true;
break;
}
}
if (bD3D11AdapterFound == false)
{
std::cout << "Direct3D 11 compatbile adapter named " << sDeviceName.c_str() << "was not found!" << std::endl;
return EXIT_FAILURE;
}
const D3D_FEATURE_LEVEL RequestedFeatureLevels = D3D_FEATURE_LEVEL_11_0;
D3D_FEATURE_LEVEL FeatureLevel;
UINT nFlags = 0;
#ifdef _DEBUG
nFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
CComPtr<ID3D11Device> pDevice;
CComPtr<ID3D11DeviceContext> pDeviceContext;
ATLENSURE_SUCCEEDED(D3D11CreateDevice(pDXGIAdapter1, D3D_DRIVER_TYPE_UNKNOWN, NULL, nFlags, &RequestedFeatureLevels, 1, D3D11_SDK_VERSION, &pDevice, &FeatureLevel, &pDeviceContext));
std::unique_ptr<unsigned char[]> pFrame(new unsigned char[nWidth * nHeight * 3 / 2]);
D3D11_TEXTURE2D_DESC TextureDescription = {};
TextureDescription.Width = nWidth;
TextureDescription.Height = nHeight;
TextureDescription.Format = DXGI_FORMAT_NV12;
TextureDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
TextureDescription.Usage = D3D11_USAGE_DYNAMIC;
TextureDescription.MipLevels = 1;
TextureDescription.ArraySize = 1;
TextureDescription.SampleDesc.Count = 1;
TextureDescription.BindFlags = D3D11_BIND_DECODER;
CComPtr<ID3D11Texture2D> pTexture;
ATLENSURE_SUCCEEDED(pDevice->CreateTexture2D(&TextureDescription, NULL, &pTexture));
CComQIPtr<ID3D11Resource> pResource(pTexture);
D3D11_MAPPED_SUBRESOURCE MappedSubresource = {};
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
ATLENSURE_SUCCEEDED(pDeviceContext->Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSubresource));
_ASSERT(nWidth == MappedSubresource.RowPitch);
{
memcpy(MappedSubresource.pData, pFrame.get(), nWidth * nHeight * 3 / 2);
}
pDeviceContext->Unmap(pResource, 0);
}
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "Map/memcpy/Unmap total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
ATLENSURE_SUCCEEDED(pDeviceContext->Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSubresource));
pDeviceContext->Unmap(pResource, 0);
}
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "Map/Unmap total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
TextureDescription.Usage = D3D11_USAGE_DEFAULT;
TextureDescription.CPUAccessFlags = 0;
pTexture.Release();
ATLENSURE_SUCCEEDED(pDevice->CreateTexture2D(&TextureDescription, NULL, &pTexture));
pResource = pTexture;
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
pDeviceContext->UpdateSubresource(pResource, 0, NULL, pFrame.get(), 1920, 0);
}
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "UpdateSubresource total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
#pragma endregion
#pragma region Cuda
int nCudaDeviceCount = 0;
auto nCudaError = cudaGetDeviceCount(&nCudaDeviceCount);
_ASSERT(nCudaError == CUDA_SUCCESS);
std::vector<cudaDeviceProp> Devices;
Devices.resize(nCudaDeviceCount);
bool bCudaDeviceFound = false;
int nCudaDevice = 0;
for (; nCudaDevice < nCudaDeviceCount; ++nCudaDevice)
{
nCudaError = cudaGetDeviceProperties(&Devices[nCudaDevice], nCudaDevice);
_ASSERT(nCudaError == CUDA_SUCCESS);
if (Devices[nCudaDevice].name == sDeviceName)
{
bCudaDeviceFound = true;
break;
}
}
if (bCudaDeviceFound == false)
{
std::cout << "Cuda compatbile adapter named " << sDeviceName.c_str() << "was not found!" << std::endl;
return EXIT_FAILURE;
}
nCudaError = cudaSetDevice(nCudaDevice);
_ASSERT(nCudaError == CUDA_SUCCESS);
void *pHostMemory = NULL, *pDeviceMemory = NULL;
nCudaError = cudaMalloc(&pDeviceMemory, nWidth * nHeight * 3 / 2);
_ASSERT(nCudaError == CUDA_SUCCESS);
nCudaError = cudaMallocHost(&pHostMemory, nWidth * nHeight * 3 / 2);
_ASSERT(nCudaError == CUDA_SUCCESS);
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
nCudaError = cudaMemcpy(pDeviceMemory, pFrame.get(), nWidth * nHeight * 3 / 2, cudaMemcpyHostToDevice);
_ASSERT(nCudaError == CUDA_SUCCESS);
}
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "cudaMemcpy total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
nCudaError = cudaMemcpyAsync(pDeviceMemory, pFrame.get(), nWidth * nHeight * 3 / 2, cudaMemcpyHostToDevice);
_ASSERT(nCudaError == CUDA_SUCCESS);
}
cudaDeviceSynchronize();
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "cudaMemcpyAsync total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
{
FILETIME StartFileTime = {};
::GetSystemTimeAsFileTime(&StartFileTime);
for (size_t nIteration = 0; nIteration < nIterations; ++nIteration)
{
nCudaError = cudaMemcpyAsync(pDeviceMemory, pHostMemory, nWidth * nHeight * 3 / 2, cudaMemcpyHostToDevice);
_ASSERT(nCudaError == CUDA_SUCCESS);
}
cudaDeviceSynchronize();
FILETIME EndFileTime = {};
::GetSystemTimeAsFileTime(&EndFileTime);
ULARGE_INTEGER StartTime = { StartFileTime.dwLowDateTime, StartFileTime.dwHighDateTime }, EndTime = { EndFileTime.dwLowDateTime, EndFileTime.dwHighDateTime };
double fElapsedMiliseconds = static_cast<double>((EndTime.QuadPart - StartTime.QuadPart) / 10000.0f);
std::cout << "cudaMemcpyAsync with cudaMalloc'ed input memory total time: " << fElapsedMiliseconds << " ms, " << fElapsedMiliseconds / nIterations << " per call" << std::endl;
}
cudaFree(pDeviceMemory);
cudaFree(pHostMemory);
#pragma endregion
return EXIT_SUCCESS;
}
关于cuda - CPU 到 GPU 内存传输 - cudaMemcpy() 与使用 Map() 的 Direct3D 动态资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27590055/
下面是一小段代码,将数组中的 4 个元素复制到 GPU。我真的不明白为什么 cudaMemcpy 在这种情况下会抛出错误。请帮忙 int size = 5; float *a = (float*)ma
我对我看到的关于阻塞和 cudaMemcpy 的一些评论感到困惑。我的理解是 Fermi HW 可以同时执行内核和执行 cudaMemcpy。 我读到 Lib func cudaMemcpy() 是一
我的程序运行 2 个线程 - 线程 A(用于输入)和 B(用于处理)。我还有一对指向 2 个缓冲区的指针,这样当线程 A 完成将数据复制到缓冲区 1 时,线程 B 开始处理缓冲区 1,线程 A 开始将
之间有什么区别 cudaMemcpy and cudaMemset?? 如何将int值从主机复制到设备? 这是我正在使用的代码 int addXdir = 1; int devAddXdir; cu
我用 cudaMemcpy()一次将 1GB 的数据精确复制到设备。这需要 5.9 秒。反之则需要 5.1 秒。这是正常的吗?函数本身在复制之前有这么多开销吗? 理论上,PCIe 总线的吞吐量至少应为
在这种情况下,cudaMemcpy 函数将如何工作? 我已经声明了一个这样的矩阵 float imagen[par->N][par->M]; 我想将它复制到 cuda 设备,所以我这样做了 float
我正在尝试将无符号整数数组(在 msgs 中)复制到 GPU 上以对其进行处理,但以下代码不会复制任何内容。我在 cudaMemcpy 调用周围添加了一些 cuda 错误检查代码,并且得到以下信息:无
我根据本教程创建了一个简单但完整的程序:http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#device-memory #i
我正在调用 cudaMemcpy 并且副本成功返回,但是源值没有被复制到目标。我使用 memcpy() 写了一篇类似的文章,效果很好。我在这里缺少什么? // host externs extern
我很好奇,当我们从主机复制到设备时,cudaMemcpy 是在 CPU 还是 GPU 上执行的? 换句话说,它是复制一个顺序过程还是并行完成? 让我解释一下我为什么这么问:我有一个包含 500 万个元
cudaMemcpy(dst, src, filesize, cudaMemcpyDeviceToHost); 其中filesize是存储在设备全局内存中的变量。 最佳答案 简单的答案是否定的。 参数
我试图找出为什么 cudaMemcpyFromSymbol() 存在。似乎“symbol” func 可以做的所有事情,nonSymbol cmd 也可以做。 symbol 函数似乎可以轻松移动数组或
我刚刚开始学习如何使用 CUDA。我正在尝试运行一些简单的示例代码: float *ah, *bh, *ad, *bd; ah = (float *)malloc(sizeof(float)*4);
cudaMemcpy(dst, src, filesize, cudaMemcpyDeviceToHost); 其中 filesize 是存储在设备全局内存中的变量。 最佳答案 简单的回答是否定的。
这个错误困扰了我很长一段时间,所以我决定将其发布在这里。 调用 cudaMemcpy 时发生此段错误: CurrentGrid->cdata[i] = new float[size]; cudaMem
这个错误困扰了我很长一段时间,所以我决定将其发布在这里。 调用 cudaMemcpy 时发生此段错误: CurrentGrid->cdata[i] = new float[size]; cudaMem
这个错误困扰了我很长一段时间,所以我决定将其发布在这里。 调用 cudaMemcpy 时发生此段错误: CurrentGrid->cdata[i] = new float[size]; cudaMem
我无法追踪 cudaMemcpy 调用的无效参数的来源,以下是相关代码: 在 gpu_memory.cu 中,我为设备指针声明并分配内存: #define cudaErrorCheck(ans) {
我有一个带指针的数据结构(想想链表)。在启动读取输入数据的内核之前无法确定其大小。所以我在输入处理期间在设备上分配数据。 但是,尝试将该数据复制回主机失败。据我所知,这是因为 CUDA 中存在限制,不
在下面的代码中,cudaMemcpy 不工作,它返回一个错误,然后程序退出。可能是什么问题?在我看来我没有做违法的事情, vector 的大小对我来说似乎没问题。 算法可能在某些时候做错了,但我想这个
我是一名优秀的程序员,十分优秀!