080-02-fib_trie-Update-usage-stats-to-be-percpu-instead-of-.patch 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. From: Alexander Duyck <alexander.h.duyck@redhat.com>
  2. Date: Wed, 31 Dec 2014 10:55:29 -0800
  3. Subject: [PATCH] fib_trie: Update usage stats to be percpu instead of
  4. global variables
  5. The trie usage stats were currently being shared by all threads that were
  6. calling fib_table_lookup. As a result when multiple threads were
  7. performing lookups simultaneously the trie would begin to cache bounce
  8. between those threads.
  9. In order to prevent this I have updated the usage stats to use a set of
  10. percpu variables. By doing this we should be able to avoid the cache
  11. bouncing and still make use of these stats.
  12. Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
  13. Signed-off-by: David S. Miller <davem@davemloft.net>
  14. ---
  15. --- a/net/ipv4/fib_frontend.c
  16. +++ b/net/ipv4/fib_frontend.c
  17. @@ -67,7 +67,7 @@ static int __net_init fib4_rules_init(st
  18. return 0;
  19. fail:
  20. - kfree(local_table);
  21. + fib_free_table(local_table);
  22. return -ENOMEM;
  23. }
  24. #else
  25. --- a/net/ipv4/fib_trie.c
  26. +++ b/net/ipv4/fib_trie.c
  27. @@ -153,7 +153,7 @@ struct trie_stat {
  28. struct trie {
  29. struct rt_trie_node __rcu *trie;
  30. #ifdef CONFIG_IP_FIB_TRIE_STATS
  31. - struct trie_use_stats stats;
  32. + struct trie_use_stats __percpu *stats;
  33. #endif
  34. };
  35. @@ -631,7 +631,7 @@ static struct rt_trie_node *resize(struc
  36. if (IS_ERR(tn)) {
  37. tn = old_tn;
  38. #ifdef CONFIG_IP_FIB_TRIE_STATS
  39. - t->stats.resize_node_skipped++;
  40. + this_cpu_inc(t->stats->resize_node_skipped);
  41. #endif
  42. break;
  43. }
  44. @@ -658,7 +658,7 @@ static struct rt_trie_node *resize(struc
  45. if (IS_ERR(tn)) {
  46. tn = old_tn;
  47. #ifdef CONFIG_IP_FIB_TRIE_STATS
  48. - t->stats.resize_node_skipped++;
  49. + this_cpu_inc(t->stats->resize_node_skipped);
  50. #endif
  51. break;
  52. }
  53. @@ -1357,7 +1357,7 @@ static int check_leaf(struct fib_table *
  54. err = fib_props[fa->fa_type].error;
  55. if (err) {
  56. #ifdef CONFIG_IP_FIB_TRIE_STATS
  57. - t->stats.semantic_match_passed++;
  58. + this_cpu_inc(t->stats->semantic_match_passed);
  59. #endif
  60. return err;
  61. }
  62. @@ -1372,7 +1372,7 @@ static int check_leaf(struct fib_table *
  63. continue;
  64. #ifdef CONFIG_IP_FIB_TRIE_STATS
  65. - t->stats.semantic_match_passed++;
  66. + this_cpu_inc(t->stats->semantic_match_passed);
  67. #endif
  68. res->prefixlen = li->plen;
  69. res->nh_sel = nhsel;
  70. @@ -1388,7 +1388,7 @@ static int check_leaf(struct fib_table *
  71. }
  72. #ifdef CONFIG_IP_FIB_TRIE_STATS
  73. - t->stats.semantic_match_miss++;
  74. + this_cpu_inc(t->stats->semantic_match_miss);
  75. #endif
  76. }
  77. @@ -1399,6 +1399,9 @@ int fib_table_lookup(struct fib_table *t
  78. struct fib_result *res, int fib_flags)
  79. {
  80. struct trie *t = (struct trie *) tb->tb_data;
  81. +#ifdef CONFIG_IP_FIB_TRIE_STATS
  82. + struct trie_use_stats __percpu *stats = t->stats;
  83. +#endif
  84. int ret;
  85. struct rt_trie_node *n;
  86. struct tnode *pn;
  87. @@ -1417,7 +1420,7 @@ int fib_table_lookup(struct fib_table *t
  88. goto failed;
  89. #ifdef CONFIG_IP_FIB_TRIE_STATS
  90. - t->stats.gets++;
  91. + this_cpu_inc(stats->gets);
  92. #endif
  93. /* Just a leaf? */
  94. @@ -1441,7 +1444,7 @@ int fib_table_lookup(struct fib_table *t
  95. if (n == NULL) {
  96. #ifdef CONFIG_IP_FIB_TRIE_STATS
  97. - t->stats.null_node_hit++;
  98. + this_cpu_inc(stats->null_node_hit);
  99. #endif
  100. goto backtrace;
  101. }
  102. @@ -1576,7 +1579,7 @@ backtrace:
  103. chopped_off = 0;
  104. #ifdef CONFIG_IP_FIB_TRIE_STATS
  105. - t->stats.backtrack++;
  106. + this_cpu_inc(stats->backtrack);
  107. #endif
  108. goto backtrace;
  109. }
  110. @@ -1830,6 +1833,11 @@ int fib_table_flush(struct fib_table *tb
  111. void fib_free_table(struct fib_table *tb)
  112. {
  113. +#ifdef CONFIG_IP_FIB_TRIE_STATS
  114. + struct trie *t = (struct trie *)tb->tb_data;
  115. +
  116. + free_percpu(t->stats);
  117. +#endif /* CONFIG_IP_FIB_TRIE_STATS */
  118. kfree(tb);
  119. }
  120. @@ -1973,7 +1981,14 @@ struct fib_table *fib_trie_table(u32 id)
  121. tb->tb_num_default = 0;
  122. t = (struct trie *) tb->tb_data;
  123. - memset(t, 0, sizeof(*t));
  124. + RCU_INIT_POINTER(t->trie, NULL);
  125. +#ifdef CONFIG_IP_FIB_TRIE_STATS
  126. + t->stats = alloc_percpu(struct trie_use_stats);
  127. + if (!t->stats) {
  128. + kfree(tb);
  129. + tb = NULL;
  130. + }
  131. +#endif
  132. return tb;
  133. }
  134. @@ -2139,18 +2154,31 @@ static void trie_show_stats(struct seq_f
  135. #ifdef CONFIG_IP_FIB_TRIE_STATS
  136. static void trie_show_usage(struct seq_file *seq,
  137. - const struct trie_use_stats *stats)
  138. + const struct trie_use_stats __percpu *stats)
  139. {
  140. + struct trie_use_stats s = { 0 };
  141. + int cpu;
  142. +
  143. + /* loop through all of the CPUs and gather up the stats */
  144. + for_each_possible_cpu(cpu) {
  145. + const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu);
  146. +
  147. + s.gets += pcpu->gets;
  148. + s.backtrack += pcpu->backtrack;
  149. + s.semantic_match_passed += pcpu->semantic_match_passed;
  150. + s.semantic_match_miss += pcpu->semantic_match_miss;
  151. + s.null_node_hit += pcpu->null_node_hit;
  152. + s.resize_node_skipped += pcpu->resize_node_skipped;
  153. + }
  154. +
  155. seq_printf(seq, "\nCounters:\n---------\n");
  156. - seq_printf(seq, "gets = %u\n", stats->gets);
  157. - seq_printf(seq, "backtracks = %u\n", stats->backtrack);
  158. + seq_printf(seq, "gets = %u\n", s.gets);
  159. + seq_printf(seq, "backtracks = %u\n", s.backtrack);
  160. seq_printf(seq, "semantic match passed = %u\n",
  161. - stats->semantic_match_passed);
  162. - seq_printf(seq, "semantic match miss = %u\n",
  163. - stats->semantic_match_miss);
  164. - seq_printf(seq, "null node hit= %u\n", stats->null_node_hit);
  165. - seq_printf(seq, "skipped node resize = %u\n\n",
  166. - stats->resize_node_skipped);
  167. + s.semantic_match_passed);
  168. + seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss);
  169. + seq_printf(seq, "null node hit= %u\n", s.null_node_hit);
  170. + seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped);
  171. }
  172. #endif /* CONFIG_IP_FIB_TRIE_STATS */
  173. @@ -2191,7 +2219,7 @@ static int fib_triestat_seq_show(struct
  174. trie_collect_stats(t, &stat);
  175. trie_show_stats(seq, &stat);
  176. #ifdef CONFIG_IP_FIB_TRIE_STATS
  177. - trie_show_usage(seq, &t->stats);
  178. + trie_show_usage(seq, t->stats);
  179. #endif
  180. }
  181. }