flex_proportions.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Floating proportions with flexible aging period
  4. *
  5. * Copyright (C) 2011, SUSE, Jan Kara <jack@suse.cz>
  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;
  63. unsigned long flags;
  64. local_irq_save(flags);
  65. events = percpu_counter_sum(&p->events);
  66. /*
  67. * Don't do anything if there are no events.
  68. */
  69. if (events <= 1) {
  70. local_irq_restore(flags);
  71. return false;
  72. }
  73. write_seqcount_begin(&p->sequence);
  74. if (periods < 64)
  75. events -= events >> periods;
  76. /* Use addition to avoid losing events happening between sum and set */
  77. percpu_counter_add(&p->events, -events);
  78. p->period += periods;
  79. write_seqcount_end(&p->sequence);
  80. local_irq_restore(flags);
  81. return true;
  82. }
  83. /*
  84. * ---- SINGLE ----
  85. */
  86. int fprop_local_init_single(struct fprop_local_single *pl)
  87. {
  88. pl->events = 0;
  89. pl->period = 0;
  90. raw_spin_lock_init(&pl->lock);
  91. return 0;
  92. }
  93. void fprop_local_destroy_single(struct fprop_local_single *pl)
  94. {
  95. }
  96. static void fprop_reflect_period_single(struct fprop_global *p,
  97. struct fprop_local_single *pl)
  98. {
  99. unsigned int period = p->period;
  100. unsigned long flags;
  101. /* Fast path - period didn't change */
  102. if (pl->period == period)
  103. return;
  104. raw_spin_lock_irqsave(&pl->lock, flags);
  105. /* Someone updated pl->period while we were spinning? */
  106. if (pl->period >= period) {
  107. raw_spin_unlock_irqrestore(&pl->lock, flags);
  108. return;
  109. }
  110. /* Aging zeroed our fraction? */
  111. if (period - pl->period < BITS_PER_LONG)
  112. pl->events >>= period - pl->period;
  113. else
  114. pl->events = 0;
  115. pl->period = period;
  116. raw_spin_unlock_irqrestore(&pl->lock, flags);
  117. }
  118. /* Event of type pl happened */
  119. void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl)
  120. {
  121. fprop_reflect_period_single(p, pl);
  122. pl->events++;
  123. percpu_counter_add(&p->events, 1);
  124. }
  125. /* Return fraction of events of type pl */
  126. void fprop_fraction_single(struct fprop_global *p,
  127. struct fprop_local_single *pl,
  128. unsigned long *numerator, unsigned long *denominator)
  129. {
  130. unsigned int seq;
  131. s64 num, den;
  132. do {
  133. seq = read_seqcount_begin(&p->sequence);
  134. fprop_reflect_period_single(p, pl);
  135. num = pl->events;
  136. den = percpu_counter_read_positive(&p->events);
  137. } while (read_seqcount_retry(&p->sequence, seq));
  138. /*
  139. * Make fraction <= 1 and denominator > 0 even in presence of percpu
  140. * counter errors
  141. */
  142. if (den <= num) {
  143. if (num)
  144. den = num;
  145. else
  146. den = 1;
  147. }
  148. *denominator = den;
  149. *numerator = num;
  150. }
  151. /*
  152. * ---- PERCPU ----
  153. */
  154. #define PROP_BATCH (8*(1+ilog2(nr_cpu_ids)))
  155. int fprop_local_init_percpu(struct fprop_local_percpu *pl, gfp_t gfp)
  156. {
  157. int err;
  158. err = percpu_counter_init(&pl->events, 0, gfp);
  159. if (err)
  160. return err;
  161. pl->period = 0;
  162. raw_spin_lock_init(&pl->lock);
  163. return 0;
  164. }
  165. void fprop_local_destroy_percpu(struct fprop_local_percpu *pl)
  166. {
  167. percpu_counter_destroy(&pl->events);
  168. }
  169. static void fprop_reflect_period_percpu(struct fprop_global *p,
  170. struct fprop_local_percpu *pl)
  171. {
  172. unsigned int period = p->period;
  173. unsigned long flags;
  174. /* Fast path - period didn't change */
  175. if (pl->period == period)
  176. return;
  177. raw_spin_lock_irqsave(&pl->lock, flags);
  178. /* Someone updated pl->period while we were spinning? */
  179. if (pl->period >= period) {
  180. raw_spin_unlock_irqrestore(&pl->lock, flags);
  181. return;
  182. }
  183. /* Aging zeroed our fraction? */
  184. if (period - pl->period < BITS_PER_LONG) {
  185. s64 val = percpu_counter_read(&pl->events);
  186. if (val < (nr_cpu_ids * PROP_BATCH))
  187. val = percpu_counter_sum(&pl->events);
  188. percpu_counter_add_batch(&pl->events,
  189. -val + (val >> (period-pl->period)), PROP_BATCH);
  190. } else
  191. percpu_counter_set(&pl->events, 0);
  192. pl->period = period;
  193. raw_spin_unlock_irqrestore(&pl->lock, flags);
  194. }
  195. /* Event of type pl happened */
  196. void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl)
  197. {
  198. fprop_reflect_period_percpu(p, pl);
  199. percpu_counter_add_batch(&pl->events, 1, PROP_BATCH);
  200. percpu_counter_add(&p->events, 1);
  201. }
  202. void fprop_fraction_percpu(struct fprop_global *p,
  203. struct fprop_local_percpu *pl,
  204. unsigned long *numerator, unsigned long *denominator)
  205. {
  206. unsigned int seq;
  207. s64 num, den;
  208. do {
  209. seq = read_seqcount_begin(&p->sequence);
  210. fprop_reflect_period_percpu(p, pl);
  211. num = percpu_counter_read_positive(&pl->events);
  212. den = percpu_counter_read_positive(&p->events);
  213. } while (read_seqcount_retry(&p->sequence, seq));
  214. /*
  215. * Make fraction <= 1 and denominator > 0 even in presence of percpu
  216. * counter errors
  217. */
  218. if (den <= num) {
  219. if (num)
  220. den = num;
  221. else
  222. den = 1;
  223. }
  224. *denominator = den;
  225. *numerator = num;
  226. }
  227. /*
  228. * Like __fprop_inc_percpu() except that event is counted only if the given
  229. * type has fraction smaller than @max_frac/FPROP_FRAC_BASE
  230. */
  231. void __fprop_inc_percpu_max(struct fprop_global *p,
  232. struct fprop_local_percpu *pl, int max_frac)
  233. {
  234. if (unlikely(max_frac < FPROP_FRAC_BASE)) {
  235. unsigned long numerator, denominator;
  236. fprop_fraction_percpu(p, pl, &numerator, &denominator);
  237. if (numerator >
  238. (((u64)denominator) * max_frac) >> FPROP_FRAC_SHIFT)
  239. return;
  240. }
  241. __fprop_inc_percpu(p, pl);
  242. }