Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/util.h"
9 : : #include "spdk/queue.h"
10 : : #include "spdk_internal/cunit.h"
11 : :
12 : : #include <rte_config.h>
13 : : #include <rte_version.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_eal_memconfig.h>
16 : : #include <rte_eal.h>
17 : :
18 : : struct mem_allocation {
19 : : uintptr_t vaddr;
20 : : size_t len;
21 : : TAILQ_ENTRY(mem_allocation) link;
22 : : };
23 : :
24 : : static TAILQ_HEAD(, mem_allocation) g_mem_allocations = TAILQ_HEAD_INITIALIZER(g_mem_allocations);
25 : :
26 : : static void
27 : 114 : memory_hotplug_cb(enum rte_mem_event event_type, const void *addr, size_t len, void *arg)
28 : : {
29 : : struct mem_allocation *allocation;
30 : :
31 [ + + ]: 114 : if (event_type == RTE_MEM_EVENT_ALLOC) {
32 : 57 : allocation = calloc(1, sizeof(*allocation));
33 [ - + ]: 57 : SPDK_CU_ASSERT_FATAL(allocation != NULL);
34 : :
35 [ - + ]: 57 : printf("register %p %ju\n", addr, len);
36 : 57 : allocation->vaddr = (uintptr_t)addr;
37 : 57 : allocation->len = len;
38 : 57 : TAILQ_INSERT_TAIL(&g_mem_allocations, allocation, link);
39 [ + - ]: 57 : } else if (event_type == RTE_MEM_EVENT_FREE) {
40 [ + - ]: 114 : TAILQ_FOREACH(allocation, &g_mem_allocations, link) {
41 [ + + + - ]: 114 : if (allocation->vaddr == (uintptr_t)addr && allocation->len == len) {
42 : 57 : break;
43 : : }
44 : : }
45 [ - + - + ]: 57 : printf("unregister %p %ju %s\n", addr, len, allocation == NULL ? "FAILED" : "PASSED");
46 [ - + ]: 57 : SPDK_CU_ASSERT_FATAL(allocation != NULL);
47 [ + + ]: 57 : TAILQ_REMOVE(&g_mem_allocations, allocation, link);
48 : 57 : free(allocation);
49 : : }
50 : 114 : }
51 : :
52 : : static int
53 : 19 : memory_iter_cb(const struct rte_memseg_list *msl,
54 : : const struct rte_memseg *ms, size_t len, void *arg)
55 : : {
56 : : struct mem_allocation *allocation;
57 : :
58 : 19 : allocation = calloc(1, sizeof(*allocation));
59 [ - + ]: 19 : SPDK_CU_ASSERT_FATAL(allocation != NULL);
60 : :
61 [ - + ]: 19 : printf("register %p %ju\n", ms->addr, len);
62 : 19 : allocation->vaddr = (uintptr_t)ms->addr;
63 : 19 : allocation->len = len;
64 : 19 : TAILQ_INSERT_TAIL(&g_mem_allocations, allocation, link);
65 : :
66 : 19 : return 0;
67 : : }
68 : :
69 : : static void
70 : 76 : verify_buffer(void *_buf, size_t len)
71 : : {
72 : 76 : uintptr_t buf = (uintptr_t)_buf;
73 : : struct mem_allocation *allocation;
74 : :
75 [ - + ]: 76 : SPDK_CU_ASSERT_FATAL(_buf != NULL);
76 [ - + ]: 76 : printf("buf %p len %ju ", _buf, len);
77 [ + - ]: 171 : TAILQ_FOREACH(allocation, &g_mem_allocations, link) {
78 [ + - ]: 171 : if (buf >= allocation->vaddr &&
79 [ + + ]: 171 : buf + len <= allocation->vaddr + allocation->len) {
80 : 76 : break;
81 : : }
82 : : }
83 [ - + - + ]: 76 : printf("%s\n", allocation == NULL ? "FAILED" : "PASSED");
84 : 76 : CU_ASSERT(allocation != NULL);
85 : 76 : }
86 : :
87 : : static void
88 : 19 : test(void)
89 : : {
90 : : void *buf1, *buf2, *buf3, *buf4;
91 : : size_t len1, len2, len3, len4;
92 : :
93 : 19 : printf("\n");
94 : :
95 : 19 : rte_mem_event_callback_register("test", memory_hotplug_cb, NULL);
96 : 19 : rte_memseg_contig_walk(memory_iter_cb, NULL);
97 : :
98 : : /* First allocate a 3MB buffer. This will allocate a 4MB hugepage
99 : : * region, with the 3MB buffer allocated from the end of it.
100 : : */
101 : 19 : len1 = 3 * 1024 * 1024;
102 [ - + ]: 19 : printf("malloc %ju\n", len1);
103 : 19 : buf1 = rte_malloc(NULL, len1, 0);
104 : 19 : verify_buffer(buf1, len1);
105 : :
106 : : /* Now allocate a very small buffer. This will get allocated from
107 : : * the previous 4MB hugepage allocation, just before the 3MB buffer
108 : : * allocated just above.
109 : : */
110 : 19 : len2 = 64;
111 [ - + ]: 19 : printf("malloc %ju\n", len2);
112 : 19 : buf2 = rte_malloc(NULL, len2, 0);
113 : 19 : verify_buffer(buf2, len2);
114 : :
115 : : /* Allocate a 4MB buffer. This should trigger a new hugepage allocation
116 : : * just for this 4MB buffer.
117 : : */
118 : 19 : len3 = 4 * 1024 * 1024;
119 [ - + ]: 19 : printf("malloc %ju\n", len3);
120 : 19 : buf3 = rte_malloc(NULL, len3, 0);
121 : 19 : verify_buffer(buf3, len3);
122 : :
123 : : /* Free the three buffers. Specifically free buf1 first. buf2 was
124 : : * allocated from the same huge page allocation as buf1 - so we want
125 : : * to make sure that DPDK doesn't try to free part of the first huge
126 : : * page allocation - it needs to wait until buf2 is also freed so it
127 : : * can free all of it.
128 : : */
129 [ - + ]: 19 : printf("free %p %ju\n", buf1, len1);
130 : 19 : rte_free(buf1);
131 [ - + ]: 19 : printf("free %p %ju\n", buf2, len2);
132 : 19 : rte_free(buf2);
133 [ - + ]: 19 : printf("free %p %ju\n", buf3, len3);
134 : 19 : rte_free(buf3);
135 : :
136 : : /* Do a single 8MB hugepage allocation and then free it. This covers
137 : : * the more simple case.
138 : : */
139 : 19 : len4 = 8 * 1024 * 1024;
140 [ - + ]: 19 : printf("malloc %ju\n", len4);
141 : 19 : buf4 = rte_malloc(NULL, len4, 0);
142 : 19 : verify_buffer(buf4, len4);
143 : :
144 [ - + ]: 19 : printf("free %p %ju\n", buf4, len4);
145 : 19 : rte_free(buf4);
146 : 19 : }
147 : :
148 : : int
149 : 19 : main(int argc, char **argv)
150 : : {
151 : 19 : CU_pSuite suite = NULL;
152 : : unsigned int num_failures;
153 : 19 : char *dpdk_arg[] = {
154 : : "mem_callbacks", "-c 0x1",
155 : : "--base-virtaddr=0x200000000000",
156 : : "--match-allocations",
157 : : };
158 : : int rc;
159 : :
160 : 19 : rc = rte_eal_init(SPDK_COUNTOF(dpdk_arg), dpdk_arg);
161 [ - + ]: 19 : if (rc < 0) {
162 [ # # ]: 0 : printf("Err: Unable to initialize DPDK\n");
163 : 0 : return 1;
164 : : }
165 : :
166 [ - + ]: 19 : if (CU_initialize_registry() != CUE_SUCCESS) {
167 : 0 : return CU_get_error();
168 : : }
169 : :
170 : 19 : suite = CU_add_suite("memory", NULL, NULL);
171 [ - + ]: 19 : if (suite == NULL) {
172 : 0 : CU_cleanup_registry();
173 : 0 : return CU_get_error();
174 : : }
175 : :
176 [ - + ]: 19 : if (
177 : 19 : CU_add_test(suite, "test", test) == NULL
178 : : ) {
179 : 0 : CU_cleanup_registry();
180 : 0 : return CU_get_error();
181 : : }
182 : :
183 : 19 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
184 : 19 : CU_cleanup_registry();
185 : :
186 : 19 : return num_failures;
187 : : }
|