1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/kernel.h>
5 #include <linux/types.h>
10 #include <sys/resource.h>
11 #include <api/fs/fs.h>
19 static char *test_file(int size)
21 #define TEMPL "/tmp/perf-test-XXXXXX"
22 static char buf_templ[sizeof(TEMPL)];
23 char *templ = buf_templ;
27 strcpy(buf_templ, TEMPL);
32 perror("mkstemp failed");
42 for (i = 0; i < size; i++)
43 buf[i] = (unsigned char) ((int) i % 10);
45 if (size != write(fd, buf, size))
53 #define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
55 struct test_data_offset {
61 struct test_data_offset offsets[] = {
62 /* Fill first cache page. */
65 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
68 /* Read first cache page. */
71 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
74 /* Fill cache boundary pages. */
76 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
77 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
80 /* Read cache boundary pages. */
82 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
83 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
86 /* Fill final cache page. */
88 .offset = TEST_FILE_SIZE - 10,
89 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
92 /* Read final cache page. */
94 .offset = TEST_FILE_SIZE - 10,
95 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
98 /* Read final cache page. */
100 .offset = TEST_FILE_SIZE - 3,
101 .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
106 /* move it from util/dso.c for compatibility */
107 static int dso__data_fd(struct dso *dso, struct machine *machine)
109 int fd = dso__data_get_fd(dso, machine);
112 dso__data_put_fd(dso);
117 int test__dso_data(struct test *test __maybe_unused, int subtest __maybe_unused)
119 struct machine machine;
121 char *file = test_file(TEST_FILE_SIZE);
124 TEST_ASSERT_VAL("No test file", file);
126 memset(&machine, 0, sizeof(machine));
128 dso = dso__new((const char *)file);
130 TEST_ASSERT_VAL("Failed to access to dso",
131 dso__data_fd(dso, &machine) >= 0);
133 /* Basic 10 bytes tests. */
134 for (i = 0; i < ARRAY_SIZE(offsets); i++) {
135 struct test_data_offset *data = &offsets[i];
140 size = dso__data_read_offset(dso, &machine, data->offset,
143 TEST_ASSERT_VAL("Wrong size", size == data->size);
144 TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
147 /* Read cross multiple cache pages. */
153 buf = malloc(TEST_FILE_SIZE);
154 TEST_ASSERT_VAL("ENOMEM\n", buf);
156 /* First iteration to fill caches, second one to read them. */
157 for (c = 0; c < 2; c++) {
158 memset(buf, 0, TEST_FILE_SIZE);
159 size = dso__data_read_offset(dso, &machine, 10,
160 buf, TEST_FILE_SIZE);
162 TEST_ASSERT_VAL("Wrong size",
163 size == (TEST_FILE_SIZE - 10));
165 for (i = 0; i < (size_t)size; i++)
166 TEST_ASSERT_VAL("Wrong data",
178 static long open_files_cnt(void)
185 scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint());
186 pr_debug("fd path: %s\n", path);
189 TEST_ASSERT_VAL("failed to open fd directory", dir);
191 while ((dent = readdir(dir)) != NULL) {
192 if (!strcmp(dent->d_name, ".") ||
193 !strcmp(dent->d_name, ".."))
203 static struct dso **dsos;
205 static int dsos__create(int cnt, int size)
209 dsos = malloc(sizeof(*dsos) * cnt);
210 TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
212 for (i = 0; i < cnt; i++) {
215 file = test_file(size);
216 TEST_ASSERT_VAL("failed to get dso file", file);
218 dsos[i] = dso__new(file);
219 TEST_ASSERT_VAL("failed to get dso", dsos[i]);
225 static void dsos__delete(int cnt)
229 for (i = 0; i < cnt; i++) {
230 struct dso *dso = dsos[i];
239 static int set_fd_limit(int n)
243 if (getrlimit(RLIMIT_NOFILE, &rlim))
246 pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n);
249 return setrlimit(RLIMIT_NOFILE, &rlim);
252 int test__dso_data_cache(struct test *test __maybe_unused, int subtest __maybe_unused)
254 struct machine machine;
255 long nr_end, nr = open_files_cnt();
256 int dso_cnt, limit, i, fd;
258 /* Rest the internal dso open counter limit. */
261 memset(&machine, 0, sizeof(machine));
263 /* set as system limit */
265 TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
267 /* and this is now our dso open FDs limit */
269 TEST_ASSERT_VAL("failed to create dsos\n",
270 !dsos__create(dso_cnt, TEST_FILE_SIZE));
272 for (i = 0; i < (dso_cnt - 1); i++) {
273 struct dso *dso = dsos[i];
276 * Open dsos via dso__data_fd(), it opens the data
277 * file and keep it open (unless open file limit).
279 fd = dso__data_fd(dso, &machine);
280 TEST_ASSERT_VAL("failed to get fd", fd > 0);
287 n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE);
288 TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE);
292 /* verify the first one is already open */
293 TEST_ASSERT_VAL("dsos[0] is not open", dsos[0]->data.fd != -1);
295 /* open +1 dso to reach the allowed limit */
296 fd = dso__data_fd(dsos[i], &machine);
297 TEST_ASSERT_VAL("failed to get fd", fd > 0);
299 /* should force the first one to be closed */
300 TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1);
302 /* cleanup everything */
303 dsos__delete(dso_cnt);
305 /* Make sure we did not leak any file descriptor. */
306 nr_end = open_files_cnt();
307 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
308 TEST_ASSERT_VAL("failed leaking files", nr == nr_end);
312 int test__dso_data_reopen(struct test *test __maybe_unused, int subtest __maybe_unused)
314 struct machine machine;
315 long nr_end, nr = open_files_cnt();
318 #define dso_0 (dsos[0])
319 #define dso_1 (dsos[1])
320 #define dso_2 (dsos[2])
322 /* Rest the internal dso open counter limit. */
325 memset(&machine, 0, sizeof(machine));
329 * - create 3 dso objects
330 * - set process file descriptor limit to current
332 * - test that the first dso gets closed when we
333 * reach the files count limit
336 /* Make sure we are able to open 3 fds anyway */
337 TEST_ASSERT_VAL("failed to set file limit",
338 !set_fd_limit((nr + 3)));
340 TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
343 fd = dso__data_fd(dso_0, &machine);
344 TEST_ASSERT_VAL("failed to get fd", fd > 0);
347 fd = dso__data_fd(dso_1, &machine);
348 TEST_ASSERT_VAL("failed to get fd", fd > 0);
351 * open extra file descriptor and we just
352 * reached the files count limit
354 fd_extra = open("/dev/null", O_RDONLY);
355 TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0);
358 fd = dso__data_fd(dso_2, &machine);
359 TEST_ASSERT_VAL("failed to get fd", fd > 0);
362 * dso_0 should get closed, because we reached
363 * the file descriptor limit
365 TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1);
368 fd = dso__data_fd(dso_0, &machine);
369 TEST_ASSERT_VAL("failed to get fd", fd > 0);
372 * dso_1 should get closed, because we reached
373 * the file descriptor limit
375 TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1);
377 /* cleanup everything */
381 /* Make sure we did not leak any file descriptor. */
382 nr_end = open_files_cnt();
383 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
384 TEST_ASSERT_VAL("failed leaking files", nr == nr_end);