Skip to content

Commit 9d55c36

Browse files
author
Nick Piggin
committed
fs: implement faster dentry memcmp
The standard memcmp function on a Westmere system shows up hot in profiles in the `git diff` workload (both parallel and single threaded), and it is likely due to the costs associated with trapping into microcode, and little opportunity to improve memory access (dentry name is not likely to take up more than a cacheline). So replace it with an open-coded byte comparison. This increases code size by 8 bytes in the critical __d_lookup_rcu function, but the speedup is huge, averaging 10 runs of each: git diff st user sys elapsed CPU before 1.15 2.57 3.82 97.1 after 1.14 2.35 3.61 96.8 git diff mt user sys elapsed CPU before 1.27 3.85 1.46 349 after 1.26 3.54 1.43 333 Elapsed time for single threaded git diff at 95.0% confidence: -0.21 +/- 0.01 -5.45% +/- 0.24% It's -0.66% +/- 0.06% elapsed time on my Opteron, so rep cmp costs on the fam10h seem to be relatively smaller, but there is still a win. Signed-off-by: Nick Piggin <[email protected]>
1 parent e1bb578 commit 9d55c36

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

fs/dcache.c

+3-9
Original file line numberDiff line numberDiff line change
@@ -1454,9 +1454,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
14541454
continue;
14551455
if (alias->d_parent != entry->d_parent)
14561456
continue;
1457-
if (qstr->len != len)
1458-
continue;
1459-
if (memcmp(qstr->name, name, len))
1457+
if (dentry_cmp(qstr->name, qstr->len, name, len))
14601458
continue;
14611459
__dget(alias);
14621460
return alias;
@@ -1810,9 +1808,7 @@ struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name,
18101808
tlen, tname, name))
18111809
continue;
18121810
} else {
1813-
if (tlen != len)
1814-
continue;
1815-
if (memcmp(tname, str, tlen))
1811+
if (dentry_cmp(tname, tlen, str, len))
18161812
continue;
18171813
}
18181814
/*
@@ -1925,9 +1921,7 @@ struct dentry *__d_lookup(struct dentry *parent, struct qstr *name)
19251921
tlen, tname, name))
19261922
goto next;
19271923
} else {
1928-
if (tlen != len)
1929-
goto next;
1930-
if (memcmp(tname, str, tlen))
1924+
if (dentry_cmp(tname, tlen, str, len))
19311925
goto next;
19321926
}
19331927

include/linux/dcache.h

+21
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ struct dentry_stat_t {
4747
};
4848
extern struct dentry_stat_t dentry_stat;
4949

50+
/*
51+
* Compare 2 name strings, return 0 if they match, otherwise non-zero.
52+
* The strings are both count bytes long, and count is non-zero.
53+
*/
54+
static inline int dentry_cmp(const unsigned char *cs, size_t scount,
55+
const unsigned char *ct, size_t tcount)
56+
{
57+
int ret;
58+
if (scount != tcount)
59+
return 1;
60+
do {
61+
ret = (*cs != *ct);
62+
if (ret)
63+
break;
64+
cs++;
65+
ct++;
66+
tcount--;
67+
} while (tcount);
68+
return ret;
69+
}
70+
5071
/* Name hashing routines. Initial hash value */
5172
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
5273
#define init_name_hash() 0

0 commit comments

Comments
 (0)