Skip to contentSkip to conversation

Allow increasing the buffer-head per-CPU LRU size

PATCH In review Sebastien Buisson 4 participants 13 messages Jul 4, 2014 – Jul 10, 2014 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Allow increasing the buffer-head per-CPU LRU size

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

* parent directory inode table block (ctime, nlinks for subdirs)
* new inode bitmap
* inode table block
* 2 quota blocks
* directory leaf block (not reused, but pollutes one cache entry)
* 2 levels htree blocks (only one is reused, other pollutes cache)
* 2 levels indirect/index blocks (only one is reused)

The buffer-head per-CPU LRU size can be changed at config time, and its default value is raised to 16.

---
 fs/Kconfig  |    9 +++++++++
 fs/buffer.c |    3 +--
 2 files changed, 10 insertions(+), 2 deletions(-)
fs/Kconfig +9 -0
index c229f82..afea808 100644
@@ -268,4 +268,13 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config BH_LRU_SIZE
+      int "buffer head per-CPU LRU size"
+      range 8 64
+      default "16"
+      help
+        This sets the per-CPU LRU size for buffer heads in memory.
+        More complex filesystems may be modiyfing multiple blocks
+        within a single transaction, so keeping the buffer heads in
+        CPU-local cache speeds up modifations significantly.
 endmenu
fs/buffer.c +0 -0
index 6024877..b83fa63 100644
@@ -1255,8 +1255,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
  * The LRUs themselves only need locking against invalidate_bh_lrus. 

We use
* a local interrupt disable for that.
*/
-
-#define BH_LRU_SIZE 8
+#define BH_LRU_SIZE CONFIG_BH_LRU_SIZE

struct bh_lru {
struct buffer_head *bhs[BH_LRU_SIZE];

Signature · 1 line
1.7.1
#1 lore raw

Hi,

two typos:

fs/Kconfig endif # NETWORK_FILESYSTEMS · line 277

Quoted 7 lines
fs/Kconfig +7 -0
+config BH_LRU_SIZE
+      int "buffer head per-CPU LRU size"
+      range 8 64
+      default "16"
+      help
+        This sets the per-CPU LRU size for buffer heads in memory.
+        More complex filesystems may be modiyfing multiple blocks
                                           ^^^^^^^

fs/Kconfig endif # NETWORK_FILESYSTEMS · line 279

Quoted 2 lines
fs/Kconfig +2 -0
+        within a single transaction, so keeping the buffer heads in
+        CPU-local cache speeds up modifations significantly.
                                        ^^^^^^

Thanks for this nice optimization,

Andreas Mohr

#2 lore raw
In reply to Sebastien Buisson
Quoted 5 lines · Sebastien Buisson

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

I don't think that should be a user visible config. Most users wouldn't know how to set it. And Linux already has far too many obscure config options.

Either make it set implicitely by the file system config. Or just increase it unconditionally?

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only
#3 lore raw

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

* parent directory inode table block (ctime, nlinks for subdirs)
* new inode bitmap
* inode table block
* 2 quota blocks
* directory leaf block (not reused, but pollutes one cache entry)
* 2 levels htree blocks (only one is reused, other pollutes cache)
* 2 levels indirect/index blocks (only one is reused)

The buffer-head per-CPU LRU size can be changed at config time, and its default value is raised to 16.

---
 fs/Kconfig  |    9 +++++++++
 fs/buffer.c |    3 +--
 2 files changed, 10 insertions(+), 2 deletions(-)
fs/Kconfig +9 -0
index c229f82..c08844c 100644
@@ -268,4 +268,13 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config BH_LRU_SIZE
+      int
+      range 8 64
+      default "16"
+      help
+        This sets the per-CPU LRU size for buffer heads in memory.
+        More complex filesystems may be modifying multiple blocks
+        within a single transaction, so keeping the buffer heads in
+        CPU-local cache speeds up modifications significantly.
 endmenu
fs/buffer.c +0 -0
index 6024877..b83fa63 100644
@@ -1255,8 +1255,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
  * The LRUs themselves only need locking against invalidate_bh_lrus. 

We use
* a local interrupt disable for that.
*/
-
-#define BH_LRU_SIZE 8
+#define BH_LRU_SIZE CONFIG_BH_LRU_SIZE

struct bh_lru {
struct buffer_head *bhs[BH_LRU_SIZE];

Signature · 1 line
1.7.1
Quoted 18 lines · Andi Kleen
Quoted 5 lines · Sebastien Buisson

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

I don't think that should be a user visible config. Most users wouldn't know how to set it. And Linux already has far too many obscure config options.

Either make it set implicitely by the file system config. Or just increase it unconditionally?

-Andi

#4 lore raw

fs/Kconfig endif # NETWORK_FILESYSTEMS · line 274

Quoted 12 lines
fs/Kconfig +4 -0
index c229f82..c08844c 100644
@@ -268,4 +268,13 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config BH_LRU_SIZE
+      int
+      range 8 64
+      default "16"

So who sets it then?

You need it for ext4 and quota right? So this combination should set it at least. Something like (unested)

It would be also good to audit or test other file systems if they need the same if that's possible.

config BH_LARGE_LRU

