Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.188.142.146] |
|
Сообщ.
#1
,
|
|
|
Есть машины, из которых я делаю сервер видеозаписи. На них стоит 8-ми канальная карта видеозахвата (Decklink Quad 2). Есть написанная мною программа, которая через DirectShow забирает видео/аудио данные, жмёт в DV и складывает в файл.
В одноканальном режиме программа работает без проблем на паре десятков машин уже пару лет минимум. Для многоканального режима я просто запускаю восемь экземпляров программы с разными настройками. Запись идёт на SSD, откуда по сети забирается на сервер. Данные получаются из Directshow через механизм SampleGrabber callback, то есть у меня есть коллбеки, в которых полученные данные складываются в буфер в памяти. Потом в процедуре обработки таймера данные из буфера в памяти складываются на диск. И вот тут начинается проблема - время от времени запись на диск начинает зверски тормозить, буфера переполняются и идёт потеря видео. Потом вдруг всё приходит в себя, буфер сливается на диск и всё становится опять нормально до следующей проблемы. Вот так выглядит участок записи буфера на диск: RecStart := Now(); FileWrite(OutFileHandle, AVFrame^, AVFrame_size); RecDur := Millisecondsbetween(Now(), RecStart); if RecDur > RecordTO then WriteToLog('На запись одного кадра ушло ' + inttostr(RecDur) + ' мс'); Один кадр занимает 151688 байт, таких кадров пишется в секунду 25, то есть в одной программе генерится поток на запись около 3.8МБ/сек. В сумме в 8 экземплярах программ - около 30МБ/сек, что для SSD не должно быть проблемой никак (по тестам он продолжительно пишет около 300МБ/сек без каких-либо провалов). В реальности же я получаю в логах сообщения вида: 2017-05-11 12:18:49.114 На запись одного кадра ушло 1025 мс 2017-05-11 12:26:01.756 На запись одного кадра ушло 2629 мс 2017-05-11 12:36:21.011 На запись одного кадра ушло 1941 мс 2017-05-11 12:47:09.617 На запись одного кадра ушло 1252 мс 2017-05-11 13:01:03.850 На запись одного кадра ушло 1986 мс То есть пара секунд на запись 150 кбайт! Причём что характерно - вот если есть торможение в 2017-05-11 13:01:03.850 то оно будет по всем каналам, то есть это некое глобальное торможение. Понимаю, что возможно это какие-то проблемы с машиной или виндой. Но я имею совершенно аналогичные проблемы на двух машинах. Windows 7 x64 ENT. Пробовал ставить Win10 с совершенно аналогичным результатом. Может есть какие советы - что попробовать сделать? |
Сообщ.
#2
,
|
|
|
Похоже на глюкавую фичу менеджера ленивой записи ОС, когда ленивый сброс данных на диск происходит медленнее их записи в кэш, что рано или поздно приводит к переполнению кэша и лихорадочному сбросу на диск "всего и вся" с соответствующими периодическими тормозами.
Самое простое, что можно попробовать - это добавить после записи FlushFileBuffers (или тупо после каждой записи, или лучше после записи определенного, достаточно большого размера данных, например 4-8-16 Мб). Другой вариант - открывать файл с флагом FILE_FLAG_WRITE_THROUGH, или еще круче FILE_FLAG_WRITE_THROUGH + FILE_FLAG_NO_BUFFERING (но тогда придется записывать данные с выравниванием размера на сектор 512 байт, или лучше на кластер 4 кБ). При этом также желательно увеличить размер буфера записи до нескольких мегабайт для уменьшения частоты обращения к диску. |
Сообщ.
#3
,
|
|
|
Да, похоже. Особенно характерно то, что при этом по монитору ресурсов до упора растёт память кеша.
Надо будет существенно переделать логику - вынести все операции записи в отдельный класс, тогда будет проще менять логику записи. Та еще работёнка. Но сейчас займусь... Небольшой побочный вопрос: вот если я делаю FILE_FLAG_WRITE_THROUGH + FILE_FLAG_NO_BUFFERING, то как записывать последний блок данных? Размер файла же некратен размеру кластера. Или надо записывать последний блок целиком, а потом выставлять отдельно длину файла? Что-то не нашёл в MSDN ответа на этот вопрос. |
Сообщ.
#4
,
|
|
|
А, всё, нашёл, гугл рулит Действительно - записываем последний блок целиком и потом вызываем SetFileInformationByHandle и задаём длину файла.
|