test_sref_weakref.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. * Copyright (c) 2017-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 module is a stress test of the weak reference implementation
  19. * of scalable reference counters. Two threads are created. The first
  20. * periodically allocates a page and initializes a counter inside the
  21. * page, then immediately decrements the counter. The intended effect
  22. * is to mark the counter as dying as soon as possible. The second
  23. * thread continually attempts to obtain a reference, i.e. increment
  24. * the counter, through a weak reference. Counters are regularly
  25. * printed to monitor activity. There should be almost as many noref
  26. * calls as there are iterations in the first thread (a bit lower
  27. * because of the review delay) and a good amount of revives (at least
  28. * on multiprocessor machines) caused by successfully getting the counter
  29. * from the weak reference while it is marked dying but still in review.
  30. * Iterations in the second thread may spike when obtaining a reference
  31. * fails, because the error case is much faster and continues until the
  32. * first thread reinitializes the weak reference.
  33. */
  34. #include <stddef.h>
  35. #include <stdio.h>
  36. #include <kern/error.h>
  37. #include <kern/init.h>
  38. #include <kern/log.h>
  39. #include <kern/macros.h>
  40. #include <kern/sref.h>
  41. #include <kern/syscnt.h>
  42. #include <kern/thread.h>
  43. #include <test/test.h>
  44. #include <vm/vm_kmem.h>
  45. static struct sref_weakref test_weakref;
  46. static void
  47. test_noref(struct sref_counter *counter)
  48. {
  49. vm_kmem_free(counter, sizeof(*counter));
  50. }
  51. static void
  52. test_run(void *arg)
  53. {
  54. struct sref_counter *counter;
  55. volatile unsigned long j;
  56. unsigned long i;
  57. (void)arg;
  58. for (i = 1; /* no condition */; i++) {
  59. counter = vm_kmem_alloc(sizeof(*counter));
  60. if (counter == NULL) {
  61. continue;
  62. }
  63. sref_counter_init(counter, 1, &test_weakref, test_noref);
  64. sref_counter_dec(counter);
  65. for (j = 0; j < 0x20000000; j++);
  66. printf("run: iterations: %lu\n", i);
  67. syscnt_info("sref_epoch", log_info);
  68. syscnt_info("sref_dirty_zero", log_info);
  69. syscnt_info("sref_revive", log_info);
  70. syscnt_info("sref_true_zero", log_info);
  71. }
  72. }
  73. static void
  74. test_ref(void *arg)
  75. {
  76. struct sref_counter *counter;
  77. unsigned long i;
  78. (void)arg;
  79. for (i = 1; /* no condition */; i++) {
  80. counter = sref_weakref_get(&test_weakref);
  81. if (counter != NULL) {
  82. sref_counter_dec(counter);
  83. }
  84. if ((i % 100000000) == 0) {
  85. printf("ref: iterations: %lu\n", i);
  86. }
  87. }
  88. }
  89. void __init
  90. test_setup(void)
  91. {
  92. struct thread_attr attr;
  93. struct thread *thread;
  94. int error;
  95. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "test_run");
  96. thread_attr_set_detached(&attr);
  97. error = thread_create(&thread, &attr, test_run, NULL);
  98. error_check(error, "thread_create");
  99. thread_attr_init(&attr, THREAD_KERNEL_PREFIX "test_ref");
  100. thread_attr_set_detached(&attr);
  101. error = thread_create(&thread, &attr, test_ref, NULL);
  102. error_check(error, "thread_create");
  103. }