From: Karsten Blees <karsten.blees@gmail.com>
To: Junio C Hamano <gitster@pobox.com>, git@vger.kernel.org
Cc: Thomas Rast <tr@thomasrast.ch>, Jonathan Nieder <jrnieder@gmail.com>
Subject: [PATCH] hashmap.h: make sure map entries are tightly packed
Date: Sun, 09 Feb 2014 00:35:55 +0100 [thread overview]
Message-ID: <52F6BF5B.9090807@gmail.com> (raw)
In-Reply-To: <xmqqtxcatze2.fsf@gitster.dls.corp.google.com>
Am 07.02.2014 21:56, schrieb Junio C Hamano:
> * kb/fast-hashmap (2014-01-03) 19 commits
> - hashmap.h: make sure map entries are tightly packed
> (merged to 'next' on 2014-01-03 at dc85001)
[...]
> The tip one does not seem to have reached concensus (yet).
See discussion leading up to $gmane/239433.
I'd like to finish this up, so here are the options regarding the tip commit as I see them, ordered least risk to broadest compiler support:
1.) Drop the tip commit
Wastes 4 bytes of memory per entry on 64-bit platforms (still an improvement wrt memory, hash.[ch] wastes 4 bytes per bucket).
Works on all platforms.
2.) Keep the tip commit, i.e. "__attribute__(__packed__)"
Currently in pu at 036ad21.
Fixes the problem for 64-bit GCC only.
May fail on HP, all other platforms #define __attribute__ /* empty */
3.) Replace with the patch below, i.e. "#pragma pack"
Same as $gmane/239430 + $gmane/239433.
Should fix the problem for most compilers, with unit-test to make sure.
May fail on IRIX/MIPSPro (supposedly wants "#pragma pack(0)" to reset packing to default).
I don't know whether IRIX is still relevant (support ended Dec 2013). But if we fix this issue, I'd like to support as many platforms as possible, even though I can't test them all. The inline __attribute__ syntax is a dead end in that respect, so I'd suggest to go for #pragma pack (3). At the very least we shouldn't stall the rest of the patch series on a hunch that the last (unfortunately non-standard) patch may break on some legacy system.
Cheers,
Karsten
----8<----
Subject: [PATCH] hashmap.h: make sure map entries are tightly packed
Extending 'struct hashmap_entry' with an int-sized member shouldn't waste
memory on 64-bit systems. This is already documented in api-hashmap.txt,
but struct hashmap_entry needs to be packed for this to work. E.g.
struct name_entry {
struct hashmap_entry ent; /* consists of pointer + int */
int namelen;
char *name;
};
should be 24 instead of 32 bytes.
Packing structures is compiler-specific, most compilers support [1]:
#pragma pack(n) - to set structure packing
#pragma pack() - to reset structure packing to default
Compilers are supposed to ignore unknown #pragmas, so using this without
further #if <compiler> guards should be safe.
Wasting a few bytes for padding is acceptable, however, compiling the rest
of git with packed structures (and thus mis-aligned arrays of structs) is
not. Add a test to ensure that '#pragma pack()' really resets the packing.
[1] Compiler docs regarding #pragma pack:
http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Structure_002dPacking-Pragmas.html#Structure_002dPacking-Pragmas
http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx
http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/Online_Help/pragmas.htm#pragma-PACK
http://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
http://uw714doc.sco.com/en/SDK_cprog/_Preprocessing_Directives.html
http://osr507doc.sco.com/en/tools/ANSI_F.3.13_Preprocessing.html
http://docs.oracle.com/cd/E19422-01/819-3690/Pragmas_App.html#73499
http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp?topic=%2Fcom.ibm.vacpp7a.doc%2Fcompiler%2Fref%2Frnpgpack.htm
Supposedly wants #pragma pack(0) to reset:
http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi/0650/bks/SGI_Developer/books/Pragmas/sgi_html/ch04.html
Not supported:
http://software.intel.com/sites/products/documentation/doclib/iss/2013/compiler/cpp-lin/GUID-DD32852C-A0F9-4AC6-BF67-D10D064CC87A.htm
Signed-off-by: Karsten Blees <blees@dcon.de>
---
hashmap.h | 7 +++++++
t/t0011-hashmap.sh | 6 ++++++
test-hashmap.c | 17 +++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/hashmap.h b/hashmap.h
index a816ad4..93b330b 100644
--- a/hashmap.h
+++ b/hashmap.h
@@ -15,10 +15,17 @@ extern unsigned int memihash(const void *buf, size_t len);
/* data structures */
+/*
+ * Set struct packing to 4 so that we don't waste memory on 64-bit systems.
+ * Struct hashmap_entry is used as prefix to other (un-packed) structures,
+ * so this won't cause alignment issues e.g. for odd elements in an array.
+ */
+#pragma pack(4)
struct hashmap_entry {
struct hashmap_entry *next;
unsigned int hash;
};
+#pragma pack()
typedef int (*hashmap_cmp_fn)(const void *entry, const void *entry_or_key,
const void *keydata);
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
index 391e2b6..3f3c90b 100755
--- a/t/t0011-hashmap.sh
+++ b/t/t0011-hashmap.sh
@@ -237,4 +237,10 @@ test_expect_success 'grow / shrink' '
'
+test_expect_success '"#pragma pack()" resets packing to default' '
+
+ test_hashmap "pragma-pack" "ok"
+
+'
+
test_done
diff --git a/test-hashmap.c b/test-hashmap.c
index f5183fb..64bd9ec 100644
--- a/test-hashmap.c
+++ b/test-hashmap.c
@@ -36,6 +36,12 @@ static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
return entry;
}
+struct pointer_int
+{
+ void *ptr;
+ int i;
+};
+
#define HASH_METHOD_FNV 0
#define HASH_METHOD_I 1
#define HASH_METHOD_IDIV10 2
@@ -136,6 +142,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
* remove key -> NULL / old value
* iterate -> key1 value1\nkey2 value2\n...
* size -> tablesize numentries
+ * pragma-pack -> ok / failure
*
* perfhashmap method rounds -> test hashmap.[ch] performance
*/
@@ -239,6 +246,16 @@ int main(int argc, char *argv[])
/* print table sizes */
printf("%u %u\n", map.tablesize, map.size);
+ } else if (!strcmp("pragma-pack", cmd)) {
+
+ if ((sizeof(struct pointer_int) % sizeof(void *)) == 0)
+ printf("ok\n");
+ else
+ printf("sizeof(pointer+int) (%u) is not a "
+ "multiple of sizeof(pointer) (%u)!\n",
+ (unsigned) sizeof(struct pointer_int),
+ (unsigned) sizeof(void *));
+
} else if (!strcmp("perfhashmap", cmd) && l1 && l2) {
perf_hashmap(atoi(p1), atoi(p2));
--
1.8.5.2.msysgit.1
next prev parent reply other threads:[~2014-02-08 23:36 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-07 20:56 What's cooking in git.git (Feb 2014, #03; Fri, 7) Junio C Hamano
2014-02-08 23:35 ` Karsten Blees [this message]
2014-02-10 19:48 ` [PATCH] hashmap.h: make sure map entries are tightly packed Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52F6BF5B.9090807@gmail.com \
--to=karsten.blees@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
--cc=tr@thomasrast.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.