From 30f0a3102379fe46dcee8622a80063bcfe2d8b5e Mon Sep 17 00:00:00 2001 From: greg Date: Sun, 3 Mar 2019 20:14:10 -0500 Subject: [PATCH] wip --- README.md | 14 ++++++-------- pdf/Makefile | 11 +---------- pdf/css/style.css | 1 + pdf/parallel_hashmap.html | 7 +++---- 4 files changed, 11 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 171b0c5..1357b8e 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/pdf/Makefile b/pdf/Makefile index c70d215..192daa8 100644 --- a/pdf/Makefile +++ b/pdf/Makefile @@ -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) diff --git a/pdf/css/style.css b/pdf/css/style.css index ca3cbd7..82ff12c 100644 --- a/pdf/css/style.css +++ b/pdf/css/style.css @@ -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; } diff --git a/pdf/parallel_hashmap.html b/pdf/parallel_hashmap.html index d28c76d..a84fbc9 100644 --- a/pdf/parallel_hashmap.html +++ b/pdf/parallel_hashmap.html @@ -8,7 +8,6 @@ - @@ -108,7 +107,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

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).

closed_hashing

@@ -152,7 +151,7 @@
  • compute the index of the target sub-table from the hash)
  • 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

    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.

    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:

    @@ -229,7 +228,7 @@

    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.

    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.

    github repository for the benchmark code used in this paper

    Swiss Tables doc