From 4d7405283a15cfb531f000ff9aacc64426513a3b Mon Sep 17 00:00:00 2001 From: Olivier Giniaux Date: Fri, 13 Oct 2023 09:36:28 +0200 Subject: [PATCH] Fix some typos --- README.md | 2 +- article/article.pdf | Bin 2980446 -> 2980968 bytes article/article.tex | 15 +++++++-------- article/references.bib | 7 +++++++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 432a495..eb2e36b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # gxhash-rust ![CI](https://github.com/ogxd/gxhash-rust/actions/workflows/rust.yml/badge.svg) -The fastest non-cryptographic hashing algorithm +Up to this date, the fastest non-cryptographic hashing algorithm ## Publication diff --git a/article/article.pdf b/article/article.pdf index f4f43a9812e1a07680f9db70fe265aae712681d2..9bedac698b76065e42fb3516f1ef05b610155d06 100644 GIT binary patch delta 30866 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 W4=>C;*hLD+ZQ3<5a_Fv^uKxobC0HE* diff --git a/article/article.tex b/article/article.tex index 0b3fc9e..5cf1896 100644 --- a/article/article.tex +++ b/article/article.tex @@ -22,7 +22,7 @@ In the rapidly evolving landscape of data processing and cybersecurity, hashing algorithms play a pivotal role in ensuring data integrity and security. Traditional hashing methods, while effective, often fail to fully utilize the computational capabilities of modern processors. -This paper introduces the GxHash hashing algorithm, a novel approach that harnesses the power of high instruction-level parallelism (ILP) and Single Instruction, Multiple Data (SIMD) capabilities of contemporary CPUs to achieve high-throughput non-cryptographic hashing. Through a comprehensive analysis, including benchmarks and comparisons with existing methods, we demonstrate that GxHash significantly outperforms conventional algorithms in terms of speed and computational efficiency without compromising on security. The paper also explores the implications, limitations, and avenues for future research in this burgeoning field. +This paper introduces the GxHash hashing algorithm, a novel approach that harnesses the power of high Instruction-Level Parallelism (ILP) and Single Instruction, Multiple Data (SIMD) capabilities of contemporary CPUs to achieve high-throughput non-cryptographic hashing. Through a comprehensive analysis, including benchmarks and comparisons with existing methods, we demonstrate that GxHash significantly outperforms conventional algorithms in terms of speed and computational efficiency without compromising on security. The paper also explores the implications, limitations, and avenues for future research in this burgeoning field. \end{abstract} @@ -36,7 +36,7 @@ \section{Introduction} \subsection{Motivations} As a software engineer at Equativ, a company specializing in high-performance AdServing backends that handle billions of auctions daily, -I face unique challenges in maximizing throughput while minimizing latency. In this high-stakes environment, every millisecond counts, and the performance of underlying data structures becomes critically important. We heavily rely on in-memory caches and other hash-based data structures, making the efficiency of hashing algorithms a non-trivial concern in our system's overall performance.\\\\ +I face unique challenges in maximizing throughput while minimizing latency. In this high-stakes environment, every millisecond counts, and the performance of underlying data structures becomes critically important. As we heavily rely on in-memory caches and other hash-based data structures, making the efficiency of hashing algorithms a non-trivial concern in our system's overall performance.\\\\ While diving into the theory of hashing out of both necessity and intellectual curiosity, I discovered that existing hashing algorithms, including those built on well-known constructions like Merkle–Damgård, are not optimized to exploit the full capabilities of modern general-purpose CPUs. These CPUs offer advanced features such as Single Instruction, Multiple Data (SIMD) and Instruction-Level Parallelism (ILP), which remain largely untapped by current hashing methods.\\\\ The challenge of creating a faster, more efficient hashing algorithm became not just a professional necessity but also a personal quest. @@ -484,9 +484,7 @@ \subsubsection{Benchmark Quality Criteria} \subsubsection{Quality Results} -While we can compute quality metrics, the result will greatly vary depending on the actual inputs used for our hash function. Let's see how the GxHash0 algorithm qualifies against a few well-known non-cryptographic algorithms in a few scenarios. - -For comparison, we'll also include qualification results for a few other popular non-cryptographic hash algorithms such as: +While we can compute quality metrics, the result will greatly vary depending on the actual inputs used for our hash function. Let's see how the GxHash0 algorithm qualifies in specific scenarios against some well-known non-cryptographic algorithms, such as: \begin{itemize} \item \textbf{HighwayHash}\cite{highwayhash} The latest non-cryptographic hash algorithm from Google Research @@ -540,7 +538,7 @@ \subsubsection{Quality Results} Where \(n\) is the number of samples and \(m\) is the number of possible values. When \(n=1000000\) and \(m=2^{32}\) we obtain 0.0116\%. You can see that this value closely matches most of the collision rates benchmarked. This is because the generated hashes are of 32-bit size, thus naturally colliding at this rate. For inputs of size 4, the inputs themselves are also likely to collide with the same odds (because inputs are randomly generated). For this reason, the collision rate is expected to be about 2 \(\times\) 0.0116\%. -We can see however that CRC and XxHash have lower odds of collisions for 4 bytes input, which can be explained by a size-specific logic to handle small inputs bijectively. +We can see however that CRC and XxHash\cite{xxhash} have lower odds of collisions for 4 bytes input, which can be explained by a size-specific logic to handle small inputs bijectively. \begin{figure}[H] \centering @@ -684,11 +682,12 @@ \subsubsection{Compiler Dependencies} \subsection{Future Work} Despite the outstanding benchmark results, we think there are still many possible paths for research and improvement. Here is a non-exhaustive list: \begin{itemize} - \item Leveraging larger SIMD intrinsics, such as Intel AVX-512 or ARM SVE2. - \item Using leading zero count intrinsics followed by a C-style fallthrough to process small inputs faster. + \item Leverage larger SIMD intrinsics, such as Intel AVX-512 or ARM SVE2. + \item Use leading zero count intrinsics followed by a C-style fallthrough to process small inputs faster. \item Rewrite the algorithm in assembly code or a language that is more explicit about registers. \item Introduce more than one stage of laning. For instance 16 lanes, then 8 lanes, then 4 lanes, and finally 2 lanes, to leverage ILP as much as possible. \item Fine-tune the finalization stage to find the perfect balance between performance and avalanche effect. + \item Run GxHash0 against more quality benchmarks, such as SMHasher\cite{smhasher}. \end{itemize} \section{Conclusion} diff --git a/article/references.bib b/article/references.bib index c255b0f..9b183cf 100644 --- a/article/references.bib +++ b/article/references.bib @@ -66,4 +66,11 @@ @software{highway-rs url = {https://github.com/nickbabcock/highway-rs}, note = {v1.1.0}, version = {1.1.0} +} + + +@software{smhasher, + author = {Reini Urban}, + title = {github.com/rurban/smhasher}, + url = {https://github.com/rurban/smhasher} } \ No newline at end of file