This commit is contained in:
2026-08-27 07:13:23 +03:00
parent 87b588f63e
commit 9e9c99fc2b
+59 -6
View File
@@ -291,7 +291,7 @@ O(C+s_P+s_R)+O\bigl(d\max(p,r)\bigr)+O(p+r),
\section{Оптимизации с сохранением текущего формата}
\label{COMPATIBLE_OPTIMIZATIONS}
Для проверки направлений оптимизации была создана экспериментальная реализация \texttt{set9.c}. Она сохраняет Jenkins OAAT, формат заголовка, Golomb--Rice/Base62-представление и пять функций публичного API. Поэтому сформированные ею строки побайтово совместимы с исходной реализацией, а изменения относятся только к внутренним структурам и алгоритмам.
Для проверки направлений оптимизации была создана экспериментальная реализация \texttt{set9.c} [\Ref{SET9}]. Она сохраняет Jenkins OAAT, формат заголовка, Golomb--Rice/Base62-представление и пять функций публичного API. Поэтому сформированные ею строки побайтово совместимы с исходной реализацией, а изменения относятся только к внутренним структурам и алгоритмам.
Помимо оптимизации сравнения, построение множества было переведено с отдельных \texttt{xstrdup()} для каждого имени на общую растущую строковую арену. В массиве элементов хранятся смещения, которые остаются корректными после \texttt{xrealloc()} арены. Кодирование и декодирование выполняются потоково: дельты, состояния Голомба--Райса и Base62 обрабатываются через 64-битный аккумулятор без отдельных массивов битов и дельт.
@@ -398,7 +398,7 @@ K_{\mathrm{CPU}}=
\subsection{Roaring Bitmap: отрицательный результат}
Roaring Bitmap предназначен прежде всего для множеств, содержащих плотные участки целочисленного пространства. Усечённые хеши, напротив, распределены по диапазону приблизительно равномерно. Поэтому контейнеры bitmap не получают длинных серий соседних значений, но сохраняют собственные заголовки и индексы.
Roaring Bitmap [\Ref{ROARING}] предназначен прежде всего для множеств, содержащих плотные участки целочисленного пространства. Усечённые хеши, напротив, распределены по диапазону приблизительно равномерно. Поэтому контейнеры bitmap не получают длинных серий соседних значений, но сохраняют собственные заголовки и индексы.
В микротесте использовались 1000 предоставляемых и 500 требуемых символов при $b=32$. Результаты приведены в табл.~\Ref{ROARING_RESULTS}. Коэффициенты времени вычислены относительно \texttt{set9.c}; значение больше единицы означает замедление.
@@ -422,11 +422,11 @@ Roaring+zstd & 14\,126 & 4,96 & 101,86 \\
Без дополнительного сжатия строка оказалась длиннее в 4,99 раза. Холодное сравнение заняло 1321,17 мкс вместо 293,87 мкс, а прогретое --- 399,20 мкс вместо 5,24 мкс. При этом построение bitmap занимало лишь $0,76$ времени \texttt{set\_fini()} варианта \texttt{set9}; ускорение генерации не компенсировало стоимость хранения и сравнения.
Сжатие zstd уменьшило строку до 14\,126 символов, то есть до 3,54 длины \texttt{set9}, но добавило декомпрессию в горячий путь. В отдельном прогоне холодное и прогретое сравнения были медленнее соответственно в 4,96 и 101,86 раза. Таким образом, Roaring Bitmap для равномерных хешей является подтверждённым отрицательным вариантом: структура данных не соответствует распределению кодируемых значений.
Сжатие zstd [\Ref{ZSTD}] уменьшило строку до 14\,126 символов, то есть до 3,54 длины \texttt{set9}, но добавило декомпрессию в горячий путь. В отдельном прогоне холодное и прогретое сравнения были медленнее соответственно в 4,96 и 101,86 раза. Таким образом, Roaring Bitmap для равномерных хешей является подтверждённым отрицательным вариантом: структура данных не соответствует распределению кодируемых значений.
\subsection{Прямые хеши в Base64}
Другой вариант, обозначенный как D1, исключает дельты и код Голомба--Райса. $n$ отсортированных уникальных хешей записываются подряд по $b$ бит, после чего битовый массив преобразуется в Base64-строку. Если
Другой вариант, обозначенный как D1, исключает дельты и код Голомба--Райса. $n$ отсортированных уникальных хешей записываются подряд по $b$ бит, после чего битовый массив преобразуется в Base64-строку [\Ref{BASE64}]. Если
\[
Q=\left\lceil\frac{nb}{8}\right\rceil
\]
@@ -461,7 +461,7 @@ L_{\mathrm{payload}}=
\subsection{Альтернативные хеш-функции}
Отдельно сравнивались Jenkins OAAT, xxHash32 и CityHash32. Сравнение было необходимо, так как xxHash и CityHash --- хэш функции, разработанные значительно позже последнего обновления \texttt{set.c}. В каждом замере использовались три запуска; в табл.~\Ref{HASH_SPEED} приведены медианы. Для коротких строк указано время одного хеширования, для длинных --- пропускная способность.
Отдельно сравнивались Jenkins OAAT, xxHash32 [\Ref{XXHASH}] и CityHash32 [\Ref{CITYHASH}]. Сравнение было необходимо, так как xxHash и CityHash --- хеш-функции, разработанные значительно позже последнего обновления \texttt{set.c}. В каждом замере использовались три запуска; в табл.~\Ref{HASH_SPEED} приведены медианы. Для коротких строк указано время одного хеширования, для длинных --- пропускная способность.
\begin{table}[H]
\begin{center}
@@ -483,7 +483,7 @@ CityHash32 & 16,70 & 4,10 \\
На строках длиной 32 байта xxHash32 был быстрее Jenkins примерно в 4,4 раза, CityHash32 --- в 3,1 раза. При 1024 байтах различие по пропускной способности достигало соответственно 9,8 и 7,7 раза. Следовательно, Jenkins OAAT не является оптимальным по скорости, особенно на длинных входах.
Для оценки качества использовался другой тест, в нём сравнивались Jenkins OAAT, 64-битный xxHash и \texttt{t1ha2\_atonce};. Поскольку формат \texttt{set:version} сохраняет не более 32 бит хеша, при сопоставлении учитывались младшие 32 выходных бита всех трёх функций.
Для оценки качества использовался другой тест, в нём сравнивались Jenkins OAAT, 64-битный xxHash и \texttt{t1ha2\_atonce} [\Ref{T1HA}]. Поскольку формат \texttt{set:version} сохраняет не более 32 бит хеша, при сопоставлении учитывались младшие 32 выходных бита всех трёх функций.
Тест измерял лавинный эффект на реальном корпусе экспортируемых C++-символов ALT Linux p11. Утилита \texttt{provided\_symbols} извлекла из 259 ELF-файлов пяти пакетов 577\,509 уникальных имён. Пакеты выбирались среди имеющих наиболее длинные \texttt{Provides set:}-строки. Корпус специально является сложным для хеширования похожих строк: 99,60\% символов имеют с другим символом общий префикс длиной не менее 12 знаков, 95,05\% --- не менее 24 знаков, а медиана максимального общего префикса равна 61 знаку.
@@ -528,8 +528,61 @@ ALT RPM source code, 2010--2012.
\item
\Label{JENKINS}
Jenkins B.
\emph{A Hash Function for Hash Table Lookup}.
1997, обновлено в 2013 г.
[Электронный ресурс] URL: \url{https://burtleburtle.net/bob/hash/doobs.html}.
\item
\Label{GOLOMB-RICE}
Wikipedia contributors.
\emph{Golomb coding: описание кодов Голомба и Райса}.
[Электронный ресурс] URL: \url{https://en.wikipedia.org/wiki/Golomb_coding}.
\item
\Label{SET9}
Гудов Д.О.
\emph{set9.c --- экспериментальная реализация алгоритмов set:version}.
Исходный код на GitHub.
[Электронный ресурс] URL: \url{https://github.com/kr0sh512/alt-rpm-set-version/blob/main/reimplement/set9.c}.
\item
\Label{ROARING}
RoaringBitmap.org.
\emph{Roaring Bitmaps --- A better compressed bitset}.
[Электронный ресурс] URL: \url{https://roaringbitmap.org/}.
\item
\Label{BASE64}
Josefsson S.
\emph{The Base16, Base32, and Base64 Data Encodings}. RFC~4648, 2006.
[Электронный ресурс] URL: \url{https://www.rfc-editor.org/info/rfc4648}.
\item
\Label{ZSTD}
Collet Y., Kucherawy M.
\emph{Zstandard Compression and the application/zstd Media Type}. RFC~8878, 2021.
[Электронный ресурс] URL: \url{https://www.rfc-editor.org/info/rfc8878}.
\item
\Label{XXHASH}
Collet Y.
\emph{xxHash --- extremely fast non-cryptographic hash algorithm}.
Исходный код и документация.
[Электронный ресурс] URL: \url{https://github.com/Cyan4973/xxHash}.
\item
\Label{CITYHASH}
Google.
\emph{CityHash --- a family of hash functions for strings}.
Исходный код и документация.
[Электронный ресурс] URL: \url{https://github.com/google/cityhash}.
\item
\Label{T1HA}
Erthink.
\emph{t1ha --- Fast Positive Hash}.
Исходный код и документация.
[Электронный ресурс] URL: \url{https://gitflic.ru/project/erthink/t1ha}.
\end{enumerate}