diff options
author | Nick Piggin <npiggin@suse.de> | 2008-12-01 03:33:43 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-12-31 18:07:38 -0500 |
commit | c2452f32786159ed85f0e4b21fec09258f822fc8 (patch) | |
tree | 50d93df47f4547a5699c87a608e85596e4c6165f | |
parent | e2b689d82c0394e5239a3557a217f19e2f47f1be (diff) |
shrink struct dentry
struct dentry is one of the most critical structures in the kernel. So it's
sad to see it going neglected.
With CONFIG_PROFILING turned on (which is probably the common case at least
for distros and kernel developers), sizeof(struct dcache) == 208 here
(64-bit). This gives 19 objects per slab.
I packed d_mounted into a hole, and took another 4 bytes off the inline
name length to take the padding out from the end of the structure. This
shinks it to 200 bytes. I could have gone the other way and increased the
length to 40, but I'm aiming for a magic number, read on...
I then got rid of the d_cookie pointer. This shrinks it to 192 bytes. Rant:
why was this ever a good idea? The cookie system should increase its hash
size or use a tree or something if lookups are a problem. Also the "fast
dcookie lookups" in oprofile should be moved into the dcookie code -- how
can oprofile possibly care about the dcookie_mutex? It gets dropped after
get_dcookie() returns so it can't be providing any sort of protection.
At 192 bytes, 21 objects fit into a 4K page, saving about 3MB on my system
with ~140 000 entries allocated. 192 is also a multiple of 64, so we get
nice cacheline alignment on 64 and 32 byte line systems -- any given dentry
will now require 3 cachelines to touch all fields wheras previously it
would require 4.
I know the inline name size was chosen quite carefully, however with the
reduction in cacheline footprint, it should actually be just about as fast
to do a name lookup for a 36 character name as it was before the patch (and
faster for other sizes). The memory footprint savings for names which are
<= 32 or > 36 bytes long should more than make up for the memory cost for
33-36 byte names.
Performance is a feature...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/powerpc/oprofile/cell/spu_task_sync.c | 2 | ||||
-rw-r--r-- | drivers/oprofile/buffer_sync.c | 2 | ||||
-rw-r--r-- | fs/dcache.c | 4 | ||||
-rw-r--r-- | fs/dcookies.c | 28 | ||||
-rw-r--r-- | include/linux/dcache.h | 21 |
5 files changed, 35 insertions, 22 deletions
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c index 2949126d28d1..6b793aeda72e 100644 --- a/arch/powerpc/oprofile/cell/spu_task_sync.c +++ b/arch/powerpc/oprofile/cell/spu_task_sync.c | |||
@@ -297,7 +297,7 @@ static inline unsigned long fast_get_dcookie(struct path *path) | |||
297 | { | 297 | { |
298 | unsigned long cookie; | 298 | unsigned long cookie; |
299 | 299 | ||
300 | if (path->dentry->d_cookie) | 300 | if (path->dentry->d_flags & DCACHE_COOKIE) |
301 | return (unsigned long)path->dentry; | 301 | return (unsigned long)path->dentry; |
302 | get_dcookie(path, &cookie); | 302 | get_dcookie(path, &cookie); |
303 | return cookie; | 303 | return cookie; |
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 737bd9484822..65e8294a9e29 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c | |||
@@ -200,7 +200,7 @@ static inline unsigned long fast_get_dcookie(struct path *path) | |||
200 | { | 200 | { |
201 | unsigned long cookie; | 201 | unsigned long cookie; |
202 | 202 | ||
203 | if (path->dentry->d_cookie) | 203 | if (path->dentry->d_flags & DCACHE_COOKIE) |
204 | return (unsigned long)path->dentry; | 204 | return (unsigned long)path->dentry; |
205 | get_dcookie(path, &cookie); | 205 | get_dcookie(path, &cookie); |
206 | return cookie; | 206 | return cookie; |
diff --git a/fs/dcache.c b/fs/dcache.c index a1d86c7f3e66..fd244c7a7cc0 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/bootmem.h> | 34 | #include <linux/bootmem.h> |
35 | #include "internal.h" | 35 | #include "internal.h" |
36 | 36 | ||
37 | |||
38 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 37 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
39 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); | 38 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
40 | 39 | ||
@@ -948,9 +947,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
948 | dentry->d_op = NULL; | 947 | dentry->d_op = NULL; |
949 | dentry->d_fsdata = NULL; | 948 | dentry->d_fsdata = NULL; |
950 | dentry->d_mounted = 0; | 949 | dentry->d_mounted = 0; |
951 | #ifdef CONFIG_PROFILING | ||
952 | dentry->d_cookie = NULL; | ||
953 | #endif | ||
954 | INIT_HLIST_NODE(&dentry->d_hash); | 950 | INIT_HLIST_NODE(&dentry->d_hash); |
955 | INIT_LIST_HEAD(&dentry->d_lru); | 951 | INIT_LIST_HEAD(&dentry->d_lru); |
956 | INIT_LIST_HEAD(&dentry->d_subdirs); | 952 | INIT_LIST_HEAD(&dentry->d_subdirs); |
diff --git a/fs/dcookies.c b/fs/dcookies.c index 855d4b1d619a..180e9fec4ad8 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c | |||
@@ -93,10 +93,15 @@ static struct dcookie_struct *alloc_dcookie(struct path *path) | |||
93 | { | 93 | { |
94 | struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, | 94 | struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, |
95 | GFP_KERNEL); | 95 | GFP_KERNEL); |
96 | struct dentry *d; | ||
96 | if (!dcs) | 97 | if (!dcs) |
97 | return NULL; | 98 | return NULL; |
98 | 99 | ||
99 | path->dentry->d_cookie = dcs; | 100 | d = path->dentry; |
101 | spin_lock(&d->d_lock); | ||
102 | d->d_flags |= DCACHE_COOKIE; | ||
103 | spin_unlock(&d->d_lock); | ||
104 | |||
100 | dcs->path = *path; | 105 | dcs->path = *path; |
101 | path_get(path); | 106 | path_get(path); |
102 | hash_dcookie(dcs); | 107 | hash_dcookie(dcs); |
@@ -119,14 +124,14 @@ int get_dcookie(struct path *path, unsigned long *cookie) | |||
119 | goto out; | 124 | goto out; |
120 | } | 125 | } |
121 | 126 | ||
122 | dcs = path->dentry->d_cookie; | 127 | if (path->dentry->d_flags & DCACHE_COOKIE) { |
123 | 128 | dcs = find_dcookie((unsigned long)path->dentry); | |
124 | if (!dcs) | 129 | } else { |
125 | dcs = alloc_dcookie(path); | 130 | dcs = alloc_dcookie(path); |
126 | 131 | if (!dcs) { | |
127 | if (!dcs) { | 132 | err = -ENOMEM; |
128 | err = -ENOMEM; | 133 | goto out; |
129 | goto out; | 134 | } |
130 | } | 135 | } |
131 | 136 | ||
132 | *cookie = dcookie_value(dcs); | 137 | *cookie = dcookie_value(dcs); |
@@ -251,7 +256,12 @@ out_kmem: | |||
251 | 256 | ||
252 | static void free_dcookie(struct dcookie_struct * dcs) | 257 | static void free_dcookie(struct dcookie_struct * dcs) |
253 | { | 258 | { |
254 | dcs->path.dentry->d_cookie = NULL; | 259 | struct dentry *d = dcs->path.dentry; |
260 | |||
261 | spin_lock(&d->d_lock); | ||
262 | d->d_flags &= ~DCACHE_COOKIE; | ||
263 | spin_unlock(&d->d_lock); | ||
264 | |||
255 | path_put(&dcs->path); | 265 | path_put(&dcs->path); |
256 | kmem_cache_free(dcookie_cache, dcs); | 266 | kmem_cache_free(dcookie_cache, dcs); |
257 | } | 267 | } |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index a37359d0bad1..c66d22487bf8 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -75,14 +75,22 @@ full_name_hash(const unsigned char *name, unsigned int len) | |||
75 | return end_name_hash(hash); | 75 | return end_name_hash(hash); |
76 | } | 76 | } |
77 | 77 | ||
78 | struct dcookie_struct; | 78 | /* |
79 | 79 | * Try to keep struct dentry aligned on 64 byte cachelines (this will | |
80 | #define DNAME_INLINE_LEN_MIN 36 | 80 | * give reasonable cacheline footprint with larger lines without the |
81 | * large memory footprint increase). | ||
82 | */ | ||
83 | #ifdef CONFIG_64BIT | ||
84 | #define DNAME_INLINE_LEN_MIN 32 /* 192 bytes */ | ||
85 | #else | ||
86 | #define DNAME_INLINE_LEN_MIN 40 /* 128 bytes */ | ||
87 | #endif | ||
81 | 88 | ||
82 | struct dentry { | 89 | struct dentry { |
83 | atomic_t d_count; | 90 | atomic_t d_count; |
84 | unsigned int d_flags; /* protected by d_lock */ | 91 | unsigned int d_flags; /* protected by d_lock */ |
85 | spinlock_t d_lock; /* per dentry lock */ | 92 | spinlock_t d_lock; /* per dentry lock */ |
93 | int d_mounted; | ||
86 | struct inode *d_inode; /* Where the name belongs to - NULL is | 94 | struct inode *d_inode; /* Where the name belongs to - NULL is |
87 | * negative */ | 95 | * negative */ |
88 | /* | 96 | /* |
@@ -107,10 +115,7 @@ struct dentry { | |||
107 | struct dentry_operations *d_op; | 115 | struct dentry_operations *d_op; |
108 | struct super_block *d_sb; /* The root of the dentry tree */ | 116 | struct super_block *d_sb; /* The root of the dentry tree */ |
109 | void *d_fsdata; /* fs-specific data */ | 117 | void *d_fsdata; /* fs-specific data */ |
110 | #ifdef CONFIG_PROFILING | 118 | |
111 | struct dcookie_struct *d_cookie; /* cookie, if any */ | ||
112 | #endif | ||
113 | int d_mounted; | ||
114 | unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ | 119 | unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */ |
115 | }; | 120 | }; |
116 | 121 | ||
@@ -177,6 +182,8 @@ d_iput: no no no yes | |||
177 | 182 | ||
178 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ | 183 | #define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */ |
179 | 184 | ||
185 | #define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */ | ||
186 | |||
180 | extern spinlock_t dcache_lock; | 187 | extern spinlock_t dcache_lock; |
181 | extern seqlock_t rename_lock; | 188 | extern seqlock_t rename_lock; |
182 | 189 | ||