Быстро написать много больших файлов на C++

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

Размер каждого необработанного кадра составляет 2 МБ, а частота кадров — 30 кадров в секунду (т. е. скорость передачи данных составляет около 60 МБ/с), и я пишу на SSD, который может легко обрабатывать устойчивые > 150 МБ/с (проверено путем копирования 4000 файлов размером 2 МБ с другого диска). что заняло 38 секунд, а Process Explorer показывает постоянную активность ввода-вывода).

Моя проблема заключается в том, что иногда вызовы fopen(), fwrite() и fclose() останавливаются на срок до 5 секунд, что означает, что 300 МБ кадров накапливаются в памяти в виде невыполненного журнала, и после нескольких таких задержек я достиг предела 4 ГБ для 32-битного процесса. . (Когда происходит задержка, Process Explorer показывает пробел в активности ввода-вывода)

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

writeFrame(char* data, size_t dataSize, char* filepath)
{
    // Time block 2
    FILE* pFile = NULL;
    fopen(&pFile, filepath, "wb");
    // End Time block 2

    // Time block 3
    fwrite(data,1,dataSize,pFile);
    // End Time block 3

    // Time block 4
    fclose(pFile);
    // End Time block 4
}

(В реальном коде также есть проверка ошибок, но это не имеет значения для этой проблемы) Я регистрирую время, необходимое для каждого из блоков, и общее время, необходимое для запуска функции, и я получаю результаты, которые большую часть времени выглядеть так: (количество раз в мс)

TotalT,5,       FOpenT,1,       FWriteT,2,    FCloseT,2
TotalT,4,       FOpenT,1,       FWriteT,1,    FCloseT,2
TotalT,5,       FOpenT,1,       FWriteT,2,    FCloseT,2

т.е. ~5 мс для запуска всех функций, ~1 мс для открытия файла, ~2 мс для вызова записи и ~2 мс для закрытия файла.

Однако иногда (в среднем примерно 1 из каждых 50 кадров, но иногда между возникновением этой проблемы могут быть тысячи кадров) я получаю кадры, которые занимают более 4000 мс:

TotalT,4032,    FOpenT,4023,    FWriteT,6,    FCloseT,3

и

TotalT,1533,    FOpenT,1,       FWriteT,2,    FCloseT,1530

Все кадры имеют одинаковый размер, и никогда не fwrite требуется дополнительное время, всегда fopen или fclose

Ни один другой процесс не выполняет чтение/запись на/с этого SSD (подтверждено с помощью Process Monitor).

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


person digitalPhonix    schedule 17.01.2014    source источник
comment
Каждый кадр пишется в отдельный файл? Возможно, вы могли бы записать группы кадров в один файл и иметь отдельный поток для их постобработки, чтобы взять файл из N кадров и впоследствии разделить на отдельные файлы (чтобы облегчить вызовы fopen/fclose в потоке обработки видео). Это позволит вашей функции writeFrame работать намного быстрее и не замедлит процесс захвата видео.   -  person spartygw    schedule 17.01.2014
comment
рассмотрите возможность проверки того, что fopen и fclose на самом деле успешно открываются и закрываются, также проверьте, сколько потоков запущено, возможно, вы достигли максимального количества потоков.   -  person Matthew Pigram    schedule 17.01.2014
comment
Вы не упоминаете платформу или тип файловой системы, используемый на ssd. Если это окна, это было бы хорошим местом для использования асинхронной записи.   -  person Dan    schedule 17.01.2014
comment
@spartygw да, каждый кадр записывается в отдельный файл. Я подумываю записать в массивный файл, а потом обрезать его, но это все же должно быть возможно, верно? :(   -  person digitalPhonix    schedule 17.01.2014
comment
@MatthewPigram Извините, я не понял, есть только две темы. Один ждет команды запуска/остановки, поток, который запускает эту функцию в цикле, и кадры доставляются в очередь в обратном вызове драйвера.   -  person digitalPhonix    schedule 17.01.2014
comment
@Dan Работает в Windows. Разве быстрая асинхронная запись в разные файлы не будет плохой?   -  person digitalPhonix    schedule 17.01.2014
comment
Каждый кадр отдельным файлом? Очень вероятно, что проблема. Вы создаете 30*60*2=3600 файлов за 2 минуты. В то время как последовательная запись выполняется быстро, создание файла/закрытие файла - нет, поскольку они не являются последовательным доступом к диску, им необходимо получить доступ к структуре каталогов/записям таблицы файлов, при условии, что многие из них находятся в кеше памяти, но вы будете время от времени нажимать на диск . Другая проблема с ntfs заключается в том, что каталог не масштабируется, чем больше файлов в одном каталоге, тем медленнее создается новый файл (очевидно, это проявляется только тогда, когда количество файлов в одном каталоге превышает 10 КБ).   -  person X.J    schedule 17.01.2014
comment
Какую файловую систему использует SSD?   -  person Collin Dauphinee    schedule 17.01.2014
comment
Это NTFS (сейчас просто подумал... не будет ли для этого лучше FAT? Я не собираюсь ограничивать размер файла). Как копирование файлов Windows поддерживает гораздо более высокие скорости передачи данных при записи одних и тех же файлов?   -  person digitalPhonix    schedule 17.01.2014
comment
@X.J.: SSD-накопители заботятся о непоследовательном доступе? (изменить: derp, кэширование записи, nm)   -  person Lightness Races in Orbit    schedule 17.01.2014
comment
msdn.microsoft.com/ en-us/library/windows/desktop/   -  person Dan    schedule 17.01.2014


Ответы (2)


Я буду на стороне XJ, вы, вероятно, записываете слишком много файлов в один каталог. Решением может быть создание нового каталога для каждой партии кадров. Также рассмотрите возможность вызова SetEndOfFile сразу после создания файла, так как это поможет Windows выделить достаточно места за одну операцию.

FAT не является реальным решением, так как она еще хуже работает с большими каталогами.

person MSalters    schedule 17.01.2014

Подготовьте пустые файлы (файлы 2 МБ, заполненные нулями) Так что место уже "готово", то просто перезапишите эти файлы. Или создайте файл, состоящий из нескольких кадров, чтобы уменьшить количество файлов.

есть библиотеки для сжатия и распаковки и воспроизведения видео:

libTheora может быть полезна, потому что уже сжимает кадры (ну, вам нужно будет выводить видео в один файл) и делает это довольно быстро (кстати, сжатие с потерями).

person CoffeDeveloper    schedule 17.01.2014