Высокий уровень использования 3D, вызов OpenCL/CUDA с большим буфером на настольном графическом процессореC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Высокий уровень использования 3D, вызов OpenCL/CUDA с большим буфером на настольном графическом процессоре

Сообщение Anonymous »

Недавно я начал изучать OpenCL и пытался с его помощью преобразовать видеокадр RGBA в NV12.
Я заметил, что в диспетчере задач для такой легкой задачи отображается недопустимо высокий уровень использования 3D. , но не используется Copy/Copy1/Copy2.
При попытке внесения изменений я обнаружил, что это продолжает происходить даже при пустой функции ядра.

Код: Выделить всё

#define CL_HPP_ENABLE_EXCEPTIONS
#define CL_HPP_TARGET_OPENCL_VERSION 200

#include 
#include 
#include 
#include 
#include 

int main() {
std::vector platdevlist;
std::vector platforms;
cl::Platform::get(&platforms);
for (auto& p : platforms) {
std::string platver = p.getInfo();
if (platver.find("OpenCL 2.") != std::string::npos ||
platver.find("OpenCL 3.") != std::string::npos)
{
cl::vector devices;
p.getDevices(CL_DEVICE_TYPE_ALL, &devices);

for (auto& d : devices) {
platdevlist.emplace_back(std::make_pair(p, d));
}
}
}

for(int i = 0; i < platdevlist.size(); ++i) {
fprintf(stderr, "%d: platform: %s, device: %s\n",
i,
platdevlist[i].first.getInfo().c_str(),
platdevlist[i].second.getInfo().c_str()
);
}
int selected_index;
fprintf(stderr, "select one: \n");
scanf("%d", &selected_index);

auto selected = platdevlist[selected_index];

auto ctx = cl::Context(cl::vector{ selected.second });
auto queue = cl::CommandQueue{ ctx, selected.second, cl::QueueProperties::None };

std::string sourcecode{ "kernel void empty(global char* dst, global const char* src) { }" };
auto program = cl::Program(ctx, {sourcecode});
try {
program.build("-cl-std=CL2.0");
}
catch (...) {
for (auto& pair : program.getBuildInfo()) {
fprintf(stderr, "%s", pair.second.c_str());
}

return 1;
}

auto func = cl::KernelFunctor(program, "empty");

std::vector srcbuf(2560 * 1440 * 4);
std::vector dstbuf(2560 * 1440 * 1.5);
cl::Buffer src(ctx, CL_MEM_READ_ONLY, (size_t)2560 * 1440 * 4);
cl::Buffer dst(ctx, CL_MEM_WRITE_ONLY, (size_t)2560 * 1440 * 1.5);

auto iter_count = 1;
auto begin = std::chrono::steady_clock::now();
size_t frames = 0;
for(;;) {
auto diff = std::chrono::steady_clock::now() - begin;
if (diff > std::chrono::seconds(1)) {
fprintf(stderr, "fps = %g\n", frames * 1000.0 / std::chrono::duration_cast(diff).count());
if (iter_count >= 15)
break;
begin = std::chrono::steady_clock::now();
frames = 0;
++iter_count;
}
queue.enqueueWriteBuffer(src, CL_FALSE, 0, 2560 * 1440 * 4, srcbuf.data());
func(cl::EnqueueArgs(queue, cl::NDRange(2560 / 2, 1440 / 2)), dst, src); // comment out this line and the 3D usage gone.
queue.enqueueReadBuffer(dst, CL_TRUE, 0, 2560 * 1440 * 1.5, dstbuf.data());
frames += 1;
}
return 0;
}
Моя среда — 64-разрядная версия Windows 10 с настольным компьютером RTX 2060; он использует 90% 3D. При этом он использует гораздо меньше (52%) iGPU Intel UHD 630 (i7-10700).
[img]https:// i.sstatic.net/e8HC3DPv.png[/img]
Изображение

Это также произошло с настольной видеокартой RTX 2080 или настольной видеокартой Vega64.

Но этого не произошло с ноутбуком RTX 2080 или ноутбуком RTX 4090.
< blockquote>
edit: я обнаружил, что если я настрою в BIOS прямую связь монитора ноутбука с дискретной графической платой, он будет действовать так же, как настольный компьютер.

