tblock.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. tblock.c
  9. Abstract:
  10. This module implements the kernel block allocator tests.
  11. Author:
  12. Chris Stevens 14-Nov-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include "ktestdrv.h"
  21. #include "testsup.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define KTEST_BLOCK_DEFAULT_ITERATIONS 500000
  26. #define KTEST_BLOCK_DEFAULT_THREAD_COUNT 5
  27. #define KTEST_BLOCK_DEFAULT_ALLOCATION_COUNT 500
  28. #define KTEST_BLOCK_DEFAULT_BLOCK_SIZE 1024
  29. #define KTEST_BLOCK_DEFAULT_INITIAL_CAPACITY 100
  30. #define KTEST_BLOCK_DEFAULT_ALIGNMENT 1
  31. //
  32. // ------------------------------------------------------ Data Type Definitions
  33. //
  34. //
  35. // ----------------------------------------------- Internal Function Prototypes
  36. //
  37. VOID
  38. KTestBlockStressRoutine (
  39. PVOID Parameter
  40. );
  41. //
  42. // -------------------------------------------------------------------- Globals
  43. //
  44. //
  45. // ------------------------------------------------------------------ Functions
  46. //
  47. KSTATUS
  48. KTestBlockStressStart (
  49. PKTEST_START_TEST Command,
  50. PKTEST_ACTIVE_TEST Test
  51. )
  52. /*++
  53. Routine Description:
  54. This routine starts a new invocation of the block allocator stress tests.
  55. Arguments:
  56. Command - Supplies a pointer to the start command.
  57. Test - Supplies a pointer to the active test structure to initialize.
  58. Return Value:
  59. Status code.
  60. --*/
  61. {
  62. PKTEST_PARAMETERS Parameters;
  63. KSTATUS Status;
  64. ULONG ThreadIndex;
  65. Parameters = &(Test->Parameters);
  66. RtlCopyMemory(Parameters, &(Command->Parameters), sizeof(KTEST_PARAMETERS));
  67. if (Parameters->Iterations == 0) {
  68. Parameters->Iterations = KTEST_BLOCK_DEFAULT_ITERATIONS;
  69. }
  70. if (Parameters->Threads == 0) {
  71. Parameters->Threads = KTEST_BLOCK_DEFAULT_THREAD_COUNT;
  72. }
  73. if (Parameters->Parameters[0] == 0) {
  74. Parameters->Parameters[0] = KTEST_BLOCK_DEFAULT_ALLOCATION_COUNT;
  75. }
  76. if (Parameters->Parameters[1] == 0) {
  77. Parameters->Parameters[1] = KTEST_BLOCK_DEFAULT_BLOCK_SIZE;
  78. }
  79. if (Parameters->Parameters[2] == 0) {
  80. Parameters->Parameters[2] = KTEST_BLOCK_DEFAULT_INITIAL_CAPACITY;
  81. }
  82. if (Parameters->Parameters[3] == 0) {
  83. Parameters->Parameters[3] = KTEST_BLOCK_DEFAULT_ALIGNMENT;
  84. }
  85. Test->Total = Test->Parameters.Iterations;
  86. Test->Results.Status = STATUS_SUCCESS;
  87. Test->Results.Failures = 0;
  88. for (ThreadIndex = 0;
  89. ThreadIndex < Test->Parameters.Threads;
  90. ThreadIndex += 1) {
  91. Status = PsCreateKernelThread(KTestBlockStressRoutine,
  92. Test,
  93. "KTestBlockStressRoutine");
  94. if (!KSUCCESS(Status)) {
  95. Status = STATUS_INSUFFICIENT_RESOURCES;
  96. goto PoolStressStartEnd;
  97. }
  98. }
  99. Status = STATUS_SUCCESS;
  100. PoolStressStartEnd:
  101. return Status;
  102. }
  103. //
  104. // --------------------------------------------------------- Internal Functions
  105. //
  106. VOID
  107. KTestBlockStressRoutine (
  108. PVOID Parameter
  109. )
  110. /*++
  111. Routine Description:
  112. This routine implements the block allocator stress test.
  113. Arguments:
  114. Parameter - Supplies a pointer to the thread parameter, which in this
  115. case is a pointer to the active test structure.
  116. Return Value:
  117. None.
  118. --*/
  119. {
  120. UINTN Alignment;
  121. UINTN AllocatedMemory;
  122. PUCHAR Allocation;
  123. UINTN AllocationCount;
  124. PVOID *Array;
  125. UINTN ArraySize;
  126. PBLOCK_ALLOCATOR BlockAllocator;
  127. UINTN BlockSize;
  128. UINTN ExpansionCount;
  129. ULONG Failures;
  130. UINTN Flags;
  131. UINTN Index;
  132. PKTEST_ACTIVE_TEST Information;
  133. UINTN Iteration;
  134. UINTN MaxAllocatedMemory;
  135. UINTN MaxAllocationCount;
  136. PKTEST_PARAMETERS Parameters;
  137. PPHYSICAL_ADDRESS PhysicalAddress;
  138. PHYSICAL_ADDRESS PhysicalAddressBuffer;
  139. ULONG Random;
  140. KSTATUS Status;
  141. ULONG ThreadNumber;
  142. UINTN WriteIndex;
  143. AllocatedMemory = 0;
  144. AllocationCount = 0;
  145. Array = NULL;
  146. Failures = 0;
  147. MaxAllocatedMemory = 0;
  148. MaxAllocationCount = 0;
  149. Information = Parameter;
  150. Parameters = &(Information->Parameters);
  151. ArraySize = Parameters->Parameters[0];
  152. BlockSize = Parameters->Parameters[1];
  153. ExpansionCount = Parameters->Parameters[2];
  154. Alignment = Parameters->Parameters[3];
  155. ThreadNumber = RtlAtomicAdd32(&(Information->ThreadsStarted), 1);
  156. if (BlockSize < sizeof(UINTN)) {
  157. BlockSize = sizeof(UINTN);
  158. }
  159. //
  160. // Create the block allocator.
  161. //
  162. Flags = 0;
  163. PhysicalAddress = NULL;
  164. if (Parameters->TestType == KTestNonPagedBlockStress) {
  165. Flags |= BLOCK_ALLOCATOR_FLAG_NON_PAGED;
  166. Flags |= BLOCK_ALLOCATOR_FLAG_PHYSICALLY_CONTIGUOUS;
  167. PhysicalAddress = &PhysicalAddressBuffer;
  168. }
  169. BlockAllocator = MmCreateBlockAllocator(BlockSize,
  170. Alignment,
  171. ExpansionCount,
  172. Flags,
  173. KTEST_ALLOCATION_TAG);
  174. if (BlockAllocator == NULL) {
  175. Failures += 1;
  176. Status = STATUS_INSUFFICIENT_RESOURCES;
  177. goto BlockStressRoutineEnd;
  178. }
  179. //
  180. // Create the array that holds the allocations.
  181. //
  182. Array = MmAllocatePagedPool(ArraySize * sizeof(PVOID),
  183. KTEST_ALLOCATION_TAG);
  184. if (Array == NULL) {
  185. Failures += 1;
  186. Status = STATUS_INSUFFICIENT_RESOURCES;
  187. goto BlockStressRoutineEnd;
  188. }
  189. RtlZeroMemory(Array, ArraySize * sizeof(PVOID));
  190. //
  191. // Loop simply making and freeing allocations randomly.
  192. //
  193. for (Iteration = 0; Iteration < Parameters->Iterations; Iteration += 1) {
  194. if (Information->Cancel != FALSE) {
  195. Status = STATUS_SUCCESS;
  196. goto BlockStressRoutineEnd;
  197. }
  198. Index = KTestGetRandomValue() % ArraySize;
  199. if (ThreadNumber == 0) {
  200. Information->Progress += 1;
  201. }
  202. //
  203. // If the lowest bit is set, attempt to allocate. Otherwise, attempt to
  204. // free. If there's nothing to free, allocate.
  205. //
  206. Random = KTestGetRandomValue();
  207. if (Array[Index] == NULL) {
  208. Random |= 1;
  209. }
  210. if ((Random & 1) != 0) {
  211. Allocation = MmAllocateBlock(BlockAllocator, PhysicalAddress);
  212. if (Allocation == NULL) {
  213. Failures += 1;
  214. continue;
  215. }
  216. if (IS_ALIGNED((UINTN)Allocation, Alignment) == FALSE) {
  217. RtlDebugPrint("KTEST: Block allocator return unaligned "
  218. "block: block virtual address 0x%0x, "
  219. "alignment: 0x%x\n",
  220. Allocation,
  221. Alignment);
  222. Failures += 1;
  223. Status = STATUS_UNSUCCESSFUL;
  224. goto BlockStressRoutineEnd;
  225. }
  226. if ((PhysicalAddress != NULL) &&
  227. (IS_ALIGNED(*PhysicalAddress, Alignment) == FALSE)) {
  228. RtlDebugPrint("KTEST: Block allocator return unaligned "
  229. "block: block physical address 0x%I64x, "
  230. "alignment: 0x%x\n",
  231. *PhysicalAddress,
  232. Alignment);
  233. Failures += 1;
  234. Status = STATUS_UNSUCCESSFUL;
  235. goto BlockStressRoutineEnd;
  236. }
  237. AllocatedMemory += BlockSize;
  238. //
  239. // Initialize the memory to something. Put the size at the
  240. // beginning.
  241. //
  242. ASSERT(BlockSize >= sizeof(UINTN));
  243. *((PUINTN)Allocation) = Random;
  244. for (WriteIndex = sizeof(UINTN);
  245. WriteIndex < BlockSize;
  246. WriteIndex += 1) {
  247. Allocation[WriteIndex] = WriteIndex + 0x80;
  248. }
  249. //
  250. // Free the old array.
  251. //
  252. if (Array[Index] != NULL) {
  253. AllocatedMemory -= BlockSize;
  254. MmFreeBlock(BlockAllocator, Array[Index]);
  255. AllocationCount -= 1;
  256. }
  257. Array[Index] = Allocation;
  258. AllocationCount += 1;
  259. if (AllocationCount > MaxAllocationCount) {
  260. MaxAllocationCount = AllocationCount;
  261. }
  262. if (AllocatedMemory > MaxAllocatedMemory) {
  263. MaxAllocatedMemory = AllocatedMemory;
  264. }
  265. } else {
  266. AllocatedMemory -= BlockSize;
  267. AllocationCount -= 1;
  268. MmFreeBlock(BlockAllocator, Array[Index]);
  269. Array[Index] = NULL;
  270. }
  271. }
  272. Status = STATUS_SUCCESS;
  273. BlockStressRoutineEnd:
  274. //
  275. // Clean up the block allocator.
  276. //
  277. if (BlockAllocator != NULL) {
  278. MmDestroyBlockAllocator(BlockAllocator);
  279. }
  280. if (Array != NULL) {
  281. MmFreePagedPool(Array);
  282. }
  283. //
  284. // Save the results.
  285. //
  286. if (!KSUCCESS(Status)) {
  287. Information->Results.Status = Status;
  288. }
  289. Information->Results.Failures += Failures;
  290. if (ThreadNumber == 0) {
  291. Information->Results.Results[0] = MaxAllocationCount;
  292. Information->Results.Results[1] = MaxAllocatedMemory;
  293. }
  294. RtlAtomicAdd32(&(Information->ThreadsFinished), 1);
  295. return;
  296. }