LINUX.ORG.RU

Все таки fread или mmap?

 , fread, ,


0

2

Приветствую.

В продолжении темы

Имеется армка 512МБ рам и 512ГБ сд карта.

Суть - для построения журнала видео архива на носителе без файловой системы при прямом проходе (при обратном смещение 1 минута и перечитывается флешка за секунды) флешки выполняю смещение на размер кадра, для поиска нужным мне меток. Все в целом устраивало при перечитывании временных меток пока писал JPEG, который был размером где то 220КБ, но как только начал писать H264 перечитать флешку «вперед» стало проблемой иба кадры в основном около 15КБ.

И тут вспомнился мне комментарий и полез читать в гугль например где говорится как я понял, что ммап быстрее последовательного доступа только в пределах размера памяти, но перечитать фактически мне нужно последовательно всю флешку кусками где то байт по 20, для которых выполняется парсинг простым сравнением памяти и копированием нужных ее мест из каждого куска.

Собсна глобальный вопрос - как бы ускорить чтение с носителя???

Второстепенный - fread vs fseeko какими буферами оперируют если читается фридом условно 20 байт и как его менять? setvbuf почему то чем то вроде setvbuf(pf, NULL, _IOFBF, 32 * 1024 * 1024) никак не влияет на скорость перечитывания носителя

Или может я просто уперся в физическую скорость флешки!?

★★★

Последнее исправление: Dimez (всего исправлений: 1)
Ответ на: комментарий от AntonI

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

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

Так что от таблицы содержания я отказался по причине максимальной жизни флешки и минимальной нагрузке при записи.

wolverin ★★★
() автор топика
Ответ на: комментарий от m0xf

Если данные выровнены, то можно открыть файл с опцией O_DIRECT с помощью системного вызова open. Так можно избежать лишнего копирования памяти.

нельзя :-) ТС работает с целиковой флешкой как с raw-device. Там нет отдельных файлов.

на мой взгляд это архитектурная ошибка. Но ему виднее, он за неё деньги получает

MKuznetsov ★★★★★
()
Ответ на: комментарий от mky

еще раз спасибо за подсказки на что обратить внимание, пока для перечитывания журнала выкинул fread читающий из 20 байт по факту 4кб заменив на read читающий те же самые 20 байт (проверил через strace) очевидно поднимая в память 1-2 сектора по 512б и смещаясь на условно 15кб, это дало наверное 10-15% прироста скорости судя по секундомеру ))

… буду дальше думать

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)
Ответ на: комментарий от mky

стандарты нигде не требуют, чтобы fread() превращался в read() с размером буфера, указаным через setvbuf()

Он и не для этого нужен. Буфер этот нужен чтобы getc не делал каждый раз read по одному байту, а сразу прочитал блок и потом отдавал по байту. Изменять стандартный размер этого буфера нужно когда ты читаешь данные кусками которые больше стандартного размера этого буфера. Иначе libc будет делать несколько read чтобы заполнить буфер в который ты читаешь.

Поэтому в куче программ fread() и не используют, самостоятельно реализуют его функционал, делают read() в большой буфер и разгребают его содержимое

При чтении в большой буфер нет смысла использовать fread, т.к. это не только ничего не даёт, но даже делает хуже, потому что сначала данные читаются во внутренний буфер libc (который предварительно нужно сделать достаточно большим), а потом копируются в твой буфер.

no-such-file ★★★★★
()

насколько я понимаю, сейчас теоретически самый низко-оверхедный способ прочитать файл в онтопике - это открыть его с O_DIRECT и нафигачить запросов на чтение через io_uring.

Но это для быстрых ssd, когда ты можешь читать гигабитами в секунду и всякие кэши страниц памяти уже начинают давать ощутимый оверхед. Медленная SD-карта - явно не тот случай. Тут fread или mmap вообще без разницы.

Lrrr ★★★★★
()
Ответ на: комментарий от Lrrr

С фриад и ммап все таки есть разница - во-первых ммап не выполняет копирование памяти, во-вторых при последовательном режиме (MADV_SEQUENTIAL) чтения ОС будет сама поднимать несколько секторов в кеш, проблема я так понимаю возникнет, когда потребуется вытеснять кеш.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)

есть отличный источник информации - Linux Kernel Programming и Linux Device Drivers. Даже переводные-старенькие, вам новые фичи и не нужны

Их можно за неделю по диагонали прочесть - просто чтобы представлять что происходит при fread (который вообще библиотечный), что при mmap, что там в блочных устройствах и как память шарится и кешируются; Возможно есть и более популярные изложения.