	bool
	depends on (EXT4_FS && QUOTA)

config BH_LRU_SIZE
....
default "16" if BH_LARGE_LRU
default "8" if !BH_LARGE_LRU

-Andi

#5 lore raw
Quoted 2 lines

config BH_LARGE_LRU
bool

should be def_bool y

Quoted 9 lines
	depends on (EXT4_FS && QUOTA)

config BH_LRU_SIZE
....
default "16" if BH_LARGE_LRU
default "8" if !BH_LARGE_LRU

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.
#6 lore raw
In reply to Andi Kleen
Quoted 21 lines · On Mon, 7 Jul 2014 18:30:03 +0200 Andi Kleen <[email protected]> wrote:

fs/Kconfig endif # NETWORK_FILESYSTEMS · line 274

Quoted 12 lines
fs/Kconfig +4 -0
index c229f82..c08844c 100644
@@ -268,4 +268,13 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config BH_LRU_SIZE
+      int
+      range 8 64
+      default "16"

So who sets it then?

You need it for ext4 and quota right? So this combination should set it at least. Something like (unested)

It would be also good to audit or test other file systems if they need the same if that's possible.

Quoted 8 lines

config BH_LARGE_LRU

	bool
	depends on (EXT4_FS && QUOTA)

config BH_LRU_SIZE
....
default "16" if BH_LARGE_LRU
default "8" if !BH_LARGE_LRU

Can anyone demonstrate why we shouldn't just do

fs/buffer.c renamed from fs/buffer.c~a +1 -1
@@ -1258,7 +1258,7 @@ static struct buffer_head *__bread_slow(
  * a local interrupt disable for that.
  */
 
-#define BH_LRU_SIZE	8
+#define BH_LRU_SIZE	16
 
 struct bh_lru {
 	struct buffer_head *bhs[BH_LRU_SIZE];

_

#7 lore raw
Quoted 1 line

Can anyone demonstrate why we shouldn't just do

I was assuming due to memory usage: with 4K blocks 32K->64K

-Andi

#8 lore raw
Quoted 5 lines
Quoted 2 lines

Can anyone demonstrate why we shouldn't just do

I was assuming due to memory usage: with 4K blocks 32K->64K

Moreover, performance gain was not that satisfactory on ext4 when increasing BH_LRU_SIZE to 16. Here are the performances I got with:
(a) mdtest on ramdisk device, single shared dir, with large ACL and SELinux
(b) mdtest on ramdisk device, single shared dir, with large ACL but NO SELinux

(results show performance gain in percentage when increasing BH_LRU_SIZE to 16)

(a)
files tasks dir size Creation Stat Removal

1000000      1     	  0          -8,7        -2,7     -0,5
1000000      1       100000          -5,2        -0,5     -1,1
1000000      1       500000          -5,1        -3,7     -1,5
1000000      1      2000000          -5,1        -4,0     -8,5
1000000      1      5000000          -4,2        -5,3     -10,2
1000000      1     10000000          -3,5        -8,0     -10,9
1000000      8            0          -0,3        -3,8     -1,2
1000000      8       100000          -1,2        -3,7     -1,5
1000000      8       500000           0,5        -3,2     -5,3
1000000      8      2000000          -1,7        -6,1     -8,7
1000000      8      5000000          -5,9        -7,7     -11,9
1000000      8     10000000          -4,1        -8,8     -13,6

(b)
files tasks dir size Creation Stat Removal

1000000      1           0            0,0        -0,9     -1,1
1000000      1      100000            1,0        -3,0     -3,5
1000000      1      500000            3,7        -3,0     -2,4
1000000      1     2000000            1,1         3,6     -0,2
1000000      1     5000000            3,5         0,1      5,9
1000000      1    10000000            9,0         3,8      6,4
1000000      8           0            2,4        -1,2     -4,3
1000000      8      100000           -0,2        -1,8     -2,4
1000000      8      500000            1,1        -0,3      2,0
1000000      8     2000000           -0,3        -2,8     -3,3
1000000      8     5000000            0,3        -3,1     -1,3
1000000      8    10000000            1,5         0,0      0,7

To compare with the performances I got on Lustre with:
(c) mds-survey on ramdisk device, quota enabled, shared directory
(d) mds-survey on ramdisk device, quota enabled, directory per process

(c)
fi dir threads create lookup destroy

1000000     1        1          11,3      1,2      7,2
1000000     1        2           6,4      2,3      6,9
1000000     1        4           1,9      3,0      1,3
1000000     1        8          -0,6      4,3      0,7
1000000     1       16           0,5      4,4      0,6

(d)
files dir threads create lookup destroy

1000000     4       4            3,2     28,5      5,3
1000000     8       8            1,2     33,9      2,0
1000000    16      16            0,6      7,9     -0,2

Sebastien.

#9 lore raw

PATCH 1/1 Allow increasing the buffer-head per-CPU LRU size

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

* parent directory inode table block (ctime, nlinks for subdirs)
* new inode bitmap
* inode table block
* 2 quota blocks
* directory leaf block (not reused, but pollutes one cache entry)
* 2 levels htree blocks (only one is reused, other pollutes cache)
* 2 levels indirect/index blocks (only one is reused)

The buffer-head per-CPU LRU size can be changed at config time, and its default value is raised to 16.

---
 fs/Kconfig  |   14 ++++++++++++++
 fs/buffer.c |    3 +--
 2 files changed, 15 insertions(+), 2 deletions(-)
fs/Kconfig +14 -0
index c229f82..afbb6fa 100644
@@ -268,4 +268,18 @@ endif # NETWORK_FILESYSTEMS
 source "fs/nls/Kconfig"
 source "fs/dlm/Kconfig"
 
+config BH_LARGE_LRU
+      def_bool y
+      depends on (EXT4_FS && QUOTA)
+
+config BH_LRU_SIZE
+      int
+      range 8 64
+      default "16" if BH_LARGE_LRU
+      default "8" if !BH_LARGE_LRU
+      help
+        This sets the per-CPU LRU size for buffer heads in memory.
+        More complex filesystems may be modifying multiple blocks
+        within a single transaction, so keeping the buffer heads in
+        CPU-local cache speeds up modifications significantly.
 endmenu
fs/buffer.c +0 -0
index 6024877..b83fa63 100644
@@ -1255,8 +1255,7 @@ static struct buffer_head *__bread_slow(struct buffer_head *bh)
  * The LRUs themselves only need locking against invalidate_bh_lrus. 

We use
* a local interrupt disable for that.
*/
-
-#define BH_LRU_SIZE 8
+#define BH_LRU_SIZE CONFIG_BH_LRU_SIZE

struct bh_lru {
struct buffer_head *bhs[BH_LRU_SIZE];

Signature · 1 line
1.7.1
#10 lore raw
Quoted 14 lines · On Thu, 10 Jul 2014 08:51:17 +0200 Sebastien Buisson…

Allow increasing the buffer-head per-CPU LRU size to allow efficient filesystem operations that access many blocks for each transaction. For example, creating a file in a large ext4 directory with quota enabled will accesses multiple buffer heads and will overflow the LRU at the default 8-block LRU size:

* parent directory inode table block (ctime, nlinks for subdirs)
* new inode bitmap
* inode table block
* 2 quota blocks
* directory leaf block (not reused, but pollutes one cache entry)
* 2 levels htree blocks (only one is reused, other pollutes cache)
* 2 levels indirect/index blocks (only one is reused)

Quoted 2 lines

The buffer-head per-CPU LRU size can be changed at config time, and its default value is raised to 16.

The patch is a performance optimisation but the changelog omits all mention of the most important part: the magnitude of the performance improvement.

Quoted 10 lines
fs/Kconfig +4 -0
@@ -268,4 +268,18 @@ endif # NETWORK_FILESYSTEMS
  source "fs/nls/Kconfig"
  source "fs/dlm/Kconfig"
 
+config BH_LARGE_LRU
+      def_bool y
+      depends on (EXT4_FS && QUOTA)
+

fs/Kconfig endif # NETWORK_FILESYSTEMS · line 284

Quoted 10 lines
fs/Kconfig +10 -0
+config BH_LRU_SIZE
+      int
+      range 8 64
+      default "16" if BH_LARGE_LRU
+      default "8" if !BH_LARGE_LRU
+      help
+        This sets the per-CPU LRU size for buffer heads in memory.
+        More complex filesystems may be modifying multiple blocks
+        within a single transaction, so keeping the buffer heads in
+        CPU-local cache speeds up modifications significantly.

This hardwires 16 if ext4&quota and 8 otherwise. There's no way for anyone to alter this decision if they think it will be helpful (or harmful) in their setup.

fs/buffer.c static struct buffer_head *__bread_slow(struct · line 1255

Quoted 7 lines
fs/Kconfig +0 -0
  endmenu
fs/buffer.c +0 -0
index 6024877..b83fa63 100644
@@ -1255,8 +1255,7 @@ static struct buffer_head *__bread_slow(struct 
 buffer_head *bh)

Your email client is wordwrapping the patches btw. And it replaces tabs with spaces.

#11 lore raw
Quoted 3 lines · Andrew Morton

This hardwires 16 if ext4&quota and 8 otherwise. There's no way for anyone to alter this decision if they think it will be helpful (or harmful) in their setup.

In fact I do not know how to let experienced people alter the value without confusing the others with yet another obscure config option (Andi's comment). I would welcome any suggestion to achieve this.

Many thanks,
Sebastien.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#12 lore raw
Quoted 9 lines · Sebastien Buisson
Quoted 3 lines · Andrew Morton

This hardwires 16 if ext4&quota and 8 otherwise. There's no way for anyone to alter this decision if they think it will be helpful (or harmful) in their setup.

In fact I do not know how to let experienced people alter the value without confusing the others with yet another obscure config option (Andi's comment). I would welcome any suggestion to achieve this.

I don't think we should generally expose it.

If someone really wants to experiment they can change the source.

-Andi

Signature · 1 line
[email protected] -- Speaking for myself only.