Eugene
fld [y] fld [x] fpatan ; арктангенс y/x Результат в st(0)
FroZZZ
спасибо, буду пробовать
FroZZZ
FroZZZ
Edem
Добрый день! Почему считается нежелательным считывать по байту из файла?
Aiwan \ (•◡•) / _bot
Добрый день! Почему считается нежелательным считывать по байту из файла?
изза скорости. лучше 1 раз прочитать и куда нить записать 4 или 8 байта чем 1 при равной скорости
Anonymous
Добрый день! Почему считается нежелательным считывать по байту из файла?
Зачем, если можно считать размер файла, который хранится у ОС с начала каждого изменения файла, а после чего считать сразу по размеру, и оперировать с памятью. Обращение к памяти (в том числе выделенной) внутри процесса быстрее, чем вызов функции, и обращение к ядру
Edem
Зачем, если можно считать размер файла, который хранится у ОС с начала каждого изменения файла, а после чего считать сразу по размеру, и оперировать с памятью. Обращение к памяти (в том числе выделенной) внутри процесса быстрее, чем вызов функции, и обращение к ядру
мне нужно распарсить файл размером в несколько МБ (используя TASM, прога ".com") Думаю как лучше сделать, если нужно по байту считывать. Видимо будет эффективнее, если буду считывать, условно, по 32768 байт в буффер, а потом оперировать с ним, верно?
Edem
Не понимаю, у вас нет возможности получить размер файла?
есть, но можно ли в com программе создать буфер размером больше чем 2¹⁶ ?
Eugene
Не понимаю, у вас нет возможности получить размер файла?
Куда он будет читать весь файл размером в несколько Мб? Или ты предлагаешь ему с XMS заморочиться? А главное — зачем?
Eugene
Это не будет в итоге быстрее, чем читать большими блоками. В DOS всё равно читать будешь блоками.
Anonymous
Можно и блоками, если файл прям сильно большой. Но если есть возможность, можно исключить постоянные обращения к ядру, и считать файл сразу в выделенную память, и уже ограничиться одними инструкциями для работы с памятью
Eugene
К тому же, скорость операции физического чтения с диска ни в какое сравнение не идёт с проваливанием в ядро или вызовом прерывания.
Anonymous
К тому же, скорость операции физического чтения с диска ни в какое сравнение не идёт с проваливанием в ядро или вызовом прерывания.
Ну так в том и дело, что считываться будет с диска, ещё и обращения к ядру. А вместо этого можно оперировать с виртуальной памятью, если файл не слишком большой (дабы была возможность запросить память)
Anonymous
Ещё раз: какая разница — будет ты читать по 32 Кб и сразу обрабатывать или по 32 Кб и складывать в память, а потом обрабатывать?
Не "читать по 32 байта и складывать в память, а потом обрабатывать" А запросить размер, считать сразу весь файл, и обращаться только к памяти, вместо обращений к ядру и диску
Eugene
Если бы это была винда, можно было бы сделать map view. Но тоже не читать весь файл, ибо бы тем самым забиваешь память и вытесняешь часть памяти в файл подкачки, а это никак не ускорение.
Eugene
Так вроде MapView как раз и позволяет выделить сразу весь файл в память
Могу ошибаться, но как я понимаю, он работает аналогично подкачке. Выделяет адресное пространство (а не память). И когда ты обращаешься к несуществующей странице, подгружает данные из файла. Это не точно, но по логике должно быть так.
s54820
Ещё раз: какая разница — будет ты читать по 32 Кб и сразу обрабатывать или по 32 Кб и складывать в память, а потом обрабатывать?
Это от формата файла зависит ведь. Если у тебя максимальный размер сущности внутри файла, например, 64к, то лучше сложить в буфер и брать оттуда, чем городить дочитывания.
Eugene
Но это, по идее, тоже в итоге заполнит память файлом. Вряд ли он будет удалять старые страницы.
Eugene
Будет.
Откуда он узнает, нужны они мне или нет?
s54820
Откуда он узнает, нужны они мне или нет?
А откуда ОС знает, нужна тебе память, или её можно в своп?
Eugene
А откуда ОС знает, нужна тебе память, или её можно в своп?
Нет, речь не про своп, а про освобождение.
Eugene
В своп он, скорее всего, отправит что-то более старое тогда уж, чем свежепрочитанный файл.
s54820
Нет, речь не про своп, а про освобождение.
Ну если ты открыл на запись, оно будет обратно в файл писать. Если на чтение — то будет удалять и перечитывать по необходимости, если working set слишком разрастётся.
Eugene
Ну если ты открыл на запись, оно будет обратно в файл писать. Если на чтение — то будет удалять и перечитывать по необходимости, если working set слишком разрастётся.
Так вот, опять-таки, ЕСЛИ. Вот можно юзать что=то типа такого, наверное, https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-discardvirtualmemory
Eugene
Хотя, х/з.
Eugene
Даже скорее вот это: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-offervirtualmemory
s54820
Eugene
Это хинты. Оно в целом и само неплохо работает.
Неплохо не есть хорошо. Вот смотри, как лучше? 1. У тебя файл на 8 Гб и столько же оперативы, а занято оперативы 4 Гб. Ты прочитал 4 Гб, памяти не хватает, винда думает: что бы скинуть в своп? Видит какую-то редко используемую память, скидывает 1 Гб (условно). Ты прочитал ещё 1 Гб, она ещё что-то скинула. Потом ещё 1 Гб, скидывать особо нечего, начала скидывать начало файла. 2. У тебя файл на 8 Гб и столько же оперативы, а занято оперативы 4 Гб. Ты прочитал 1 Мб, обработал, сделал хинт. Потом ещё 1 Мб, сделал хинт. После заполнения 4 Гб винде ничего скидывать в своп не нужно, она просто удалит первый 1 Гб (условно). Или даже ещё раньше это сделает.
Eugene
В первом случае память не бережётся, зато быстрее, установлен приоритет для своего же кода. Во втором случае бережётся память, но намного медленнее.
Почему в первом быстрее? Если свопиться приходится? И почему второй намного медленнее? Ну по 1 Мб, может, действительно не стоит, но по 10 или 100 Мб вполне можно.
Anonymous
Почему в первом быстрее? Если свопиться приходится? И почему второй намного медленнее? Ну по 1 Мб, может, действительно не стоит, но по 10 или 100 Мб вполне можно.
Вообще, я писал если файл небольшой (меньше 1 гб) тогда можно сразу его прочитать. В ином случае можно запросить размер, и разделить его на блоки, и точно также выделить память, но считывать туда уже блоками.
Anonymous
Я не писал, что нужно сразу в память тащить по 8 гб
Eugene
Я не писал, что нужно сразу в память тащить по 8 гб
Ну я немного утрировал, конечно, но просто чтоб суть пояснить :)) Но говорить, что прочитать сразу несколько метров — это быстрее, чем читать блоками, потому что меньше обращений к ядру — это тоже странно. Учитывая, что скорость чтения на порядки медленнее обращения к ядру.
Eugene
Возможно своп в редких моментах быстрее, чем 819 обращений к ядру и диску
А своп — это не диск? :) В некоторых — быстрее. Например, когда своп на рамдиске :)))
Anonymous
А своп — это не диск? :) В некоторых — быстрее. Например, когда своп на рамдиске :)))
Диск, но я уточнил, что даже при таком подходе нельзя точно сказать, что каждый раз будет свопаться. Зато можно точно сказать, что будет 819 обращений к ядру и диску при подходе с блоками
Eugene
Диск, но я уточнил, что даже при таком подходе нельзя точно сказать, что каждый раз будет свопаться. Зато можно точно сказать, что будет 819 обращений к ядру и диску при подходе с блоками
Я вот сейчас 1000 раз вызвал функцию Sleep(0) (аналогично с SwitchToThread — первое что в голову пришло). У меня на это ушло порядка 250 тыс. тактов. Это 75 микросекунд. Даже не миллисекунда. Если ты провалишься в ядро 1 млн раз (при чтении блоками по 64 Кб можно прочитать 64 Гб) — это займёт 75 миллисекунд. Ты заметишь это время хоть как-то? На фоне того, сколько потребуется на чтение такого файла (даже с суперскоростного NVME) и его обработку? :)
Anonymous
Кстати, 75 м\с это довольно много...
Eugene
75 наносекунд 1 вызов функции.
Eugene
Если ты выполняешь высокопроизводительные многопоточные вычисления (длиной в несколько дней, месяцев, лет), то это, безусловно, много, не спорю :)
Eugene
Но есть ли смысл оптимизировать это для данной задачи? :) Тем более ценой пожирания памяти (что может в итоге вылиться в замедление).
Anonymous
Мне кажется, есть, опять же с правильным использованием — с рассчётом на размер файла. Если не слишком большой и есть возможность выделить — так и сделать, и считать сразу весь файл, после чего 3-5 тактов обращение к выделенной памяти. Если нет — разделить на блоки, один раз выделить нужный размер памяти, и считывать туда блоками.
Aiwan \ (•◡•) / _bot
как вашу беседу перенести на msdos?
Anonymous
как вашу беседу перенести на msdos?
😄Я лично уже давно не про MS-DOS
Eugene
Мне кажется, есть, опять же с правильным использованием — с рассчётом на размер файла. Если не слишком большой и есть возможность выделить — так и сделать, и считать сразу весь файл, после чего 3-5 тактов обращение к выделенной памяти. Если нет — разделить на блоки, один раз выделить нужный размер памяти, и считывать туда блоками.
Надо смотреть ещё на то, что там за парсинг. Нет ли прыжков назад или ещё чего. Или, может, там насколько всё медленно парситься будет, что обсуждать это нет смысла. А может, чересчур быстро. И объёмы такие (или кол-во файлов), что ускорение на доли секунды в итоге выльется в сутки.
Eugene
как вашу беседу перенести на msdos?
Да никак. Мы ж не отвечаем уже, а просто рассуждаем :)
Edem
спасибо всем за информацию!
s54820
В первом случае память не бережётся, зато быстрее, установлен приоритет для своего же кода. Во втором случае бережётся память, но намного медленнее.
Мы отлично можем посчитать, кто быстрее. Чтобы съесть мегабайт, нам нужно 256 page faults, от них никуда не деться — получили page fault, идём в ядро обрабатывать. Соответственно, даже для каких-нибудь минимальных 32к кусков ReadFile будет быстрее, чем тупое чтение замапленного файла. Я потестировал, так оно и получается для последовательного чтения. А вот если у нас формат файла предполагает беготню по всему файлу, чтение по нескольку раз, или нам с кусками фиксированного размера сложно работать, тогда уже маппинг спасает. И код проще. Ну пока файл не на флешке, которая может внезапно пропасть и всё уронить.
Eugene
Кстати, интересно было бы реально потестить это дело.
Eugene
С результатами измерений скорости.
s54820
Ну уж я не думаю, что винда читает по 4 Кб. Наверняка по 64 Кб или типа того. Но page fault могут тормозов добавить, по логике - это да.
Читает-то она крупными кусками, а вот страницы маппит при первом обращении. Вот я читаю файл, прочитал гигабайт: At 1010 MiB: page faults total: 260434, 257 faults per MiB, working set 1041920 KiB, вон даже «лишний» фолт вылез откуда-то.
Eugene
@IvUyr, включи реакции, плиз.
Eugene
Если это в твоей власти 😈
Eugene
Зачем?
Дополнительный инструмент коммуникации. Плюс вместо насильно информативных слов типа "класс", "согласен", "ещё раз спасибо" (или чем промолчать) можно поставить реакцию и всё.
Eugene
Или листая длинную переписку, в которую не хочется вчитываться, можно зацепиться за 👍 (что значит, что там вероятно есть что-то толковое) и остановиться, почитать.
Anonymous
Итак, GCC 11.2.0 Без оптимизации, -m32 Первый вариант — получение размера всего файла, выделение памяти и чтение сразу в память, после чего обработка (поиск 0x01, который находится в самом конце файла). Файл весит 1 ГБ. Скорость выполнения кода (внутренний clock, сек.): 4.743380 Общее кол-во выполненных инструкций: 10,737,601,977 Данные по кэшу: I1 misses: 1,438 LLi misses: 1,420 I1 miss rate: 0.00% LLi miss rate: 0.00% D refs: 6,442,528,090 (6,442,504,347 rd + 23,743 wr) D1 misses: 16,778,976 ( 16,778,688 rd + 288 wr) LLd misses: 16,778,721 ( 16,778,453 rd + 268 wr) D1 miss rate: 0.3% ( 0.3% + 1.2% ) LLd miss rate: 0.3% ( 0.3% + 1.1% ) LL refs: 16,780,414 ( 16,780,126 rd + 288 wr) LL misses: 16,780,141 ( 16,779,873 rd + 268 wr) LL miss rate: 0.1% ( 0.1% + 1.1% ) Второй вариант — получение размера, разделение его на блоки по 10 МБ, чтение+обработка. 1 ГБ / 10 МБ = 102 итераций (чтений) + проверка на кратность, и подброс оставшихся байт Скорость выполнения кода (внутренний clock, сек.): 4.861692 Общее кол-во выполненных инструкций:9,668,078,565 I1 misses: 1,446 LLi misses: 1,428 I1 miss rate: 0.00% LLi miss rate: 0.00% D refs: 5,372,994,835 (5,372,965,524 rd + 29,311 wr) D1 misses: 16,780,106 ( 16,779,511 rd + 595 wr) LLd misses: 16,779,854 ( 16,779,279 rd + 575 wr) D1 miss rate: 0.3% ( 0.3% + 2.0% ) LLd miss rate: 0.3% ( 0.3% + 2.0% ) LL refs: 16,781,552 ( 16,780,957 rd + 595 wr) LL misses: 16,781,282 ( 16,780,707 rd + 575 wr) LL miss rate: 0.1% ( 0.1% + 2.0% )
Anonymous
Данные по поводу скорости выполнения каждый раз рознятся. После запуска первого, на втором варианте уже намного быстрее обрабатывается, и наоборот. Пытался как-то сбивать данные, чтобы по-честному всё было.
Anonymous
(Внутри версий уже стоит clock(), можете создать файл на 1 гб и запустить у себя, в конце покажет скорость выполнения)
Anonymous
disba1ancer
К тому же, скорость операции физического чтения с диска ни в какое сравнение не идёт с проваливанием в ядро или вызовом прерывания.
вот только надо ещё подумать над тем а умеет ли dos в dma, а точнее более производительные режимы, чем чтение через порты ввода вывода
disba1ancer
Так вроде MapView как раз и позволяет выделить сразу весь файл в память
он всего лишь настраивает адресное пространство процесса, а фактическая операция скорее всего происходит по запросу