Вам-же не программировать в ядро, но полезно представлять общую картину. Чтобы не тратить время и не ставить дурацкие эксперименты (замена fread на read с секундомером - это примерно из той области, пару сисколов заменили на 1, но трансфер по памяти тот-же, вы так-же читаете всю флешку и наматываете «циклы чтения»).

это не критика - это рекомендации. Вы столкнулись с вещью слегка выходящей за квалификацию. Квалификацию надо слегка поднять и это несложно

MKuznetsov ★★★★★
()
Ответ на: комментарий от wolverin

журнал в памяти нужен чтобы при обращении к архиву быстро плюнуть в сеть нужный кусок

Тогда храните его в памяти если лезет. Если не лезет - быстро поднимайте одним куском с флешки.

мне понятно ваше предложение - условно хранить место под кадр «вперед»

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

Как я понял Вам нужно в какой то момент пройти по кадрам и выдрать из каждого кадра 20 байт. Мое предложение - сложить эти 20ти байтные куски отдельно кучкой и не ходить по кадрам. Если к каждому 20ти байтнику нужно знать оффсет кадра в большом файле - положите к этим 20ти байтам еще 8 байт оффсета (хотя можно и ужаться в 4 байта, есть способы).

Если волнует дыра во флэшке - не будет там дыры если правильно делать.

AntonI ★★★★★
()
Ответ на: комментарий от AntonI

Нет никакого файла как и смысла поддерживать блок неизвестного заранее размера поделенный на куски по 512б, которые хирожопо должны обновляться только таким размером

Завтра вместо флешек заказчик начнет ставить диски по 4к сектор - опять все переделывать

При последовательной записи таблица содержания это атавизм.

wolverin ★★★
() автор топика
Ответ на: комментарий от no-such-file

Медленно оно выйдет не потому что 1 байт, а потому что дохрилион переключений контекста.

А переключения почему по-твоему? Как раз потому что по 1 байту.

firkax ★★★★★
()
Ответ на: комментарий от wolverin

То есть Вы говорите следующее - «Я как то пишу на флешку в 512Гб файлы по 15Кб а потом прохожу по ним всем и выдергиваю из них по 20 байт, и это долго. Скажите мне как это делать быстро при помощи mmap».

Это НИКАК НЕЛЬЗЯ сделать быстро, ЕДИНСТВЕННЫЙ способ это сделать быстро - положить эти 20ти байтные блоки ВМЕСТЕ (+ 4-8 байт на поиск самого файла).

Как их держать вместе что бы флешка раньше времени не умерла это второй вопрос, напр. инкрементально - алгоритмов для таких задач есть туева хуча. Да хоть по сети отправляйте их на внешнее хранилище и пусть там разбираются что надо;-)

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

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

) я не пишу файлы и 15кб это условная величина видео кадра в кодеке х264, как и 20б это тоже условная величина, которая от 18 до 26 байт

вместо вашего предложения проще использовать файловую систему

и время жизни флешки - это первостепенный вопрос - иначе не затевался бы весь этот геморрой.

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

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Работайте с суперблоками по N кадров - вначале суперблока таблица с 20ти байтными записями и оффсетами (ее размер известен, можете сразу по 26 байт выделять по макс на запись), потом сами кадры. Пока суперблок пишется, таблица висит в памяти а кадры ложатся на флешку, как суперблок закончился таблица записывается на флешку целиком и переходим к следующему суперблоку. При такой структуре данных интенсивность записи везде одинаковая, а пробежатся по всем суперблокам и выдернуть из них таблицы это будет быстро.

найти «голову» на флешке

ЯННП. Если там нет ФС, Вы же просто одним куском читаете/пишете данные по адресу? И где то у Вас должна быть разметка где что лежит, хотя бы то же начало? В исходном посте описан обычный односвязный список как я понял?

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 2)
Ответ на: комментарий от wolverin

) я не пишу файлы и 15кб это условная величина видео кадра в кодеке х264, как и 20б это тоже условная величина, которая от 18 до 26 байт

Тебе правильно говорят кешировать эти ~20 байт. Занимать это будет около 0.5% от основных данных, зато скорость чтения будет в 200 раз быстрее.

и время жизни флешки - это первостепенный вопрос - иначе не затевался бы весь этот геморрой.

Выдели 0.5% места на флешке под кеширование этих данных, износ будет такой-же как и у основных данных.

V1KT0P ★★
()
Ответ на: комментарий от AntonI

