| Qt: quint64, сектор и жопа (14.08.2025). |
|
| 2025 - Август | |||
| 14.08.2025 11:29 | |||
Пусть есть QDataStream. Успешно в файл записывается большое число, quint64: 18.446.743.798.831.644.672. После закрытия файла, открытия файла, чтения потоком - успешно и корректно читается. Между тем, начав читать данные вне файловой системы (секторы жёсткого диска), при помощи QByteArray, - исходное число никак не находилось: - даже после преобразования QByteArray.toHex().toULongLong(&bOk, 16) - с которым пришлось изрядно попотеть при создании и удостовериться, что конструкция работает как надо; - грешил именно на ошибки в чтении: сектор мог представлять не 512Б, а 517Б (+4Б на контрольную сумму сектора и что-то в начале ещё есть из служебной информации); - дополнительно этому мешала зона MFT и загрузочная зона MBR: их чтение не давало возможности даже пытаться определить искомое число в первых секторах носителя. Далее было принято решение писать в файл много больших чисел, постоянно растущих на единицу (прибавляя к исходному числу в цикле): - чтение дало повторяющийся результат: из 512Б сектора читалось 3 числа, больше искомого, в постоянных местах сектора (условно, 88-й, 120-й и какой-то там ещё номера байтов). Тоже какая-то дичь - но уже лучше; - укрепляется мысль, что проблема в алгоритме чтения, - и среди прочего дело не в LittleEndian и BigEndian. Это мнение было ровно до тех пор, пока не дошло посмотреть записанные биты в файл с помощью HEX-редактора HxD в Windows: - редактор имеет удобное представление битов в привычные типы данных; - тут-то шок и настал. uint64 (без q): вместо 18446743798831644672 - было 18446743936270598144 (FF FF FF E0 00 00 00 00); - без HEX-редактора эту незначительную разницу чисел, близкую к триллиону, глазами видно не было при просматривании файла, например, в Vim. Поток QDataStream, независимо от указываемой версии с помощью .setVersion(QDataStream::Qt_x_xx): записывает q unsigned int 64 - неправильно. Эта же ошибка имеется при считывании - поэтому никак не ощущается, пока используешь идентичные механизмы записи и считывания (потоком). Из этого также следует, что если файл потом будет считываться другим языком программирования, - может наступить жопа. Посмотрев на всё это дело, было приняты радикальные решения: - почти полностью заполнить жёсткий диск одним файлом со 125.012.049.920 уникальными записанными quint64 с разницей в единицу (не затрагивая зону MFT). Тут Astra вставляет свои 5 копеек багов: с драйвером ntfs3 жёсткий диск не заполняется до конца, оставляя 6400КБ свободного места, которое невозможно записать даже во fly-fm и текстовыми редакторами (при этом, если в Windows открыть - можно продолжить забивать диск до отказа, насоздавав файлов или копируя чего). Переключение на старый драйвер ntfs: замедлило скорость жёсткого диска до ~30МБ/с - но баг с заполнением ушёл, и диск забился до отказа; - считывать так же потоком: открыв само устройство /dev/sda - как файл только для чтения; - не привязываться к размеру сектора (он всегда делится на 8). Тупо читать 125.025.247.232 раза по 8 байтов, исходя из размера носителя; - где-то на трехмиллионной итерации: сработало условие, что число >= 18446743798831644672. Не показатель - однако такие числа стали увеличиваться на 1, с увеличением итерации на 1. Значит, чтение происходит корректно: попал в сектор близко к физическому началу диска, являющийся частью кластера ФС ближе к виртуальному концу файла (фрагментацию виртуальных кластеров по физической поверхности диска - никто не отменял). И, в рамках всех 64КБ кластера (состоящего из 128 последовательно идущих секторов): числа точно увеличиваются на 1 - начиная с начальных 8 байтов. Ещё тест будет вне темы: попытаться в Astra забить весь диск 1ТБ целиком, вместе с полным затиранием зоны MFT. Однако это далеко не конец: нужно убедиться, что все числа уникальные и в наличии на диске вне ФС. Значит, потребуется массив bool размерностью >125.025.247.232 (ещё есть загрузочная зона MBR, её бы посмотреть отдельно) - и где-то надо взять 128ГБ RAM. Или организовать чтение диска 8 раз подряд, анализируя числа массивами по 16ГБ, - при условии наличия 16ГБ RAM (а значит, SWAP будет использоваться по-полной - что ещё более замедлит анализ). (добавлено 15.08.2025) Проблема QDataStream тянется ещё с 2018 года. (добавлено 17.08.2025) Проверка 140ГБ данных из 1ТБ - заняла 3 суток. Здесь всё смешалось: и неоптимизированный алгоритм проверки (что 8 байтов содержат именно записанные ранее данные), и тормознутость HDD (драйвер ntfs Astra), и отсутствие многопоточности (нельзя: головки сломаются от фрагментированной нагрузки - это применимо только к SSD). Однако получены интересные результаты: - было выделено 12ГБ RAM под массив bool 12млрд переменных: проверка первых 96ГБ данных из 1ТБ (~125млрд переменных); - Astra опять заглючила: спустя сутки - выключила все USB-носители - ни мышь не работает, ни клавиатура. Она так ранее подключенную к виртуалке салазку спалила: внезапное вырубание питания спустя какое-то время - при условии, что на носителе салазки была максимальная нагрузка как передача данных; - подключив стороннюю мышь, удалось полазить по исходникам, переменным и остановам. Изначально, информация в самом начале диска началась не с единицы, как предполагалось, - а со 109млрд. До последнего момента были опасения, что считывание происходит неверно, - однако примерно со 129ГБ данных прочиталась эта самая единица. И так же последовательно данные увеличивались на 1, как и с отметки 109млрд. То есть, контроллер HDD (глючный драйвер ntfs?) намеренно фрагментирует данные по поверхности диска; - это можно использовать. Когда проверка HDD полностью завершится, и в огромном массиве не найдётся ни одной ячейки с false (все данные найдены успешно) - можно загрузиться с WinPE и посмотреть, как Defraggler видит этот файл, размером с весь диск. Огромная вероятность, что любой дефрагментатор покажет, что файл не фрагментирован. То есть, контроллеру всё равно: считать сектора 1-2-3-4 или 4-2-1-3: главное, чтобы между ними сторонних данных не было; - формируются абсолютно чёткие выводы. Если вы устраиваетесь на работу как сисадмин, и там стоит Astra везде, - бегите. Если вы устраиваетесь на работу как программист, и там стоит Qt, - нужно 100 раз подумать; а если связка Astra+Qt - бегите. А если миграция с Windows на Astra - бегите, галопом, независимо от специальности: ещё и исходники мигрировать заставят. (добавлено 18.08.2025) Выборочно копируя числа из переменных с помощью второй мыши (клавиатура и мышь-то до сих пор вырублены ОС) - удалось проверить разные места массива с bool. Все true - остановился на считанных ~250ГБ. Многопоточность для HDD, без его механического износа, - можно было бы обеспечить, если бы RAM было >16ГБ. Считыванием сразу огромной части данных последовательно в условный глобальный массив [1ГБ][7шт] - и разбрасыванием массива по 7 оставшимся ядрам процессора. Как только все данные будут проверены - 7 переменных bool должны стать true (признак окончания обработки) - загрузить ещё 14ГБ нулевым ядром. При текущем уровне RAM - это невозможно за 1 проход диска (требуется ~137ГБ RAM). Разве что: 8млрд данных проверять за 1 проход - но тогда потребуется 16 проходов по диску (всему или частично); и неизвестно, что ещё займёт больше времени. Также был обнаружено паразитное true в массиве с bool: в зоне MFT случайно оказалось одно 8-байтное число, удовлетворяющее обеим условиям: содержит в себе нужный паттерн (вычурную комбинацию старших битов) и корректное число (меньшее, чем 125млрд). В итоге, в массиве bool одна из ячеек оказалась перезаписана true дважды. Очередной совместный баг астры и Qt: нельзя открыть носитель больше 1014 раз. Свойство было замечено ранее, просто забыто и не описано: когда диск открывался не с помощью QFile, а через fcntl.h, - и в файле присутствовала функция open, а close отсутствовала. (добавлено 19.08.2025) Полностью подтверждённая проверка, что чтение и запись работают корректно: автоматическая проверка всего массива bool - ни одного false (начал писать данные с 0, а не с 1). Это стало доступным после ускорения алгоритма работы - без использования многопоточности: - выведение первого ядра процессора на максимум скорости 4.3ГГц, жертвуя работоспособностью других ядер на аппаратном уровне; - вспоминая Borland: ни функции математики, ни стринги не были в нём медлительными - что позволяло в дебаг ставить текстовые переменные для удобства отладки. В случае с Qt: либо pow, либо QString::mid, либо QString:contains, либо все 3 - оказались чрезвычайно медленными. Когда отображение паттерна в текстовом виде было исключено - скорость 0.55МБ/с сменилась на максимум жёсткого диска NTFS в Astra ~30МБ/с. Это даёт возможность проверять 16млрд данных за ~4ч и все данные за ~32ч. Теперь надо забить диск вообще целиком, игнорируя зону MFT и сократив её до 0: чтобы проверить, лезет ли чтение в MBR. (добавлено 20.08.2025) Забивание диска целиком - дало не те результаты, что хотелось: - дефрагментатор видит файл+MFT как разбитый на 5 частей и фрагментированный. Но если файл забивает вообще весь диск (MFT = 0Б) - файл дефрагментирован только на 4 части; - так как MFT при заполнении стремится к 0Б - свободное место при пустом разделе, на ~105МБ меньшее, - обманка; - в разных ОС форматирование в NTFS происходит по-разному: влияют ОС и её версия, драйвер NTFS и его версия, ФС NTFS и её версия. Разница разделов между Windows 11 и Astra составляет ~1.5МБ; - разница между размером раздела и размером носителя составляет ~2.9МБ; - даже если раздел забит вообще полностью - каким-то макаром, Windows создаёт на нём $RECYCLE.BIN. Либо с прошлой загрузки ОС забыл удалить - либо это какой-то ярлык, не привязанный к кластерам раздела; - при этом, дефрагментатор показывает одну ячейку диска занятую чем-то другим, в самом начале: все "файлы" там представлены с $ в начале названия. Это зона обслуживания раздела NTFS - но неясно, есть ли там MBR; - чтение полезных данных, при полностью забитом диске, - начинается с 37.289.984Б. Значит, точно MBR в этом объёме данных есть. О тормознутости QString::contains писалось ещё в 2024 году, по Qt v.5.3 2014 года выпуска, - за 11 лет ничего не изменилось. (добавлено 01.10.2025) Выкладываю собственные исходники (775КБ), чисто для примера - не до конца законченные, не до конца отлаженные, но исправно работающие. Проект на Qt v.5.15.2 под Linux. |
|||
| Обновлено ( 01.10.2025 19:03 ) |