" title="Написать письмо">Написать письмо
Донаты на карту ВТБ:
2200 4002 2461 6363

Статистика

Пользователи : 1
Статьи : 2374
Просмотры материалов : 9137302
 
Qt: quint64, сектор и жопа (14.08.2025). Печать E-mail
2025 - Август
14.08.2025 11:29
Save & Share
Чем отличилась Qt производства Великобритании: насоздавали своих классов. Не String, а QString; не int64, а qint64, - и утверждалось, что это классы-синонимы по своему функционалу и структуре. Ну вот и досоздавались: это не так. Astra Linux SE v.1.7.4.0(7) и Qt v.5.15.2: недружественные к IT-специалисту ОС и среда разработки - привели к очередным танцам с бубном: при работе с жёстким диском, минуя файловую систему.


Пусть есть 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 )
 
 

Последние новости


©2008-2026. All Rights Reserved. Разработчик - " title="Сергей Белов">Сергей Белов. Материалы сайта предоставляются по принципу "как есть". Автор не несет никакой ответственности и не гарантирует отсутствие неправильных сведений и ошибок. Вся ответственность за использование материалов лежит полностью на читателях. Размещение материалов данного сайта на иных сайтах запрещено без указания активной ссылки на данный сайт-первоисточник (ГК РФ: ст.1259 п.1 + ст.1274 п.1-3).

Много статей не имеет срока устаревания. Есть смысл смотреть и 2011, и даже 2008 год. Политика сайта: написать статью, а потом обновлять ее много лет.
Рекламодателям! Перестаньте спамить мне на почту с предложениями о размещении рекламы на этом сайте. Я никогда спамером/рекламщиком не был и не буду!
Top.Mail.Ru