В итоге имеем пустые куски в каждом суперблоке неизвестной длины, при этом нет никакой необходимости знать где лежит каждый кадр.

Я поднимаю в память только положение минутных отрезков.

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

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Тогда мы приходим к тому, что исходно сформулированную задачу Вы на самом деле решать не хотите, а хотите решать какую то совершенно другую задачу;-)

Это нормально, но эту другую задачу неплохо бы сформулировать - лето на дворе, все телепаты в отпусках.

При частоте один кадр в секунду и размере кадра 15Кб в 512Гб влезет аж 600тыс минутных отрезков, наверное про них вообще все что нужно можно в памяти хранить?;-)

имеем пустые куски в каждом суперблоке неизвестной длины

Если их суммарный размер меньше 10% от размера суперблока то на это вообще пофик.

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

Частота 30 кадров в секунду для х264 где Р кадры 10-20 КБ и И кадры 150КБ, для мжпег 180-230Кб каждый кадр при 5фпс - и в том и в другом случае метка времени и смещение только для минуты и поэтому это все помещается в памяти.

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)

ради интереса посмотрел что там в интернетах про дохлоту флешек...

в основном они дохнут от смерти собственного контроллера. (да у них в любом случае внутри есть PIC/ARM проц со своей nano-OS и RAM+DRAM и он/они дохнут). Там внутри ещё и дешманский кварц, чем дешевле тем хуже. Там так-же отдельные диоды и ёмкости. Но подыхает в 80% случаев контроллер.

Набрать 100000 циклов перезаписи одного блока, это только в лаборатории, в маркетинговых целях и это надо сильно стараться.

основная причина выхода из строя флешки - не протёртая дырка в отдельных ячейках или блоках.

MKuznetsov ★★★★★
()
Ответ на: комментарий от wolverin

Проблема в том что тогда лучше использовать файловую систему

В этом нет нужды, выделить блок в пару килобайт для описания где основные данные лежат а где кеш, плюс оставить чуть места на еще какие данные.

V1KT0P ★★
()
Ответ на: комментарий от wolverin

2 нуля лишних

то есть 1000 циклов ??

а это что такое вообще тогда ?

на два нуля меньше от 100000 - это ферритовые сердечники по которым периодично бьют молотком. За счёт ударов молотком

MKuznetsov ★★★★★
()
Ответ на: комментарий от wolverin

Совсем дешёвые вообще 500 циклов пишут )

сколько десятков килограммов таких MMC можно купить за зарплату группы разработчиков ?

и кстати даже про такое не слышал, чтобы 500 циклов всего..это у вас что-то своё-рекламное для начальства

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Ну мне зачем выдумывать - в интернетах написано, тьфу тьфу тьфу, пока за 2 года ни одна не сдохла, хотя тоже постоянно слушал скепсис что это на 1 максимум 1.5 года

wolverin ★★★
() автор топика
Ответ на: комментарий от MKuznetsov

Вот вам для примера

The different type of NAND Flash has different Program Erase P/E cycles (the processes of erasing and then writing a cell), and their typical P/E cycles are as follows:

SLC: 90,000 and 100,000

MLC: 1,500 to 3,000

3D TLC: 500 to 3,000

картинка

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

SLC, MLC - это топология базовых ячеек (single/multi layer).. во всех «дешманских флешках» только они.

при этом у вас личный опыт говорит : «тьфу тьфу тьфу, пока за 2 года ни одна не сдохла».. вы как разработчик, их имеет в хвост и гриву

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Да нет, откатал на 32гб (а как известно с ростом объема циклы падают) технологию не так уж и долго по часам, тем не менее 1000 циклов таки правильное значение, а не 100к )

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

То есть задача подняться после ребута? Но это же сравнительно редкое явление, зачем тут что то городить?

Отдать дцать Гб флешки на кольцевой буфер и писать туда что то жизнеутверждающее?:-)

AntonI ★★★★★
()
Ответ на: комментарий от AntonI

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

512гб это текущий вариант, но допускаю придут наконец нормальные камеры с битрейтом до 2мбит и с 15 фпс и это все влезет возможно на 64 Гб карту с той же глубиной архива, поэтому ну никак не хочется городить аналог таблицы содержания, должен быть какой то другой способ.

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Так а что сделать то надо в итоге?

Что известно после ребута и что надо найти?

Вот же в исходной теме у Вас все по феншую - журнал там, заголовки…

AntonI ★★★★★
()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от wolverin

