На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Тормозит FileWrite , Запись 150 кбайт занимает до нескольких секунд
    Есть машины, из которых я делаю сервер видеозаписи. На них стоит 8-ми канальная карта видеозахвата (Decklink Quad 2). Есть написанная мною программа, которая через DirectShow забирает видео/аудио данные, жмёт в DV и складывает в файл.
    В одноканальном режиме программа работает без проблем на паре десятков машин уже пару лет минимум.
    Для многоканального режима я просто запускаю восемь экземпляров программы с разными настройками.
    Запись идёт на SSD, откуда по сети забирается на сервер.
    Данные получаются из Directshow через механизм SampleGrabber callback, то есть у меня есть коллбеки, в которых полученные данные складываются в буфер в памяти. Потом в процедуре обработки таймера данные из буфера в памяти складываются на диск.
    И вот тут начинается проблема - время от времени запись на диск начинает зверски тормозить, буфера переполняются и идёт потеря видео. Потом вдруг всё приходит в себя, буфер сливается на диск и всё становится опять нормально до следующей проблемы.
    Вот так выглядит участок записи буфера на диск:
    ExpandedWrap disabled
                  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 с совершенно аналогичным результатом.
    Может есть какие советы - что попробовать сделать?
      Похоже на глюкавую фичу менеджера ленивой записи ОС, когда ленивый сброс данных на диск происходит медленнее их записи в кэш, что рано или поздно приводит к переполнению кэша и лихорадочному сбросу на диск "всего и вся" с соответствующими периодическими тормозами.
      Самое простое, что можно попробовать - это добавить после записи FlushFileBuffers (или тупо после каждой записи, или лучше после записи определенного, достаточно большого размера данных, например 4-8-16 Мб).
      Другой вариант - открывать файл с флагом FILE_FLAG_WRITE_THROUGH, или еще круче FILE_FLAG_WRITE_THROUGH + FILE_FLAG_NO_BUFFERING (но тогда придется записывать данные с выравниванием размера на сектор 512 байт, или лучше на кластер 4 кБ). При этом также желательно увеличить размер буфера записи до нескольких мегабайт для уменьшения частоты обращения к диску.
      Сообщение отредактировано: leo -
        Да, похоже. Особенно характерно то, что при этом по монитору ресурсов до упора растёт память кеша.
        Надо будет существенно переделать логику - вынести все операции записи в отдельный класс, тогда будет проще менять логику записи. Та еще работёнка. Но сейчас займусь...
        Небольшой побочный вопрос: вот если я делаю FILE_FLAG_WRITE_THROUGH + FILE_FLAG_NO_BUFFERING, то как записывать последний блок данных? Размер файла же некратен размеру кластера. Или надо записывать последний блок целиком, а потом выставлять отдельно длину файла? Что-то не нашёл в MSDN ответа на этот вопрос.
          А, всё, нашёл, гугл рулит :) Действительно - записываем последний блок целиком и потом вызываем SetFileInformationByHandle и задаём длину файла.
          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
          0 пользователей:


          Рейтинг@Mail.ru
          [ Script execution time: 0,0294 ]   [ 17 queries used ]   [ Generated: 28.03.24, 21:19 GMT ]