sref.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /*
  2. * Copyright (c) 2014-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * This implementation is based on the paper "RadixVM: Scalable address
  19. * spaces for multithreaded applications" by Austin T. Clements,
  20. * M. Frans Kaashoek, and Nickolai Zeldovich. Specifically, it implements
  21. * the Refcache component described in the paper, with a few differences
  22. * outlined below.
  23. *
  24. * Refcache flushes delta caches directly from an interrupt handler, and
  25. * disables interrupts and preemption on cache access. That behavior is
  26. * realtime-unfriendly because of the potentially large number of deltas
  27. * in a cache. This module uses dedicated manager threads to perform
  28. * cache flushes and queue reviews, and only disables preemption on
  29. * individual delta access.
  30. *
  31. * Locking protocol : cache -> counter -> global data
  32. */
  33. #include <assert.h>
  34. #include <errno.h>
  35. #include <stdbool.h>
  36. #include <stddef.h>
  37. #include <stdint.h>
  38. #include <stdio.h>
  39. #include <kern/atomic.h>
  40. #include <kern/clock.h>
  41. #include <kern/cpumap.h>
  42. #include <kern/init.h>
  43. #include <kern/list.h>
  44. #include <kern/log.h>
  45. #include <kern/macros.h>
  46. #include <kern/panic.h>
  47. #include <kern/percpu.h>
  48. #include <kern/slist.h>
  49. #include <kern/spinlock.h>
  50. #include <kern/sref.h>
  51. #include <kern/syscnt.h>
  52. #include <kern/thread.h>
  53. #include <machine/cpu.h>
  54. // Counter flags.
  55. #define SREF_CNTF_QUEUED 0x1 // Queued for review
  56. #define SREF_CNTF_DIRTY 0x2 // Dirty zero seen
  57. #define SREF_CNTF_UNREF 0x4 // Unreferenced, for debugging only
  58. // Per-cache delta table size.
  59. #define SREF_CACHE_DELTA_TABLE_SIZE 4096
  60. #if !ISP2 (SREF_CACHE_DELTA_TABLE_SIZE)
  61. #error "delta table size must be a power-of-two"
  62. #endif
  63. #ifdef __LP64__
  64. #define SREF_HASH_SHIFT 3
  65. #else
  66. #define SREF_HASH_SHIFT 2
  67. #endif
  68. // Negative close to 0 so that an overflow occurs early.
  69. #define SREF_EPOCH_ID_INIT_VALUE ((uint32_t)-500)
  70. // Weakref flags.
  71. #define SREF_WEAKREF_DYING ((uintptr_t)1)
  72. #define SREF_WEAKREF_MASK (~SREF_WEAKREF_DYING)
  73. /*
  74. * Since review queues are processor-local, at least two local epochs
  75. * must have passed before a zero is considered a true zero. As a result,
  76. * three queues are required, one for the current epoch, and two more.
  77. * The queues are stored in an array used as a ring buffer that moves
  78. * forward with each new local epoch. Indexing in this array is done
  79. * with a binary mask instead of a modulo, for performance reasons, and
  80. * consequently, the array size must be at least the nearest power-of-two
  81. * above three.
  82. */
  83. #define SREF_NR_QUEUES P2ROUND (3, 2)
  84. // Number of counters in review queue beyond which to issue a warning.
  85. #define SREF_NR_COUNTERS_WARN 10000
  86. /*
  87. * Global data.
  88. *
  89. * Processors regularly check the global epoch ID against their own,
  90. * locally cached epoch ID. If they're the same, a processor flushes
  91. * its cached deltas, acknowledges its flush by decrementing the number
  92. * of pending acknowledgment counter, and increments its local epoch ID,
  93. * preventing additional flushes during the same epoch.
  94. *
  95. * The last processor to acknowledge starts the next epoch.
  96. *
  97. * The epoch ID and the pending acknowledgments counter fill an entire
  98. * cache line each in order to avoid false sharing on SMP. Whenever
  99. * multiple processors may access them, they must use atomic operations
  100. * to avoid data races.
  101. *
  102. * Atomic operations on the pending acknowledgments counter are done
  103. * with acquire-release ordering to enforce the memory ordering
  104. * guarantees required by both the implementation and the interface.
  105. */
  106. struct sref_data
  107. {
  108. __cacheline_aligned uint32_t epoch_id;
  109. __cacheline_aligned uint32_t nr_pending_acks;
  110. uint64_t start_ts;
  111. struct syscnt sc_epochs;
  112. struct syscnt sc_dirty_zeroes;
  113. struct syscnt sc_true_zeroes;
  114. struct syscnt sc_revives;
  115. struct syscnt sc_last_epoch_ms;
  116. struct syscnt sc_longest_epoch_ms;
  117. };
  118. /*
  119. * Temporary difference to apply on a reference counter.
  120. *
  121. * Deltas are stored in per-processor caches and added to their global
  122. * counter when flushed. A delta is valid if and only if the counter it
  123. * points to isn't NULL.
  124. *
  125. * On cache flush, if a delta is valid, it must be flushed whatever its
  126. * value because a delta can be a dirty zero too. By flushing all valid
  127. * deltas, and clearing them all after a flush, activity on a counter is
  128. * reliably reported.
  129. */
  130. struct sref_delta
  131. {
  132. struct list node;
  133. struct sref_counter *counter;
  134. unsigned long value;
  135. };
  136. struct sref_queue
  137. {
  138. struct slist counters;
  139. unsigned long size;
  140. };
  141. /*
  142. * Per-processor cache of deltas.
  143. *
  144. * A cache is dirty if there is at least one delta that requires flushing.
  145. * It may only be flushed once per epoch.
  146. *
  147. * Delta caches are implemented with hash tables for quick ref count to
  148. * delta lookups. For now, a very simple replacement policy, similar to
  149. * that described in the RadixVM paper, is used. Improve with an LRU-like
  150. * algorithm if this turns out to be a problem.
  151. *
  152. * Periodic events (normally the system timer tick) trigger cache checks.
  153. * A cache check may wake up the manager thread if the cache needs management,
  154. * i.e. if it's dirty or if there are counters to review. Otherwise, the
  155. * flush acknowledgment is done directly to avoid the cost of a thread
  156. * wake-up.
  157. *
  158. * Interrupts and preemption must be disabled when accessing a delta cache.
  159. */
  160. struct sref_cache
  161. {
  162. struct sref_data *data;
  163. bool dirty;
  164. bool flushed;
  165. uint32_t epoch_id;
  166. struct sref_delta deltas[SREF_CACHE_DELTA_TABLE_SIZE];
  167. struct list valid_deltas;
  168. struct sref_queue queues[SREF_NR_QUEUES];
  169. struct thread *manager;
  170. struct syscnt sc_collisions;
  171. struct syscnt sc_flushes;
  172. };
  173. static struct sref_data sref_data;
  174. static struct sref_cache sref_cache __percpu;
  175. static uint32_t
  176. sref_data_get_epoch_id (const struct sref_data *data)
  177. {
  178. return (data->epoch_id);
  179. }
  180. static bool
  181. sref_data_check_epoch_id (const struct sref_data *data, uint32_t epoch_id)
  182. {
  183. if (likely (atomic_load_rlx (&data->epoch_id) != epoch_id))
  184. return (false);
  185. atomic_fence_acq ();
  186. return (true);
  187. }
  188. static void
  189. sref_data_start_epoch (struct sref_data *data)
  190. {
  191. uint64_t now = clock_get_time (),
  192. duration = clock_ticks_to_ms (now - data->start_ts);
  193. syscnt_set (&data->sc_last_epoch_ms, duration);
  194. if (duration > syscnt_read (&data->sc_longest_epoch_ms))
  195. syscnt_set (&data->sc_longest_epoch_ms, duration);
  196. assert (data->nr_pending_acks == 0);
  197. data->nr_pending_acks = cpu_count();
  198. data->start_ts = now;
  199. uint32_t epoch_id = atomic_load_rlx (&data->epoch_id);
  200. atomic_store_rel (&data->epoch_id, epoch_id + 1);
  201. }
  202. static void
  203. sref_data_ack_cpu (struct sref_data *data)
  204. {
  205. uint32_t prev = atomic_sub_acq_rel (&data->nr_pending_acks, 1);
  206. if (prev != 1)
  207. {
  208. assert (prev != 0);
  209. return;
  210. }
  211. syscnt_inc (&data->sc_epochs);
  212. sref_data_start_epoch (data);
  213. }
  214. static void
  215. sref_data_update_stats (struct sref_data *data, int64_t nr_dirty_zeroes,
  216. int64_t nr_true_zeroes, int64_t nr_revives)
  217. {
  218. syscnt_add (&data->sc_dirty_zeroes, nr_dirty_zeroes);
  219. syscnt_add (&data->sc_true_zeroes, nr_true_zeroes);
  220. syscnt_add (&data->sc_revives, nr_revives);
  221. }
  222. static bool
  223. sref_counter_aligned (const struct sref_counter *counter)
  224. {
  225. return (((uintptr_t)counter & ~SREF_WEAKREF_MASK) == 0);
  226. }
  227. static void
  228. sref_weakref_init (struct sref_weakref *weakref, struct sref_counter *counter)
  229. {
  230. assert (sref_counter_aligned (counter));
  231. weakref->addr = (uintptr_t)counter;
  232. }
  233. static void
  234. sref_weakref_mark_dying (struct sref_weakref *weakref)
  235. {
  236. atomic_or_rlx (&weakref->addr, SREF_WEAKREF_DYING);
  237. }
  238. static void
  239. sref_weakref_clear_dying (struct sref_weakref *weakref)
  240. {
  241. atomic_and_rlx (&weakref->addr, SREF_WEAKREF_MASK);
  242. }
  243. static int
  244. sref_weakref_kill (struct sref_weakref *weakref)
  245. {
  246. uintptr_t addr = atomic_load_rlx (&weakref->addr) | SREF_WEAKREF_DYING,
  247. oldval = atomic_cas_rlx (&weakref->addr, addr, 0);
  248. if (oldval == addr)
  249. return (0);
  250. assert ((oldval & SREF_WEAKREF_MASK) == (addr & SREF_WEAKREF_MASK));
  251. return (EBUSY);
  252. }
  253. static struct sref_counter*
  254. sref_weakref_tryget (struct sref_weakref *weakref)
  255. {
  256. uintptr_t addr, oldval, newval;
  257. do
  258. {
  259. addr = atomic_load_rlx (&weakref->addr);
  260. newval = addr & SREF_WEAKREF_MASK;
  261. oldval = atomic_cas_rlx (&weakref->addr, addr, newval);
  262. }
  263. while (oldval != addr);
  264. return ((struct sref_counter *)newval);
  265. }
  266. static uintptr_t
  267. sref_counter_hash (const struct sref_counter *counter)
  268. {
  269. uintptr_t va = (uintptr_t) counter;
  270. assert (P2ALIGNED (va, 1UL << SREF_HASH_SHIFT));
  271. return (va >> SREF_HASH_SHIFT);
  272. }
  273. static bool
  274. sref_counter_is_queued (const struct sref_counter *counter)
  275. {
  276. return ((counter->flags & SREF_CNTF_QUEUED) != 0);
  277. }
  278. static void
  279. sref_counter_mark_queued (struct sref_counter *counter)
  280. {
  281. counter->flags |= SREF_CNTF_QUEUED;
  282. }
  283. static void
  284. sref_counter_clear_queued (struct sref_counter *counter)
  285. {
  286. counter->flags &= ~SREF_CNTF_QUEUED;
  287. }
  288. static bool
  289. sref_counter_is_dirty (const struct sref_counter *counter)
  290. {
  291. return ((counter->flags & SREF_CNTF_DIRTY) != 0);
  292. }
  293. static void
  294. sref_counter_mark_dirty (struct sref_counter *counter)
  295. {
  296. counter->flags |= SREF_CNTF_DIRTY;
  297. }
  298. static void
  299. sref_counter_clear_dirty (struct sref_counter *counter)
  300. {
  301. counter->flags &= ~SREF_CNTF_DIRTY;
  302. }
  303. #ifdef SREF_VERIFY
  304. static bool
  305. sref_counter_is_unreferenced (const struct sref_counter *counter)
  306. {
  307. return ((counter->flags & SREF_CNTF_UNREF) != 0);
  308. }
  309. static void
  310. sref_counter_mark_unreferenced (struct sref_counter *counter)
  311. {
  312. counter->flags |= SREF_CNTF_UNREF;
  313. }
  314. #endif
  315. static void
  316. sref_counter_mark_dying (struct sref_counter *counter)
  317. {
  318. if (counter->weakref)
  319. sref_weakref_mark_dying (counter->weakref);
  320. }
  321. static void
  322. sref_counter_clear_dying (struct sref_counter *counter)
  323. {
  324. if (counter->weakref)
  325. sref_weakref_clear_dying (counter->weakref);
  326. }
  327. static int
  328. sref_counter_kill_weakref (struct sref_counter *counter)
  329. {
  330. return (counter->weakref ? sref_weakref_kill (counter->weakref) : 0);
  331. }
  332. static void __init
  333. sref_queue_init (struct sref_queue *queue)
  334. {
  335. slist_init (&queue->counters);
  336. queue->size = 0;
  337. }
  338. static bool
  339. sref_queue_empty (const struct sref_queue *queue)
  340. {
  341. return (queue->size == 0);
  342. }
  343. static void
  344. sref_queue_push (struct sref_queue *queue, struct sref_counter *counter)
  345. {
  346. slist_insert_tail (&queue->counters, &counter->node);
  347. ++queue->size;
  348. }
  349. static struct sref_counter*
  350. sref_queue_pop (struct sref_queue *queue)
  351. {
  352. struct sref_counter *counter = slist_first_entry (&queue->counters,
  353. typeof (*counter), node);
  354. slist_remove (&queue->counters, NULL);
  355. --queue->size;
  356. return (counter);
  357. }
  358. static void
  359. sref_queue_move (struct sref_queue *dest, const struct sref_queue *src)
  360. {
  361. slist_set_head (&dest->counters, &src->counters);
  362. dest->size = src->size;
  363. }
  364. static struct sref_queue*
  365. sref_cache_get_queue (struct sref_cache *cache, size_t index)
  366. {
  367. assert (index < ARRAY_SIZE (cache->queues));
  368. return (&cache->queues[index]);
  369. }
  370. static struct sref_queue*
  371. sref_cache_get_queue_by_epoch_id (struct sref_cache *cache, uint32_t epoch_id)
  372. {
  373. size_t mask = ARRAY_SIZE (cache->queues) - 1;
  374. return (sref_cache_get_queue (cache, epoch_id & mask));
  375. }
  376. static void
  377. sref_cache_schedule_review (struct sref_cache *cache,
  378. struct sref_counter *counter)
  379. {
  380. assert (!sref_counter_is_queued (counter));
  381. assert (!sref_counter_is_dirty (counter));
  382. sref_counter_mark_queued (counter);
  383. sref_counter_mark_dying (counter);
  384. _Auto queue = sref_cache_get_queue_by_epoch_id (cache, cache->epoch_id);
  385. sref_queue_push (queue, counter);
  386. }
  387. static void
  388. sref_counter_add (struct sref_counter *counter, unsigned long delta,
  389. struct sref_cache *cache)
  390. {
  391. assert (!cpu_intr_enabled ());
  392. SPINLOCK_GUARD (&counter->lock);
  393. counter->value += delta;
  394. if (counter->value)
  395. ;
  396. else if (sref_counter_is_queued (counter))
  397. sref_counter_mark_dirty (counter);
  398. else
  399. sref_cache_schedule_review (cache, counter);
  400. }
  401. static void
  402. sref_counter_noref (struct work *work)
  403. {
  404. _Auto counter = structof (work, struct sref_counter, work);
  405. counter->noref_fn (counter);
  406. }
  407. static void __init
  408. sref_delta_init (struct sref_delta *delta)
  409. {
  410. delta->counter = NULL;
  411. delta->value = 0;
  412. }
  413. static struct sref_counter*
  414. sref_delta_counter (struct sref_delta *delta)
  415. {
  416. return (delta->counter);
  417. }
  418. static void
  419. sref_delta_set_counter (struct sref_delta *delta, struct sref_counter *counter)
  420. {
  421. assert (!delta->value);
  422. delta->counter = counter;
  423. }
  424. static void
  425. sref_delta_clear (struct sref_delta *delta)
  426. {
  427. assert (!delta->value);
  428. delta->counter = NULL;
  429. }
  430. static void
  431. sref_delta_inc (struct sref_delta *delta)
  432. {
  433. ++delta->value;
  434. }
  435. static void
  436. sref_delta_dec (struct sref_delta *delta)
  437. {
  438. --delta->value;
  439. }
  440. static bool
  441. sref_delta_is_valid (const struct sref_delta *delta)
  442. {
  443. return (delta->counter != 0);
  444. }
  445. static void
  446. sref_delta_flush (struct sref_delta *delta, struct sref_cache *cache)
  447. {
  448. sref_counter_add (delta->counter, delta->value, cache);
  449. delta->value = 0;
  450. }
  451. static void
  452. sref_delta_evict (struct sref_delta *delta, struct sref_cache *cache)
  453. {
  454. sref_delta_flush (delta, cache);
  455. sref_delta_clear (delta);
  456. }
  457. static struct sref_cache*
  458. sref_get_local_cache (void)
  459. {
  460. return (cpu_local_ptr (sref_cache));
  461. }
  462. static uintptr_t
  463. sref_cache_compute_counter_index (const struct sref_cache *cache,
  464. const struct sref_counter *counter)
  465. {
  466. return (sref_counter_hash (counter) & (ARRAY_SIZE (cache->deltas) - 1));
  467. }
  468. static struct sref_delta*
  469. sref_cache_get_delta (struct sref_cache *cache, size_t index)
  470. {
  471. assert (index < ARRAY_SIZE (cache->deltas));
  472. return (&cache->deltas[index]);
  473. }
  474. static struct sref_cache*
  475. sref_cache_acquire (cpu_flags_t *flags)
  476. {
  477. thread_preempt_disable_intr_save (flags);
  478. return (sref_get_local_cache ());
  479. }
  480. static void
  481. sref_cache_release (cpu_flags_t flags)
  482. {
  483. thread_preempt_enable_intr_restore (flags);
  484. }
  485. static bool
  486. sref_cache_is_dirty (const struct sref_cache *cache)
  487. {
  488. return (cache->dirty);
  489. }
  490. static void
  491. sref_cache_set_dirty (struct sref_cache *cache)
  492. {
  493. cache->dirty = true;
  494. }
  495. static void
  496. sref_cache_clear_dirty (struct sref_cache *cache)
  497. {
  498. cache->dirty = false;
  499. }
  500. static bool
  501. sref_cache_is_flushed (const struct sref_cache *cache)
  502. {
  503. return (cache->flushed);
  504. }
  505. static void
  506. sref_cache_set_flushed (struct sref_cache *cache)
  507. {
  508. cache->flushed = true;
  509. }
  510. static void
  511. sref_cache_clear_flushed (struct sref_cache *cache)
  512. {
  513. cache->flushed = false;
  514. }
  515. static void
  516. sref_cache_add_delta (struct sref_cache *cache, struct sref_delta *delta,
  517. struct sref_counter *counter)
  518. {
  519. assert (!sref_delta_is_valid (delta));
  520. assert (counter);
  521. sref_delta_set_counter (delta, counter);
  522. list_insert_tail (&cache->valid_deltas, &delta->node);
  523. }
  524. static void
  525. sref_cache_remove_delta (struct sref_cache *cache, struct sref_delta *delta)
  526. {
  527. assert (sref_delta_is_valid (delta));
  528. sref_delta_evict (delta, cache);
  529. list_remove (&delta->node);
  530. }
  531. static struct sref_delta*
  532. sref_cache_take_delta (struct sref_cache *cache, struct sref_counter *counter)
  533. {
  534. size_t index = sref_cache_compute_counter_index (cache, counter);
  535. _Auto delta = sref_cache_get_delta (cache, index);
  536. if (!sref_delta_is_valid (delta))
  537. sref_cache_add_delta (cache, delta, counter);
  538. else if (sref_delta_counter (delta) != counter)
  539. {
  540. sref_cache_remove_delta (cache, delta);
  541. sref_cache_add_delta (cache, delta, counter);
  542. syscnt_inc (&cache->sc_collisions);
  543. }
  544. return (delta);
  545. }
  546. static bool
  547. sref_cache_needs_management (struct sref_cache *cache)
  548. {
  549. assert (!cpu_intr_enabled ());
  550. assert (!thread_preempt_enabled ());
  551. const _Auto queue = sref_cache_get_queue_by_epoch_id (cache,
  552. cache->epoch_id - 2);
  553. return (sref_cache_is_dirty (cache) || !sref_queue_empty (queue));
  554. }
  555. static void
  556. sref_cache_end_epoch (struct sref_cache *cache)
  557. {
  558. assert (!sref_cache_needs_management (cache));
  559. sref_data_ack_cpu (cache->data);
  560. ++cache->epoch_id;
  561. }
  562. static void
  563. sref_cache_flush (struct sref_cache *cache, struct sref_queue *queue)
  564. {
  565. cpu_flags_t flags;
  566. while (1)
  567. {
  568. thread_preempt_disable_intr_save (&flags);
  569. if (list_empty (&cache->valid_deltas))
  570. break;
  571. struct sref_delta *delta = list_first_entry (&cache->valid_deltas,
  572. typeof (*delta), node);
  573. sref_cache_remove_delta (cache, delta);
  574. thread_preempt_enable_intr_restore (flags);
  575. }
  576. sref_cache_clear_dirty (cache);
  577. sref_cache_set_flushed (cache);
  578. _Auto prev_queue = sref_cache_get_queue_by_epoch_id (cache,
  579. cache->epoch_id - 2);
  580. sref_queue_move (queue, prev_queue);
  581. sref_queue_init (prev_queue);
  582. sref_cache_end_epoch (cache);
  583. thread_preempt_enable_intr_restore (flags);
  584. syscnt_inc (&cache->sc_flushes);
  585. }
  586. static void
  587. sref_queue_review (struct sref_queue *queue, struct sref_cache *cache)
  588. {
  589. int64_t nr_dirty_zeroes = 0, nr_true_zeroes = 0, nr_revives = 0;
  590. struct work_queue works;
  591. work_queue_init (&works);
  592. while (!sref_queue_empty (queue))
  593. {
  594. _Auto counter = sref_queue_pop (queue);
  595. cpu_flags_t flags;
  596. spinlock_lock_intr_save (&counter->lock, &flags);
  597. #ifdef SREF_VERIFY
  598. assert (!sref_counter_is_unreferenced (counter));
  599. #endif
  600. assert (sref_counter_is_queued (counter));
  601. sref_counter_clear_queued (counter);
  602. bool requeue;
  603. if (counter->value)
  604. {
  605. sref_counter_clear_dirty (counter);
  606. sref_counter_clear_dying (counter);
  607. spinlock_unlock_intr_restore (&counter->lock, flags);
  608. continue;
  609. }
  610. else if (sref_counter_is_dirty (counter))
  611. {
  612. requeue = true;
  613. ++nr_dirty_zeroes;
  614. sref_counter_clear_dirty (counter);
  615. }
  616. else
  617. {
  618. if (sref_counter_kill_weakref (counter) == 0)
  619. requeue = false;
  620. else
  621. {
  622. requeue = true;
  623. ++nr_revives;
  624. }
  625. }
  626. if (requeue)
  627. {
  628. sref_cache_schedule_review (cache, counter);
  629. spinlock_unlock_intr_restore (&counter->lock, flags);
  630. }
  631. else
  632. {
  633. /*
  634. * Keep in mind that the work structure shares memory with
  635. * the counter data.
  636. */
  637. #ifdef SREF_VERIFY
  638. sref_counter_mark_unreferenced (counter);
  639. #endif
  640. /*
  641. * Unlocking isn't needed here, since this counter is now
  642. * really at 0, but do it for consistency.
  643. */
  644. spinlock_unlock_intr_restore (&counter->lock, flags);
  645. ++nr_true_zeroes;
  646. work_init (&counter->work, sref_counter_noref);
  647. work_queue_push (&works, &counter->work);
  648. }
  649. }
  650. if (work_queue_nr_works (&works) != 0)
  651. work_queue_schedule (&works, WORK_HIGHPRIO);
  652. sref_data_update_stats (cache->data, nr_dirty_zeroes,
  653. nr_true_zeroes, nr_revives);
  654. }
  655. static void
  656. sref_cache_manage (void *arg)
  657. {
  658. struct sref_cache *cache = arg;
  659. cpu_flags_t flags;
  660. thread_preempt_disable_intr_save (&flags);
  661. while (1)
  662. {
  663. while (sref_cache_is_flushed (cache))
  664. thread_sleep (NULL, cache, "sref");
  665. thread_preempt_enable_intr_restore (flags);
  666. struct sref_queue queue;
  667. sref_cache_flush (cache, &queue);
  668. sref_queue_review (&queue, cache);
  669. thread_preempt_disable_intr_save (&flags);
  670. }
  671. }
  672. static void
  673. sref_cache_check (struct sref_cache *cache)
  674. {
  675. if (!sref_data_check_epoch_id (&sref_data, cache->epoch_id))
  676. return;
  677. else if (!sref_cache_needs_management (cache))
  678. {
  679. sref_cache_end_epoch (cache);
  680. return;
  681. }
  682. sref_cache_clear_flushed (cache);
  683. thread_wakeup (cache->manager);
  684. }
  685. static void __init
  686. sref_cache_init (struct sref_cache *cache, unsigned int cpu,
  687. struct sref_data *data)
  688. {
  689. cache->data = data;
  690. cache->dirty = false;
  691. cache->flushed = true;
  692. cache->epoch_id = sref_data_get_epoch_id (&sref_data) + 1;
  693. for (size_t i = 0; i < ARRAY_SIZE (cache->deltas); i++)
  694. sref_delta_init (sref_cache_get_delta (cache, i));
  695. list_init (&cache->valid_deltas);
  696. for (size_t i = 0; i < ARRAY_SIZE (cache->queues); i++)
  697. sref_queue_init (sref_cache_get_queue (cache, i));
  698. char name[SYSCNT_NAME_SIZE];
  699. snprintf (name, sizeof (name), "sref_collisions/%u", cpu);
  700. syscnt_register (&cache->sc_collisions, name);
  701. snprintf (name, sizeof (name), "sref_flushes/%u", cpu);
  702. syscnt_register (&cache->sc_flushes, name);
  703. cache->manager = NULL;
  704. }
  705. static void __init
  706. sref_cache_init_manager (struct sref_cache *cache, uint32_t cpu)
  707. {
  708. struct cpumap *cpumap;
  709. int error = cpumap_create (&cpumap);
  710. if (error)
  711. panic ("sref: unable to create manager thread CPU map");
  712. cpumap_zero (cpumap);
  713. cpumap_set (cpumap, cpu);
  714. char name[THREAD_NAME_SIZE];
  715. snprintf (name, sizeof (name),
  716. THREAD_KERNEL_PREFIX "sref_cache_manage/%u", cpu);
  717. struct thread_attr attr;
  718. thread_attr_init (&attr, name);
  719. thread_attr_set_cpumap (&attr, cpumap);
  720. thread_attr_set_priority (&attr, THREAD_SCHED_FS_PRIO_MAX);
  721. struct thread *manager;
  722. error = thread_create (&manager, &attr, sref_cache_manage, cache);
  723. cpumap_destroy (cpumap);
  724. if (error)
  725. panic ("sref: unable to create manager thread");
  726. cache->manager = manager;
  727. }
  728. static void __init
  729. sref_data_init (struct sref_data *data)
  730. {
  731. data->epoch_id = SREF_EPOCH_ID_INIT_VALUE;
  732. data->nr_pending_acks = 0;
  733. data->start_ts = clock_get_time ();
  734. syscnt_register (&data->sc_epochs, "sref_epochs");
  735. syscnt_register (&data->sc_dirty_zeroes, "sref_dirty_zeroes");
  736. syscnt_register (&data->sc_true_zeroes, "sref_true_zeroes");
  737. syscnt_register (&data->sc_revives, "sref_revives");
  738. syscnt_register (&data->sc_last_epoch_ms, "sref_last_epoch_ms");
  739. syscnt_register (&data->sc_longest_epoch_ms, "sref_longest_epoch_ms");
  740. }
  741. static int __init
  742. sref_bootstrap (void)
  743. {
  744. sref_data_init (&sref_data);
  745. sref_cache_init (sref_get_local_cache (), 0, &sref_data);
  746. return (0);
  747. }
  748. INIT_OP_DEFINE (sref_bootstrap,
  749. INIT_OP_DEP (cpu_setup, true),
  750. INIT_OP_DEP (spinlock_setup, true),
  751. INIT_OP_DEP (syscnt_setup, true),
  752. INIT_OP_DEP (thread_bootstrap, true));
  753. static int __init
  754. sref_setup (void)
  755. {
  756. for (uint32_t i = 1; i < cpu_count (); i++)
  757. sref_cache_init (percpu_ptr (sref_cache, i), i, &sref_data);
  758. for (uint32_t i = 0; i < cpu_count (); i++)
  759. sref_cache_init_manager (percpu_ptr (sref_cache, i), i);
  760. sref_data_start_epoch (&sref_data);
  761. return (0);
  762. }
  763. INIT_OP_DEFINE (sref_setup,
  764. INIT_OP_DEP (cpu_mp_probe, true),
  765. INIT_OP_DEP (cpumap_setup, true),
  766. INIT_OP_DEP (log_setup, true),
  767. INIT_OP_DEP (sref_bootstrap, true),
  768. INIT_OP_DEP (thread_setup, true));
  769. void
  770. sref_report_periodic_event (void)
  771. {
  772. sref_cache_check (sref_get_local_cache ());
  773. }
  774. void
  775. sref_counter_init (struct sref_counter *counter,
  776. unsigned long init_value,
  777. struct sref_weakref *weakref,
  778. sref_noref_fn_t noref_fn)
  779. {
  780. assert (init_value);
  781. counter->noref_fn = noref_fn;
  782. spinlock_init (&counter->lock);
  783. counter->flags = 0;
  784. counter->value = init_value;
  785. counter->weakref = weakref;
  786. if (weakref)
  787. sref_weakref_init (weakref, counter);
  788. }
  789. static void
  790. sref_counter_inc_common (struct sref_counter *counter, struct sref_cache *cache)
  791. {
  792. sref_cache_set_dirty (cache);
  793. sref_delta_inc (sref_cache_take_delta (cache, counter));
  794. }
  795. void
  796. sref_counter_inc (struct sref_counter *counter)
  797. {
  798. cpu_flags_t flags;
  799. _Auto cache = sref_cache_acquire (&flags);
  800. sref_counter_inc_common (counter, cache);
  801. sref_cache_release (flags);
  802. }
  803. void
  804. sref_counter_dec (struct sref_counter *counter)
  805. {
  806. cpu_flags_t flags;
  807. _Auto cache = sref_cache_acquire (&flags);
  808. sref_cache_set_dirty (cache);
  809. sref_delta_dec (sref_cache_take_delta (cache, counter));
  810. sref_cache_release (flags);
  811. }
  812. struct sref_counter*
  813. sref_weakref_get (struct sref_weakref *weakref)
  814. {
  815. cpu_flags_t flags;
  816. _Auto cache = sref_cache_acquire (&flags);
  817. _Auto counter = sref_weakref_tryget (weakref);
  818. if (counter)
  819. sref_counter_inc_common (counter, cache);
  820. sref_cache_release (flags);
  821. return (counter);
  822. }