Да нет, откатал на 32гб (а как известно с ростом объема циклы падают) технологию не так уж и долго по часам, тем не менее 1000 циклов таки правильное значение, а не 100к )

да фик с ними - даже 100 циклов на озвученном флеше 512Гб (основная масса данных по кругу), 512*100 = 50 Тб. :-) Более чем дохрена

другое дело если вы их распаиваете и тогда замена дело дорогое.

но это уже ваша епархия - зачем и отчего сие мудрится. Сама по себе задача не стоит выеденного яйца, вместо того чтобы сканировать по 20 байт по всей ёмкости, сложить эти кусочки в одно место и взять целиком.

Но опять-же и это не критично, а только при загрузке. Smart-камера включится за 10 сек или за 11 сек..

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

) не так уж и дохрена 512Гб это почти 5 суток для мжпег и пока теоретически 10 суток для х264, так что очень зависит это для количества лет, поэтому не основная масса, а все данные пишутся только по кругу и никак иначе.

зы. ф планах добиться тех же 5 суток на 64гб флешке и тогда это уапще будет прорыв ))

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)

Не знаю, написали про это:

setvbuf(pf, NULL, _IOFBF, 32 * 1024 * 1024) 
Но, в glibc это конструкция смысла не имеет. https://stackoverflow.com/questions/62126052/setvbuf-not-changing-buffer-size Никакой буфер размером 32Мб не выделяется, для glib эта конструция просто включает блочную буферизацию с размером по умолчанию (4кб).

Нужно явно указывать буфер, причём, желательно в соответствии с man setvbuf:

You must make sure that the space that buf points to still exists by the time stream is closed...

То есть, или статическией, как здесь: https://www.ibm.com/docs/el/i/7.4?topic=functions-setvbuf-control-buffering или через malloc() и free() только после fclose().

mky ★★★★★
()
Ответ на: комментарий от mky

в glibc это конструкция смысла не имеет

нет, все таки ожесточенно плюсую вам! ))

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

wolverin ★★★
() автор топика
Ответ на: комментарий от AntonI

Согласен, но человек борется с проблемами живучести флешек. Поэтому такой алгоритм ему и не подходит.

Прав человек или нет - неведомо. Мне кажется, что это борьба с ветряными мельницами. Но это мне, и кажется; а он работу работает.

blex ★★★
()

У меня microSD карта Samsung Evo+ 64 GB (UHS Class 1). При подключении через USB 3 ридер тесты последовательного чтения (dd if=/dev/sdc iflag=direct) показывают вот такие числа:

  • bs=4K: 11 MB/s
  • bs=16K: 30 MB/s
  • bs=64K: 80 MB/s
  • bs=1M: 90 MB/s

При подключении через PCIe ридер тесты последовательного чтения (dd if=/dev/mmcblk0 iflag=direct) показывают вот такие числа:

  • bs=4K: 5 MB/s
  • bs=16K: 17 MB/s
  • bs=64K: 40 MB/s
  • bs=1M: 77 MB/s

Значит прочитать последовательно 512 GB это 97 минут в лучшем случае. Согласно https://www.sdcard.org/developers/sd-standard-overview/speed-class/ пропускная способность 90 MB/s это максимум, на который способен интерфейс SD.

Кажется твоя проблема в том, что метаданные перемешаны с данными, и для чтения метаданных приходится читать все данные. Хотя метаданных там 32/15K, то есть ~1/500 (около 0.2%).

Если бы твоя карта была разбита на 2 раздела (500 GB данные + 1 GB метаданные), и каждый раздел писался бы по кругу, то для чтения метаданных надо было бы прочитать всего 1 GB (менее 15 секунд).

Касательно fread. Во-первых FILE* не умеет в O_DIRECT. Соответственно есть буферизация в ядерный page cache, есть буферизация в setvbuf buffer. Есть ещё твой буфер, который ты передаёшь в fread(). Если он «20 байт» то им можно принебречь. Если же он сопоставим по размеру с setvbuf buffer, то это тройная буферизация. Использование open(O_DIRECT) позволяет исключить page cache. Использование read() позволяет исключить setvbuf buffer.

Касательно mmap. Он позволяет отмапить в адресное пространство процесса ядерный page cache. Но mmap не даёт возможности выбрать размер блока для чтения. Ядерный page cache будет сам читать с карты каким-то блоком. Это может оказаться маленький блок и чтение будет небыстрым.

iliyap ★★★★★
()
Последнее исправление: iliyap (всего исправлений: 1)