diff options
author | Alexander Duyck <alexander.h.duyck@redhat.com> | 2014-12-31 13:55:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-12-31 18:25:53 -0500 |
commit | 8274a97aa4c694ad0d7b31b283a89dcca140e62b (patch) | |
tree | e97afff8ea3e1e16e99d8cefe98b373e886534f0 /net/ipv4 | |
parent | bec94d430f2c97159e21e38c0f1fa4da3710d5e1 (diff) |
fib_trie: Update usage stats to be percpu instead of global variables
The trie usage stats were currently being shared by all threads that were
calling fib_table_lookup. As a result when multiple threads were
performing lookups simultaneously the trie would begin to cache bounce
between those threads.
In order to prevent this I have updated the usage stats to use a set of
percpu variables. By doing this we should be able to avoid the cache
bouncing and still make use of these stats.
Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/fib_frontend.c | 2 | ||||
-rw-r--r-- | net/ipv4/fib_trie.c | 68 |
2 files changed, 49 insertions, 21 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 23104a3f2924..66890209208f 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(struct net *net) | |||
67 | return 0; | 67 | return 0; |
68 | 68 | ||
69 | fail: | 69 | fail: |
70 | kfree(local_table); | 70 | fib_free_table(local_table); |
71 | return -ENOMEM; | 71 | return -ENOMEM; |
72 | } | 72 | } |
73 | #else | 73 | #else |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 18bcaf2ff2fd..d3dbb4821ae8 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -153,7 +153,7 @@ struct trie_stat { | |||
153 | struct trie { | 153 | struct trie { |
154 | struct rt_trie_node __rcu *trie; | 154 | struct rt_trie_node __rcu *trie; |
155 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 155 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
156 | struct trie_use_stats stats; | 156 | struct trie_use_stats __percpu *stats; |
157 | #endif | 157 | #endif |
158 | }; | 158 | }; |
159 | 159 | ||
@@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struct trie *t, struct tnode *tn) | |||
631 | if (IS_ERR(tn)) { | 631 | if (IS_ERR(tn)) { |
632 | tn = old_tn; | 632 | tn = old_tn; |
633 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 633 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
634 | t->stats.resize_node_skipped++; | 634 | this_cpu_inc(t->stats->resize_node_skipped); |
635 | #endif | 635 | #endif |
636 | break; | 636 | break; |
637 | } | 637 | } |
@@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struct trie *t, struct tnode *tn) | |||
658 | if (IS_ERR(tn)) { | 658 | if (IS_ERR(tn)) { |
659 | tn = old_tn; | 659 | tn = old_tn; |
660 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 660 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
661 | t->stats.resize_node_skipped++; | 661 | this_cpu_inc(t->stats->resize_node_skipped); |
662 | #endif | 662 | #endif |
663 | break; | 663 | break; |
664 | } | 664 | } |
@@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, | |||
1357 | err = fib_props[fa->fa_type].error; | 1357 | err = fib_props[fa->fa_type].error; |
1358 | if (err) { | 1358 | if (err) { |
1359 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1359 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1360 | t->stats.semantic_match_passed++; | 1360 | this_cpu_inc(t->stats->semantic_match_passed); |
1361 | #endif | 1361 | #endif |
1362 | return err; | 1362 | return err; |
1363 | } | 1363 | } |
@@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, | |||
1372 | continue; | 1372 | continue; |
1373 | 1373 | ||
1374 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1374 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1375 | t->stats.semantic_match_passed++; | 1375 | this_cpu_inc(t->stats->semantic_match_passed); |
1376 | #endif | 1376 | #endif |
1377 | res->prefixlen = li->plen; | 1377 | res->prefixlen = li->plen; |
1378 | res->nh_sel = nhsel; | 1378 | res->nh_sel = nhsel; |
@@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l, | |||
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1390 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1391 | t->stats.semantic_match_miss++; | 1391 | this_cpu_inc(t->stats->semantic_match_miss); |
1392 | #endif | 1392 | #endif |
1393 | } | 1393 | } |
1394 | 1394 | ||
@@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | |||
1399 | struct fib_result *res, int fib_flags) | 1399 | struct fib_result *res, int fib_flags) |
1400 | { | 1400 | { |
1401 | struct trie *t = (struct trie *) tb->tb_data; | 1401 | struct trie *t = (struct trie *) tb->tb_data; |
1402 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1403 | struct trie_use_stats __percpu *stats = t->stats; | ||
1404 | #endif | ||
1402 | int ret; | 1405 | int ret; |
1403 | struct rt_trie_node *n; | 1406 | struct rt_trie_node *n; |
1404 | struct tnode *pn; | 1407 | struct tnode *pn; |
@@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | |||
1417 | goto failed; | 1420 | goto failed; |
1418 | 1421 | ||
1419 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1422 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1420 | t->stats.gets++; | 1423 | this_cpu_inc(stats->gets); |
1421 | #endif | 1424 | #endif |
1422 | 1425 | ||
1423 | /* Just a leaf? */ | 1426 | /* Just a leaf? */ |
@@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, | |||
1441 | 1444 | ||
1442 | if (n == NULL) { | 1445 | if (n == NULL) { |
1443 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1446 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1444 | t->stats.null_node_hit++; | 1447 | this_cpu_inc(stats->null_node_hit); |
1445 | #endif | 1448 | #endif |
1446 | goto backtrace; | 1449 | goto backtrace; |
1447 | } | 1450 | } |
@@ -1576,7 +1579,7 @@ backtrace: | |||
1576 | chopped_off = 0; | 1579 | chopped_off = 0; |
1577 | 1580 | ||
1578 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 1581 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
1579 | t->stats.backtrack++; | 1582 | this_cpu_inc(stats->backtrack); |
1580 | #endif | 1583 | #endif |
1581 | goto backtrace; | 1584 | goto backtrace; |
1582 | } | 1585 | } |
@@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb) | |||
1830 | 1833 | ||
1831 | void fib_free_table(struct fib_table *tb) | 1834 | void fib_free_table(struct fib_table *tb) |
1832 | { | 1835 | { |
1836 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1837 | struct trie *t = (struct trie *)tb->tb_data; | ||
1838 | |||
1839 | free_percpu(t->stats); | ||
1840 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ | ||
1833 | kfree(tb); | 1841 | kfree(tb); |
1834 | } | 1842 | } |
1835 | 1843 | ||
@@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id) | |||
1973 | tb->tb_num_default = 0; | 1981 | tb->tb_num_default = 0; |
1974 | 1982 | ||
1975 | t = (struct trie *) tb->tb_data; | 1983 | t = (struct trie *) tb->tb_data; |
1976 | memset(t, 0, sizeof(*t)); | 1984 | RCU_INIT_POINTER(t->trie, NULL); |
1985 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
1986 | t->stats = alloc_percpu(struct trie_use_stats); | ||
1987 | if (!t->stats) { | ||
1988 | kfree(tb); | ||
1989 | tb = NULL; | ||
1990 | } | ||
1991 | #endif | ||
1977 | 1992 | ||
1978 | return tb; | 1993 | return tb; |
1979 | } | 1994 | } |
@@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) | |||
2139 | 2154 | ||
2140 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 2155 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
2141 | static void trie_show_usage(struct seq_file *seq, | 2156 | static void trie_show_usage(struct seq_file *seq, |
2142 | const struct trie_use_stats *stats) | 2157 | const struct trie_use_stats __percpu *stats) |
2143 | { | 2158 | { |
2159 | struct trie_use_stats s = { 0 }; | ||
2160 | int cpu; | ||
2161 | |||
2162 | /* loop through all of the CPUs and gather up the stats */ | ||
2163 | for_each_possible_cpu(cpu) { | ||
2164 | const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu); | ||
2165 | |||
2166 | s.gets += pcpu->gets; | ||
2167 | s.backtrack += pcpu->backtrack; | ||
2168 | s.semantic_match_passed += pcpu->semantic_match_passed; | ||
2169 | s.semantic_match_miss += pcpu->semantic_match_miss; | ||
2170 | s.null_node_hit += pcpu->null_node_hit; | ||
2171 | s.resize_node_skipped += pcpu->resize_node_skipped; | ||
2172 | } | ||
2173 | |||
2144 | seq_printf(seq, "\nCounters:\n---------\n"); | 2174 | seq_printf(seq, "\nCounters:\n---------\n"); |
2145 | seq_printf(seq, "gets = %u\n", stats->gets); | 2175 | seq_printf(seq, "gets = %u\n", s.gets); |
2146 | seq_printf(seq, "backtracks = %u\n", stats->backtrack); | 2176 | seq_printf(seq, "backtracks = %u\n", s.backtrack); |
2147 | seq_printf(seq, "semantic match passed = %u\n", | 2177 | seq_printf(seq, "semantic match passed = %u\n", |
2148 | stats->semantic_match_passed); | 2178 | s.semantic_match_passed); |
2149 | seq_printf(seq, "semantic match miss = %u\n", | 2179 | seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss); |
2150 | stats->semantic_match_miss); | 2180 | seq_printf(seq, "null node hit= %u\n", s.null_node_hit); |
2151 | seq_printf(seq, "null node hit= %u\n", stats->null_node_hit); | 2181 | seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped); |
2152 | seq_printf(seq, "skipped node resize = %u\n\n", | ||
2153 | stats->resize_node_skipped); | ||
2154 | } | 2182 | } |
2155 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ | 2183 | #endif /* CONFIG_IP_FIB_TRIE_STATS */ |
2156 | 2184 | ||
@@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v) | |||
2191 | trie_collect_stats(t, &stat); | 2219 | trie_collect_stats(t, &stat); |
2192 | trie_show_stats(seq, &stat); | 2220 | trie_show_stats(seq, &stat); |
2193 | #ifdef CONFIG_IP_FIB_TRIE_STATS | 2221 | #ifdef CONFIG_IP_FIB_TRIE_STATS |
2194 | trie_show_usage(seq, &t->stats); | 2222 | trie_show_usage(seq, t->stats); |
2195 | #endif | 2223 | #endif |
2196 | } | 2224 | } |
2197 | } | 2225 | } |