aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@redhat.com>2014-12-31 13:55:29 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-31 18:25:53 -0500
commit8274a97aa4c694ad0d7b31b283a89dcca140e62b (patch)
treee97afff8ea3e1e16e99d8cefe98b373e886534f0 /net/ipv4
parentbec94d430f2c97159e21e38c0f1fa4da3710d5e1 (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.c2
-rw-r--r--net/ipv4/fib_trie.c68
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
69fail: 69fail:
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 {
153struct trie { 153struct 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
1831void fib_free_table(struct fib_table *tb) 1834void 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
2141static void trie_show_usage(struct seq_file *seq, 2156static 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 }