This commit is contained in:
greg
2019-03-03 20:14:10 -05:00
parent 519bfd70ce
commit 30f0a31023
4 changed files with 11 additions and 22 deletions
Vendored
+6 -8
View File
@@ -1,9 +1,7 @@
# The Parallel Hashmap
or Abseiling from the shoulders of giants - © Gregory Popovitch - March 3, 2019
[tl;dr] built on top of Abseil's flat_hash_map, the parallel flat_hash_map is
more memory friendly, and can be used from multiple threads with high levels of
concurrency
[tl;dr] built on top of Abseil's flat_hash_map, the parallel hashmap is more memory friendly, almost as fast as the underlying flat_hash_map, and can be used from multiple threads with high levels of concurrency.
### A quick look at the current state of the art
@@ -78,11 +76,11 @@ But what about the speed? After all, for each value inserted into the parallel h
2. compute the index of the target sub-table from the hash)
3. insert the value into the sub-table
The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in Matt Godbolt's compiler explorer):
The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in *Matt Godbolt*'s compiler explorer):
![index computation cost](https://github.com/greg7mdp/parallel-hashmap/blob/master/img/idx_computation_cost.PNG?raw=true)
As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the sub-table functions, so that it is computed only once. This is exactly what I have done in my implementation pof the parallel_hash_map withing the Abseil library, adding a few extra APIs to the Abseil internal raw_hash_map.h header,= which allow the parallel_hash_map to pass the precomputed hash value to the underlying hash tables.
As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the sub-table functions, so that it is computed only once. This is exactly what I have done in my implementation pof the parallel_hash_map within the Abseil library, adding a few extra APIs to the Abseil internal raw_hash_map.h header,= which allow the parallel_hash_map to pass the precomputed hash value to the underlying hash tables.
So we have all but eliminated the cost of the first step, and seen that the cost of the second step is very minimal. At this point we expect that the parallel_hash_map performance will be close to the one of its underlying flat_hash_map, and this is confirmed by the chart below:
@@ -181,17 +179,17 @@ Still, this is a pretty good result, we are now inserting values into our parall
### In Conclusion
We have seen that the novel parallel hashmap approach, used withing a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a time benefit by drastically reducing (or even eliminating) lock contention when accessing the parallel hashmap.
We have seen that the novel parallel hashmap approach, used within a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a time benefit by drastically reducing (or even eliminating) lock contention when accessing the parallel hashmap.
### Thanks
I would like to thank Google's Matt Kulukundis for his excellent presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_map_map. Also many thanks to the Abseil container developers - I believe the main contributors are Alkis Evlogimenos and Roman Perepelitsa - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son Andre for reviewing this paper, and for his patience when I was rambling to him about the parallel_hash_map and all its benefits.
I would like to thank Google's *Matt Kulukundis* for his excellent presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_map_map. Also many thanks to the Abseil container developers - I believe the main contributors are *Alkis Evlogimenos* and *Roman Perepelitsa* - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son *Andre* for reviewing this paper, and for his patience when I was rambling to him about the parallel_hash_map and all its benefits.
### Links
[github repository for the benchmark code used in this paper](https://github.com/greg7mdp/parallel-hashmap)
[Github repository for the benchmark code used in this paper](https://github.com/greg7mdp/parallel-hashmap)
[Swiss Tables doc](https://abseil.io/blog/20180927-swisstables)
+1 -10
View File
@@ -24,10 +24,7 @@ SRC = parallel_hashmap.md
OBJ = $(SRC:.md=.html)
all: pdf
img/%.png: img/%.pdf
convert -density 150 $< $@
all: html
includes.exe: includes.hs
stack exec ghc -- -o $@ -no-keep-hi-files -no-keep-o-files includes.hs
@@ -38,15 +35,9 @@ html: ../README.md $(FILTER) ${TEMPLATE_HTML} ${STYLE}
%.pdf: %.md $(FILTER) ${TEMPLATE_TEX}
$(PANDOC) ${FILTER_OPT} ${IFORMAT} ${TEX_OPT} $(FLAGS) -o $@ $<
%.epub: %.md $(FILTER)
$(PANDOC) ${FILTER_OPT} ${IFORMAT} $(FLAGS) -o $@ $<
pdf: $(FILTER) ${TEMPLATE_TEX}
rm -f parallel_hashmap.pdf; $(PANDOC) ${FILTER_OPT} ${IFORMAT} ${TEX_OPT} $(FLAGS) -o parallel_hashmap.pdf title.md $(SRC)
epub: $(FILTER)
$(PANDOC) ${FILTER_OPT} ${IFORMAT} $(FLAGS) ${EPUB_COVER} -o cppi.epub title.md $(SRC)
native:
$(PANDOC) -s -t native $(SRC)
+1
View File
@@ -16,6 +16,7 @@ h1, h2, h3, h4, h5 {
color: #332;
font-family: "Signika";
font-weight: 400;
font-size: 1.4em;
line-height: 1.1;
margin-top: 30px;
}
+3 -4
View File
@@ -8,7 +8,6 @@
<meta name="author" content="">
<link href="http://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<link href="css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="css/colors.css" rel="stylesheet">
@@ -108,7 +107,7 @@
</div>
<h1 id="the-parallel-hashmap">The Parallel Hashmap</h1>
<p>or Abseiling from the shoulders of giants - © Gregory Popovitch - March 3, 2019</p>
<p>[tl;dr] built on top of Abseil's flat_hash_map, the parallel flat_hash_map is more memory friendly, and can be used from multiple threads with high levels of concurrency</p>
<p>[tl;dr] built on top of Abseil's flat_hash_map, the parallel hashmap is more memory friendly, almost as fast as the underlying flat_hash_map, and can be used from multiple threads with high levels of concurrency.</p>
<h3 id="a-quick-look-at-the-current-state-of-the-art">A quick look at the current state of the art</h3>
<p>If you haven't been living under a rock, you know that Google open sourced late last year their Abseil library, which includes a very efficient flat hash table implementation. The absl::flat_hash_map stores the values directly in a memory array, which avoids memory indirections (this is referred to as closed hashing).</p>
<p><img src="https://github.com/greg7mdp/parallel-hashmap/blob/master/img/closed_hashing.png?raw=true" alt="closed_hashing" /></p>
@@ -152,7 +151,7 @@
<li>compute the index of the target sub-table from the hash)</li>
<li>insert the value into the sub-table</li>
</ol>
<p>The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in Matt Godbolt's compiler explorer):</p>
<p>The first step (compute the hash) is the most problematic one, as it can potentially be costly. As we mentioned above, the second step (computing the index from the hash) is very simple and its cost in minimal (3 processor instruction as shown below in <em>Matt Godbolt</em>'s compiler explorer):</p>
<p><img src="https://github.com/greg7mdp/parallel-hashmap/blob/master/img/idx_computation_cost.PNG?raw=true" alt="index computation cost" /></p>
<p>As for the hash value computation, fortunately we can eliminate this cost by providing the computed hash to the sub-table functions, so that it is computed only once. This is exactly what I have done in my implementation pof the parallel_hash_map withing the Abseil library, adding a few extra APIs to the Abseil internal raw_hash_map.h header,= which allow the parallel_hash_map to pass the precomputed hash value to the underlying hash tables.</p>
<p>So we have all but eliminated the cost of the first step, and seen that the cost of the second step is very minimal. At this point we expect that the parallel_hash_map performance will be close to the one of its underlying flat_hash_map, and this is confirmed by the chart below:</p>
@@ -229,7 +228,7 @@
<h3 id="in-conclusion">In Conclusion</h3>
<p>We have seen that the novel parallel hashmap approach, used withing a single thread, provides significant space advantages, with a very minimal time penalty. When used in a multi-thread context, the parallel hashmap still provides a significant space benefit, in addition to a time benefit by drastically reducing (or even eliminating) lock contention when accessing the parallel hashmap.</p>
<h3 id="thanks">Thanks</h3>
<p>I would like to thank Google's Matt Kulukundis for his excellent presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_map_map. Also many thanks to the Abseil container developers - I believe the main contributors are Alkis Evlogimenos and Roman Perepelitsa - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son Andre for reviewing this paper, and for his patience when I was rambling to him about the parallel_hash_map and all its benefits.</p>
<p>I would like to thank Google's <em>Matt Kulukundis</em> for his excellent presentation of the flat_hash_map design at CPPCON 2017 - my frustration with not being able to use it helped trigger my insight into the parallel_map_map. Also many thanks to the Abseil container developers - I believe the main contributors are <em>Alkis Evlogimenos</em> and <em>Roman Perepelitsa</em> - who created an excellent codebase into which the graft of this new hashmap took easily, and finally to Google for open-sourcing Abseil. Thanks also to my son <em>Andre</em> for reviewing this paper, and for his patience when I was rambling to him about the parallel_hash_map and all its benefits.</p>
<h3 id="links">Links</h3>
<p><a href="https://github.com/greg7mdp/parallel-hashmap">github repository for the benchmark code used in this paper</a></p>
<p><a href="https://abseil.io/blog/20180927-swisstables">Swiss Tables doc</a></p>