diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-09 20:24:30 -0500 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-01-24 19:40:30 -0500 |
commit | ac13ac6f4c6c0504d2c927862216f4e422a2c0b5 (patch) | |
tree | 87d0d698e79b911428b8f8e2f357a27f74c854f9 /include | |
parent | 9e3d47df35abd6430fed04fb40a76c7358b1e815 (diff) |
sysctl: Index sysctl directories with rbtrees.
One of the most important jobs of sysctl is to export network stack
tunables. Several of those tunables are per network device. In
several instances people are running with 1000+ network devices in
there network stacks, which makes the simple per directory linked list
in sysctl a scaling bottleneck. Replace O(N^2) sysctl insertion and
lookup times with O(NlogN) by using an rbtree to index the sysctl
directories.
Benchmark before:
make-dummies 0 999 -> 0.32s
rmmod dummy -> 0.12s
make-dummies 0 9999 -> 1m17s
rmmod dummy -> 17s
Benchmark after:
make-dummies 0 999 -> 0.074s
rmmod dummy -> 0.070s
make-dummies 0 9999 -> 3.4s
rmmod dummy -> 0.44s
Benchmark after (without dev_snmp6):
make-dummies 0 9999 -> 0.75s
rmmod dummy -> 0.44s
make-dummies 0 99999 -> 11s
rmmod dummy -> 4.3s
At 10,000 dummy devices the bottleneck becomes the time to add and
remove the files under /proc/sys/net/dev_snmp6. I have commented
out the code that adds and removes files under /proc/sys/net/dev_snmp6
and taken measurments of creating and destroying 100,000 dummies to
verify the sysctl continues to scale.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/sysctl.h | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 36dec756ef9d..35c50ed36fc9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -932,6 +932,7 @@ enum | |||
932 | #include <linux/list.h> | 932 | #include <linux/list.h> |
933 | #include <linux/rcupdate.h> | 933 | #include <linux/rcupdate.h> |
934 | #include <linux/wait.h> | 934 | #include <linux/wait.h> |
935 | #include <linux/rbtree.h> | ||
935 | 936 | ||
936 | /* For the /proc/sys support */ | 937 | /* For the /proc/sys support */ |
937 | struct ctl_table; | 938 | struct ctl_table; |
@@ -1023,6 +1024,11 @@ struct ctl_table | |||
1023 | void *extra2; | 1024 | void *extra2; |
1024 | }; | 1025 | }; |
1025 | 1026 | ||
1027 | struct ctl_node { | ||
1028 | struct rb_node node; | ||
1029 | struct ctl_table_header *header; | ||
1030 | }; | ||
1031 | |||
1026 | /* struct ctl_table_header is used to maintain dynamic lists of | 1032 | /* struct ctl_table_header is used to maintain dynamic lists of |
1027 | struct ctl_table trees. */ | 1033 | struct ctl_table trees. */ |
1028 | struct ctl_table_header | 1034 | struct ctl_table_header |
@@ -1030,7 +1036,6 @@ struct ctl_table_header | |||
1030 | union { | 1036 | union { |
1031 | struct { | 1037 | struct { |
1032 | struct ctl_table *ctl_table; | 1038 | struct ctl_table *ctl_table; |
1033 | struct list_head ctl_entry; | ||
1034 | int used; | 1039 | int used; |
1035 | int count; | 1040 | int count; |
1036 | int nreg; | 1041 | int nreg; |
@@ -1042,12 +1047,13 @@ struct ctl_table_header | |||
1042 | struct ctl_table_root *root; | 1047 | struct ctl_table_root *root; |
1043 | struct ctl_table_set *set; | 1048 | struct ctl_table_set *set; |
1044 | struct ctl_dir *parent; | 1049 | struct ctl_dir *parent; |
1050 | struct ctl_node *node; | ||
1045 | }; | 1051 | }; |
1046 | 1052 | ||
1047 | struct ctl_dir { | 1053 | struct ctl_dir { |
1048 | /* Header must be at the start of ctl_dir */ | 1054 | /* Header must be at the start of ctl_dir */ |
1049 | struct ctl_table_header header; | 1055 | struct ctl_table_header header; |
1050 | struct list_head list; | 1056 | struct rb_root root; |
1051 | }; | 1057 | }; |
1052 | 1058 | ||
1053 | struct ctl_table_set { | 1059 | struct ctl_table_set { |