You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.7 KiB
201 lines
5.7 KiB
![]()
10 years ago
|
From: Alexander Duyck <alexander.h.duyck@redhat.com>
|
||
|
Date: Wed, 31 Dec 2014 10:55:29 -0800
|
||
|
Subject: [PATCH] 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>
|
||
|
---
|
||
|
|
||
|
--- a/net/ipv4/fib_frontend.c
|
||
|
+++ b/net/ipv4/fib_frontend.c
|
||
|
@@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(st
|
||
|
return 0;
|
||
|
|
||
|
fail:
|
||
|
- kfree(local_table);
|
||
|
+ fib_free_table(local_table);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
#else
|
||
|
--- a/net/ipv4/fib_trie.c
|
||
|
+++ b/net/ipv4/fib_trie.c
|
||
|
@@ -153,7 +153,7 @@ struct trie_stat {
|
||
|
struct trie {
|
||
|
struct rt_trie_node __rcu *trie;
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- struct trie_use_stats stats;
|
||
|
+ struct trie_use_stats __percpu *stats;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
@@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struc
|
||
|
if (IS_ERR(tn)) {
|
||
|
tn = old_tn;
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.resize_node_skipped++;
|
||
|
+ this_cpu_inc(t->stats->resize_node_skipped);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
@@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struc
|
||
|
if (IS_ERR(tn)) {
|
||
|
tn = old_tn;
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.resize_node_skipped++;
|
||
|
+ this_cpu_inc(t->stats->resize_node_skipped);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
@@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table *
|
||
|
err = fib_props[fa->fa_type].error;
|
||
|
if (err) {
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.semantic_match_passed++;
|
||
|
+ this_cpu_inc(t->stats->semantic_match_passed);
|
||
|
#endif
|
||
|
return err;
|
||
|
}
|
||
|
@@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table *
|
||
|
continue;
|
||
|
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.semantic_match_passed++;
|
||
|
+ this_cpu_inc(t->stats->semantic_match_passed);
|
||
|
#endif
|
||
|
res->prefixlen = li->plen;
|
||
|
res->nh_sel = nhsel;
|
||
|
@@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table *
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.semantic_match_miss++;
|
||
|
+ this_cpu_inc(t->stats->semantic_match_miss);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
@@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *t
|
||
|
struct fib_result *res, int fib_flags)
|
||
|
{
|
||
|
struct trie *t = (struct trie *) tb->tb_data;
|
||
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
+ struct trie_use_stats __percpu *stats = t->stats;
|
||
|
+#endif
|
||
|
int ret;
|
||
|
struct rt_trie_node *n;
|
||
|
struct tnode *pn;
|
||
|
@@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *t
|
||
|
goto failed;
|
||
|
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.gets++;
|
||
|
+ this_cpu_inc(stats->gets);
|
||
|
#endif
|
||
|
|
||
|
/* Just a leaf? */
|
||
|
@@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *t
|
||
|
|
||
|
if (n == NULL) {
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.null_node_hit++;
|
||
|
+ this_cpu_inc(stats->null_node_hit);
|
||
|
#endif
|
||
|
goto backtrace;
|
||
|
}
|
||
|
@@ -1576,7 +1579,7 @@ backtrace:
|
||
|
chopped_off = 0;
|
||
|
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- t->stats.backtrack++;
|
||
|
+ this_cpu_inc(stats->backtrack);
|
||
|
#endif
|
||
|
goto backtrace;
|
||
|
}
|
||
|
@@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb
|
||
|
|
||
|
void fib_free_table(struct fib_table *tb)
|
||
|
{
|
||
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
+ struct trie *t = (struct trie *)tb->tb_data;
|
||
|
+
|
||
|
+ free_percpu(t->stats);
|
||
|
+#endif /* CONFIG_IP_FIB_TRIE_STATS */
|
||
|
kfree(tb);
|
||
|
}
|
||
|
|
||
|
@@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id)
|
||
|
tb->tb_num_default = 0;
|
||
|
|
||
|
t = (struct trie *) tb->tb_data;
|
||
|
- memset(t, 0, sizeof(*t));
|
||
|
+ RCU_INIT_POINTER(t->trie, NULL);
|
||
|
+#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
+ t->stats = alloc_percpu(struct trie_use_stats);
|
||
|
+ if (!t->stats) {
|
||
|
+ kfree(tb);
|
||
|
+ tb = NULL;
|
||
|
+ }
|
||
|
+#endif
|
||
|
|
||
|
return tb;
|
||
|
}
|
||
|
@@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_f
|
||
|
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
static void trie_show_usage(struct seq_file *seq,
|
||
|
- const struct trie_use_stats *stats)
|
||
|
+ const struct trie_use_stats __percpu *stats)
|
||
|
{
|
||
|
+ struct trie_use_stats s = { 0 };
|
||
|
+ int cpu;
|
||
|
+
|
||
|
+ /* loop through all of the CPUs and gather up the stats */
|
||
|
+ for_each_possible_cpu(cpu) {
|
||
|
+ const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu);
|
||
|
+
|
||
|
+ s.gets += pcpu->gets;
|
||
|
+ s.backtrack += pcpu->backtrack;
|
||
|
+ s.semantic_match_passed += pcpu->semantic_match_passed;
|
||
|
+ s.semantic_match_miss += pcpu->semantic_match_miss;
|
||
|
+ s.null_node_hit += pcpu->null_node_hit;
|
||
|
+ s.resize_node_skipped += pcpu->resize_node_skipped;
|
||
|
+ }
|
||
|
+
|
||
|
seq_printf(seq, "\nCounters:\n---------\n");
|
||
|
- seq_printf(seq, "gets = %u\n", stats->gets);
|
||
|
- seq_printf(seq, "backtracks = %u\n", stats->backtrack);
|
||
|
+ seq_printf(seq, "gets = %u\n", s.gets);
|
||
|
+ seq_printf(seq, "backtracks = %u\n", s.backtrack);
|
||
|
seq_printf(seq, "semantic match passed = %u\n",
|
||
|
- stats->semantic_match_passed);
|
||
|
- seq_printf(seq, "semantic match miss = %u\n",
|
||
|
- stats->semantic_match_miss);
|
||
|
- seq_printf(seq, "null node hit= %u\n", stats->null_node_hit);
|
||
|
- seq_printf(seq, "skipped node resize = %u\n\n",
|
||
|
- stats->resize_node_skipped);
|
||
|
+ s.semantic_match_passed);
|
||
|
+ seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss);
|
||
|
+ seq_printf(seq, "null node hit= %u\n", s.null_node_hit);
|
||
|
+ seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped);
|
||
|
}
|
||
|
#endif /* CONFIG_IP_FIB_TRIE_STATS */
|
||
|
|
||
![]()
10 years ago
|
@@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct
|
||
![]()
10 years ago
|
trie_collect_stats(t, &stat);
|
||
|
trie_show_stats(seq, &stat);
|
||
|
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||
|
- trie_show_usage(seq, &t->stats);
|
||
|
+ trie_show_usage(seq, t->stats);
|
||
|
#endif
|
||
|
}
|
||
|
}
|