flex_proportions.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Floating proportions with flexible aging period
  3. *
  4. * Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
  5. *
  6. * The goal of this code is: Given different types of event, measure proportion
  7. * of each type of event over time. The proportions are measured with
  8. * exponentially decaying history to give smooth transitions. A formula
  9. * expressing proportion of event of type 'j' is:
  10. *
  11. * p_{j} = (\Sum_{i>=0} x_{i,j}/2^{i+1})/(\Sum_{i>=0} x_i/2^{i+1})
  12. *
  13. * Where x_{i,j} is j's number of events in i-th last time period and x_i is
  14. * total number of events in i-th last time period.
  15. *
  16. * Note that p_{j}'s are normalised, i.e.
  17. *
  18. * \Sum_{j} p_{j} = 1,
  19. *
  20. * This formula can be straightforwardly computed by maintaining denominator
  21. * (let's call it 'd') and for each event type its numerator (let's call it
  22. * 'n_j'). When an event of type 'j' happens, we simply need to do:
  23. * n_j++; d++;
  24. *
  25. * When a new period is declared, we could do:
  26. * d /= 2
  27. * for each j
  28. * n_j /= 2
  29. *
  30. * To avoid iteration over all event types, we instead shift numerator of event
  31. * j lazily when someone asks for a proportion of event j or when event j
  32. * occurs. This can bit trivially implemented by remembering last period in
  33. * which something happened with proportion of type j.
  34. */
  35. #include <linux/flex_proportions.h>
  36. int fprop_global_init(struct fprop_global *p, gfp_t gfp)
  37. {
  38. int err;
  39. p->period = 0;
  40. /* Use 1 to avoid dealing with periods with 0 events... */
  41. err = percpu_counter_init(&p->events, 1, gfp);
  42. if (err)
  43. return err;
  44. seqcount_init(&p->sequence);
  45. return 0;
  46. }
  47. void fprop_global_destroy(struct fprop_global *p)
  48. {
  49. percpu_counter_destroy(&p->events);
  50. }
  51. /*
  52. * Declare @periods new periods. It is upto the caller to make sure period
  53. * transitions cannot happen in parallel.
  54. *
  55. * The function returns true if the proportions are still defined and false
  56. * if aging zeroed out all events. This can be used to detect whether declaring
  57. * further periods has any effect.
  58. */
  59. bool fprop_new_period(struct fprop_global *p, int periods)
  60. {
  61. s64 events;
  62. unsigned long flags;
  63. local_irq_save(flags);
  64. events = percpu_counter_sum(&p->events);
  65. /*
  66. * Don't do anything if there are no events.
  67. */
  68. if (events <= 1) {
  69. local_irq_restore(flags);
  70. return false;
  71. }
  72. write_seqcount_begin(&p->sequence);
  73. if (periods < 64)
  74. events -= events >> periods;
  75. /* Use addition to avoid losing events happening between sum and set */
  76. percpu_counter_add(&p->events, -events);
  77. p->period += periods;
  78. write_seqcount_end(&p->sequence);
  79. local_irq_restore(flags);
  80. return true;
  81. }
  82. /*
  83. * ---- SINGLE ----
  84. */
  85. int fprop_local_init_single(struct fprop_local_single *pl)
  86. {
  87. pl->events = 0;
  88. pl->period = 0;
  89. raw_spin_lock_init(&pl->lock);
  90. return 0;
  91. }
  92. void fprop_local_destroy_single(struct fprop_local_single *pl)
  93. {
  94. }
  95. static void fprop_reflect_period_single(struct fprop_global *p,
  96. struct fprop_local_single *pl)
  97. {
  98. unsigned int period = p->period;
  99. unsigned long flags;
  100. /* Fast path - period didn't change */
  101. if (pl->period == period)
  102. return;
  103. raw_spin_lock_irqsave(&pl->lock, flags);
  104. /* Someone updated pl->period while we were spinning? */
  105. if (pl->period >= period) {
  106. raw_spin_unlock_irqrestore(&pl->lock, flags);
  107. return;
  108. }
  109. /* Aging zeroed our fraction? */
  110. if (period - pl->period < BITS_PER_LONG)
  111. pl->events >>= period - pl->period;
  112. else
  113. pl->events = 0;
  114. pl->period = period;
  115. raw_spin_unlock_irqrestore(&pl->lock, flags);
  116. }
  117. /* Event of type pl happened */
  118. void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
  119. {
  120. fprop_reflect_period_single(p, pl);
  121. pl->events++;
  122. percpu_counter_add(&p->events, 1);
  123. }
  124. /* Return fraction of events of type pl */
  125. void fprop_fraction_single(struct fprop_global *p,
  126. struct fprop_local_single *pl,
  127. unsigned long *numerator, unsigned long *denominator)
  128. {
  129. unsigned int seq;
  130. s64 num, den;
  131. do {
  132. seq = read_seqcount_begin(&p->sequence);
  133. fprop_reflect_period_single(p, pl);
  134. num = pl->events;
  135. den = percpu_counter_read_positive(&p->events);
  136. } while (read_seqcount_retry(&p->sequence, seq));
  137. /*
  138. * Make fraction <= 1 and denominator > 0 even in presence of percpu
  139. * counter errors
  140. */
  141. if (den <= num) {
  142. if (num)
  143. den = num;
  144. else
  145. den = 1;
  146. }
  147. *denominator = den;
  148. *numerator = num;
  149. }
  150. /*
  151. * ---- PERCPU ----
  152. */
  153. #define PROP_BATCH (8*(1+ilog2(nr_cpu_ids)))
  154. int fprop_local_init_percpu(struct fprop_local_percpu *pl, gfp_t gfp)
  155. {
  156. int err;
  157. err = percpu_counter_init(&pl->events, 0, gfp);
  158. if (err)
  159. return err;
  160. pl->period = 0;
  161. raw_spin_lock_init(&pl->lock);
  162. return 0;
  163. }
  164. void fprop_local_destroy_percpu(struct fprop_local_percpu *pl)
  165. {
  166. percpu_counter_destroy(&pl->events);
  167. }
  168. static void fprop_reflect_period_percpu(struct fprop_global *p,
  169. struct fprop_local_percpu *pl)
  170. {
  171. unsigned int period = p->period;
  172. unsigned long flags;
  173. /* Fast path - period didn't change */
  174. if (pl->period == period)
  175. return;
  176. raw_spin_lock_irqsave(&pl->lock, flags);
  177. /* Someone updated pl->period while we were spinning? */
  178. if (pl->period >= period) {
  179. raw_spin_unlock_irqrestore(&pl->lock, flags);
  180. return;
  181. }
  182. /* Aging zeroed our fraction? */
  183. if (period - pl->period < BITS_PER_LONG) {
  184. s64 val = percpu_counter_read(&pl->events);
  185. if (val < (nr_cpu_ids * PROP_BATCH))
  186. val = percpu_counter_sum(&pl->events);
  187. __percpu_counter_add(&pl->events,
  188. -val + (val >> (period-pl->period)), PROP_BATCH);
  189. } else
  190. percpu_counter_set(&pl->events, 0);
  191. pl->period = period;
  192. raw_spin_unlock_irqrestore(&pl->lock, flags);
  193. }
  194. /* Event of type pl happened */
  195. void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
  196. {
  197. fprop_reflect_period_percpu(p, pl);
  198. __percpu_counter_add(&pl->events, 1, PROP_BATCH);
  199. percpu_counter_add(&p->events, 1);
  200. }
  201. void fprop_fraction_percpu(struct fprop_global *p,
  202. struct fprop_local_percpu *pl,
  203. unsigned long *numerator, unsigned long *denominator)
  204. {
  205. unsigned int seq;
  206. s64 num, den;
  207. do {
  208. seq = read_seqcount_begin(&p->sequence);
  209. fprop_reflect_period_percpu(p, pl);
  210. num = percpu_counter_read_positive(&pl->events);
  211. den = percpu_counter_read_positive(&p->events);
  212. } while (read_seqcount_retry(&p->sequence, seq));
  213. /*
  214. * Make fraction <= 1 and denominator > 0 even in presence of percpu
  215. * counter errors
  216. */
  217. if (den <= num) {
  218. if (num)
  219. den = num;
  220. else
  221. den = 1;
  222. }
  223. *denominator = den;
  224. *numerator = num;
  225. }
  226. /*
  227. * Like __fprop_inc_percpu() except that event is counted only if the given
  228. * type has fraction smaller than @max_frac/FPROP_FRAC_BASE
  229. */
  230. void __fprop_inc_percpu_max(struct fprop_global *p,
  231. struct fprop_local_percpu *pl, int max_frac)
  232. {
  233. if (unlikely(max_frac < FPROP_FRAC_BASE)) {
  234. unsigned long numerator, denominator;
  235. fprop_fraction_percpu(p, pl, &numerator, &denominator);
  236. if (numerator >
  237. (((u64)denominator) * max_frac) >> FPROP_FRAC_SHIFT)
  238. return;
  239. } else
  240. fprop_reflect_period_percpu(p, pl);
  241. __percpu_counter_add(&pl->events, 1, PROP_BATCH);
  242. percpu_counter_add(&p->events, 1);
  243. }