Я проверил пример кода от Nvidia ( https://developer.nvidia.com/opencl ), и он использует ту же пару API, что и я.
Когда RTX 2060 запускает код при высокой загрузке 3D-графического процессора, энергопотребление графического процессора низкое (при использовании nvidia-smi dmon), составляет 51 Вт. при запуске Furmark 2 с таким же использованием 3D-графического процессора используется 165 Вт.
Я не знаю, как объяснить этот феномен и с чего начать оптимизацию кода.
Я не знаю, как объяснить этот феномен и с чего начать оптимизацию кода.
Я не знаю, как объяснить этот феномен и с чего начать оптимизацию кода.
p>
Угадайте:
  • Не сообщает ли счетчик производительности драйвера графической платы ложные данные в ОС, включено «3D» факт «Копия»?
  • Что-то не так с моей программной средой, которая отключила DMA для графической платы. Я совершенно уверен, что при чтении/записи жесткого диска в режиме PIO вместо DMA происходит высокая загрузка ЦП.
2024/5/26 добавляется :
Я попробовал CUDA запустить функцию ядра с тем же размером блока памяти, он копирует входные данные на выходные в функции ядра и действует точно так же, как и OpenCL. Меня это смущает, потому что это слишком медленно.
Код

Код: Выделить всё

#include 
#include 
#include 

static void HandleError( cudaError_t err,
const char *file,
int line ) {
if (err != cudaSuccess) {
printf( "%s in %s at line %d\n", cudaGetErrorString( err ),
file, line );
exit( EXIT_FAILURE );
}
}
#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))

__global__ void rgb2yuv(
int width, int height,
unsigned char* src, int srcstride,
unsigned char* ybuf, int ystride,
unsigned char* ubuf, int ustride,
unsigned char* vbuf, int vstride
) {
int xd2 = blockIdx.x;
int yd2 = blockIdx.y;
int x = xd2 * 2;
int y = yd2 * 2;

ybuf[y * ystride + x] = src[y + srcstride + x];
ybuf[y * ystride + x + 1] = src[y + srcstride + (x + 1) * 4];
ybuf[(y + 1) * ystride + x] = src[(y + 1) + srcstride + x];
ybuf[(y + 1) * ystride + x + 1] = src[(y + 1) + srcstride + (x + 1) * 4];

ubuf[yd2 * ustride + xd2] = src[y + srcstride + x + 1];
vbuf[yd2 * ustride + xd2] = src[y + srcstride + x + 2];
}

#include 
int main() {
const int width = 2560;
const int height = 1440;

auto src = (unsigned char*)malloc(width * height * 4);
memset(src, 255, width * height * 4);
auto y = (unsigned char*)malloc(width * height);
auto u = (unsigned char*)malloc(width * height / 4);
auto v = (unsigned char*)malloc(width * height / 4);

unsigned char *srcbuf, *ybuf, *ubuf, *vbuf;
HANDLE_ERROR(cudaMalloc((void**)&srcbuf, width * height * 4));
HANDLE_ERROR(cudaMalloc((void**)&ybuf, width * height));
HANDLE_ERROR(cudaMalloc((void**)&ubuf, width * height / 4));
HANDLE_ERROR(cudaMalloc((void**)&vbuf, width * height / 4));

auto begin = std::chrono::steady_clock::now();
size_t frames = 0;

for(;;) {
auto diff = std::chrono::steady_clock::now() - begin;
if (diff > std::chrono::seconds(1)) {
fprintf(stderr, "fps = %g\n", frames * 1000.0 / std::chrono::duration_cast(diff).count());
fflush(stdout);
begin = std::chrono::steady_clock::now();
frames = 0;
}

HANDLE_ERROR(cudaMemcpy(srcbuf, src, width * height * 4, cudaMemcpyHostToDevice));

dim3 blocks(width / 2, height / 2);
rgb2yuv(width, height,
srcbuf, width * 4,
ybuf, width,
ubuf, width / 2,
vbuf, width / 2
);

HANDLE_ERROR(cudaMemcpy(y, ybuf, width * height, cudaMemcpyDeviceToHost));
HANDLE_ERROR(cudaMemcpy(u, ubuf, width * height / 4, cudaMemcpyDeviceToHost));
HANDLE_ERROR(cudaMemcpy(v, vbuf, width * height / 4, cudaMemcpyDeviceToHost));

if (frames == 0) {
for(int i = 0; i < width * height; ++i) { if (y[i] != 255) printf("%d %s\n", i, "error"); break; }
for(int i = 0; i < width * height / 4; ++i) { if (u[i] != 255) printf("%d %s\n", i, "error"); break; }
for(int i = 0; i < width * height / 4; ++i) { if (v[i] != 255) printf("%d %s\n", i, "error"); break; }
}
++frames;
}

HANDLE_ERROR(cudaFree((void*)srcbuf));
HANDLE_ERROR(cudaFree((void*)ybuf));
HANDLE_ERROR(cudaFree((void*)ubuf));
HANDLE_ERROR(cudaFree((void*)vbuf));

free(src);
free(y);
free(u);
free(v);

return 0;
}
Изображение


Подробнее здесь: https://stackoverflow.com/questions/785 ... esktop-gpu
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»