Узкое место МПК? - PullRequest
       23

Узкое место МПК?

0 голосов
/ 24 августа 2010

У меня есть два процесса, производитель и потребитель.IPC выполняется с помощью OpenFileMapping / MapViewOfFile на Win32.

Производитель получает видео из другого источника, которое затем передает потребителю, и синхронизация выполняется через два события.

Для производителя:

Receive frame
Copy to shared memory using CopyMemory
Trigger DataProduced event
Wait for DataConsumed event

Для потребителя

Indefinitely wait for DataProducedEvent
Copy frame to own memory and send for processing
Signal DataConsumed event

Без всего этого видео в среднем составляет 5 кадров в секунду.Если я добавлю события с обеих сторон, но без CopyMemory, он все равно будет на скорости 5 кадров в секунду, хотя и чуть медленнее.Когда я добавляю операцию CopyMemory, она снижается до 2.5-2.8fps.Memcpy еще медленнее.

Мне трудно поверить, что простая копия памяти может вызвать такое замедление.Есть идеи по поводу лекарства?

Вот мой код для создания общего мема:

HANDLE fileMap = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, fileMapSize, L"foomap");
void* mapView = MapViewOfFile(fileMap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, fileMapSize);

Размер 1024

3

Редактировать - добавлен фактический код:

О производителе:

void OnFrameReceived(...)
{
    // get buffer
    BYTE *buffer = 0;
...

    // copy data to shared memory
    CopyMemory(((BYTE*)mapView) + 1, buffer, length);

    // signal data event
SetEvent(dataProducedEvent);

    // wait for it to be signaled back!
    WaitForSingleObject(dataConsumedEvent, INFINITE);
}
*1024* О потребителе:
while(WAIT_OBJECT_0 == WaitForSingleObject(dataProducedEvent, INFINITE))
    {   
        SetEvent(dataConsumedEvent);
    }

Что ж, похоже, что копирование из буфера DirectShow в общую память былоузкое место в конце концов.Я попытался использовать именованный канал для передачи данных и угадать, что - производительность восстановлена.

Кто-нибудь знает какие-либо причины, по которым это может быть?

Комудобавьте детали, которые я не считал уместными ранее: производитель вводится и подключается к графу DirectShow для получения фреймов.

Ответы [ 2 ]

1 голос
/ 24 августа 2010

Копирование памяти включает в себя определенные операции под капотом, и для видео это может быть значительным.

Я бы попробовал другой маршрут: создать общий блок для каждого кадра или нескольких кадров. Назовите их соответственно, то есть block1, block2, block3 и т. Д., Чтобы получатель знал, какой блок читать дальше. Теперь примите кадр непосредственно к выделенному blockX, уведомите потребителя о доступности нового блока, выделите и немедленно начните использовать другой блок. Потребитель отображает блок и не копирует его - теперь этот блок принадлежит потребителю, и потребитель может использовать исходный буфер для дальнейшей обработки. Как только потребитель закрывает сопоставление блока, это сопоставление уничтожается. Таким образом, вы получаете поток блоков и избегаете блокирования.

Если обработка кадра не занимает много времени, а создание общего блока делает, вы можете создать пул общих блоков, достаточно большой для того, чтобы производитель и потребитель никогда не пытались использовать один и тот же блок (вы можете усложнить схему, используя семафор или Muxx для охраны каждого блока).

Надеюсь, моя идея ясна - избегайте копирования с использованием блока в производителе, чем в потребителе

0 голосов
/ 24 августа 2010

Время, необходимое для копирования 3 МБ памяти, не должно быть заметным.Быстрый тест на моем старом (и сломанном) ноутбуке смог выполнить 10 000 memcpy(buf1, buf2, 1024 * 1024 * 3) операций примерно за 10 секунд.На 1/1000 секунды это не должно замедлять вашу частоту кадров на заметную величину.

Несмотря на это, может показаться, что, возможно, существует некоторая оптимизация, которая может ускорить процесс.В настоящее время вы, кажется, обрабатываете данные в два или три раза больше.Двойная обработка, потому что вы «получаете кадр», затем «копируете в общую память».Тройная обработка, если «Копировать кадр в собственную память и отправить для обработки» означает, что вы действительно копируете в локальный буфер, а затем обрабатываете вместо простой обработки из буфера.

Альтернативой является получение кадра в общий ресурс.буферизировать напрямую и обрабатывать его прямо из буфера.Если, как я подозреваю, вы хотите получать один кадр при обработке другого, вы просто увеличиваете размер отображения памяти, чтобы вместить более одного кадра, и используете его в качестве кругового массива.На стороне потребителя это выглядело бы примерно так:

char *sharedMemory;
int frameNumber = 0;
...
WaitForSingleObject(...)  // Consume data produced event
frame = &sharedMemory[FRAME_SIZE * (frameNumber % FRAMES_IN_ARRAY_COUNT)
processFrame(frame);
ReleaseSemaphore(...)     // Generate data consumed event

И производитель

char *sharedMemory;
int frameNumber = 0;
...
WaitForSingleObject(...)  // Consume data consumed event
frame = &sharedMemory[FRAME_SIZE * (frameNumber % FRAMES_IN_ARRAY_COUNT)
recieveFrame(frame);
ReleaseSemaphore(...)     // Generate data produced event

Просто убедитесь, что семафор семафора потребляемых данных инициализирован в FRAME_IN_ARRAY_COUNT иПроизводимый семафором данных инициализируется до 0.

...