flex_proportions.c 7.1 KB

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