1#include <stdlib.h>
2#include <linux/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <string.h>
6#include <sys/time.h>
7#include <sys/resource.h>
8#include <api/fs/fs.h>
9#include "util.h"
10#include "machine.h"
11#include "symbol.h"
12#include "tests.h"
13#include "debug.h"
14
15static char *test_file(int size)
16{
17#define TEMPL "/tmp/perf-test-XXXXXX"
18 static char buf_templ[sizeof(TEMPL)];
19 char *templ = buf_templ;
20 int fd, i;
21 unsigned char *buf;
22
23 strcpy(buf_templ, TEMPL);
24#undef TEMPL
25
26 fd = mkstemp(templ);
27 if (fd < 0) {
28 perror("mkstemp failed");
29 return NULL;
30 }
31
32 buf = malloc(size);
33 if (!buf) {
34 close(fd);
35 return NULL;
36 }
37
38 for (i = 0; i < size; i++)
39 buf[i] = (unsigned char) ((int) i % 10);
40
41 if (size != write(fd, buf, size))
42 templ = NULL;
43
44 free(buf);
45 close(fd);
46 return templ;
47}
48
49#define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
50
51struct test_data_offset {
52 off_t offset;
53 u8 data[10];
54 int size;
55};
56
57struct test_data_offset offsets[] = {
58
59 {
60 .offset = 10,
61 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
62 .size = 10,
63 },
64
65 {
66 .offset = 10,
67 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
68 .size = 10,
69 },
70
71 {
72 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
73 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
74 .size = 10,
75 },
76
77 {
78 .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
79 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
80 .size = 10,
81 },
82
83 {
84 .offset = TEST_FILE_SIZE - 10,
85 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
86 .size = 10,
87 },
88
89 {
90 .offset = TEST_FILE_SIZE - 10,
91 .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
92 .size = 10,
93 },
94
95 {
96 .offset = TEST_FILE_SIZE - 3,
97 .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
98 .size = 3,
99 },
100};
101
102
103static int dso__data_fd(struct dso *dso, struct machine *machine)
104{
105 int fd = dso__data_get_fd(dso, machine);
106
107 if (fd >= 0)
108 dso__data_put_fd(dso);
109
110 return fd;
111}
112
113int test__dso_data(int subtest __maybe_unused)
114{
115 struct machine machine;
116 struct dso *dso;
117 char *file = test_file(TEST_FILE_SIZE);
118 size_t i;
119
120 TEST_ASSERT_VAL("No test file", file);
121
122 memset(&machine, 0, sizeof(machine));
123
124 dso = dso__new((const char *)file);
125
126 TEST_ASSERT_VAL("Failed to access to dso",
127 dso__data_fd(dso, &machine) >= 0);
128
129
130 for (i = 0; i < ARRAY_SIZE(offsets); i++) {
131 struct test_data_offset *data = &offsets[i];
132 ssize_t size;
133 u8 buf[10];
134
135 memset(buf, 0, 10);
136 size = dso__data_read_offset(dso, &machine, data->offset,
137 buf, 10);
138
139 TEST_ASSERT_VAL("Wrong size", size == data->size);
140 TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
141 }
142
143
144 {
145 ssize_t size;
146 int c;
147 u8 *buf;
148
149 buf = malloc(TEST_FILE_SIZE);
150 TEST_ASSERT_VAL("ENOMEM\n", buf);
151
152
153 for (c = 0; c < 2; c++) {
154 memset(buf, 0, TEST_FILE_SIZE);
155 size = dso__data_read_offset(dso, &machine, 10,
156 buf, TEST_FILE_SIZE);
157
158 TEST_ASSERT_VAL("Wrong size",
159 size == (TEST_FILE_SIZE - 10));
160
161 for (i = 0; i < (size_t)size; i++)
162 TEST_ASSERT_VAL("Wrong data",
163 buf[i] == (i % 10));
164 }
165
166 free(buf);
167 }
168
169 dso__put(dso);
170 unlink(file);
171 return 0;
172}
173
174static long open_files_cnt(void)
175{
176 char path[PATH_MAX];
177 struct dirent *dent;
178 DIR *dir;
179 long nr = 0;
180
181 scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint());
182 pr_debug("fd path: %s\n", path);
183
184 dir = opendir(path);
185 TEST_ASSERT_VAL("failed to open fd directory", dir);
186
187 while ((dent = readdir(dir)) != NULL) {
188 if (!strcmp(dent->d_name, ".") ||
189 !strcmp(dent->d_name, ".."))
190 continue;
191
192 nr++;
193 }
194
195 closedir(dir);
196 return nr - 1;
197}
198
199static struct dso **dsos;
200
201static int dsos__create(int cnt, int size)
202{
203 int i;
204
205 dsos = malloc(sizeof(dsos) * cnt);
206 TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
207
208 for (i = 0; i < cnt; i++) {
209 char *file;
210
211 file = test_file(size);
212 TEST_ASSERT_VAL("failed to get dso file", file);
213
214 dsos[i] = dso__new(file);
215 TEST_ASSERT_VAL("failed to get dso", dsos[i]);
216 }
217
218 return 0;
219}
220
221static void dsos__delete(int cnt)
222{
223 int i;
224
225 for (i = 0; i < cnt; i++) {
226 struct dso *dso = dsos[i];
227
228 unlink(dso->name);
229 dso__put(dso);
230 }
231
232 free(dsos);
233}
234
235static int set_fd_limit(int n)
236{
237 struct rlimit rlim;
238
239 if (getrlimit(RLIMIT_NOFILE, &rlim))
240 return -1;
241
242 pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n);
243
244 rlim.rlim_cur = n;
245 return setrlimit(RLIMIT_NOFILE, &rlim);
246}
247
248int test__dso_data_cache(int subtest __maybe_unused)
249{
250 struct machine machine;
251 long nr_end, nr = open_files_cnt();
252 int dso_cnt, limit, i, fd;
253
254 memset(&machine, 0, sizeof(machine));
255
256
257 limit = nr * 4;
258 TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
259
260
261 dso_cnt = limit / 2;
262 TEST_ASSERT_VAL("failed to create dsos\n",
263 !dsos__create(dso_cnt, TEST_FILE_SIZE));
264
265 for (i = 0; i < (dso_cnt - 1); i++) {
266 struct dso *dso = dsos[i];
267
268
269
270
271
272 fd = dso__data_fd(dso, &machine);
273 TEST_ASSERT_VAL("failed to get fd", fd > 0);
274
275 if (i % 2) {
276 #define BUFSIZE 10
277 u8 buf[BUFSIZE];
278 ssize_t n;
279
280 n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE);
281 TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE);
282 }
283 }
284
285
286 TEST_ASSERT_VAL("dsos[0] is not open", dsos[0]->data.fd != -1);
287
288
289 fd = dso__data_fd(dsos[i], &machine);
290 TEST_ASSERT_VAL("failed to get fd", fd > 0);
291
292
293 TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1);
294
295
296 dsos__delete(dso_cnt);
297
298
299 nr_end = open_files_cnt();
300 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
301 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
302 return 0;
303}
304
305int test__dso_data_reopen(int subtest __maybe_unused)
306{
307 struct machine machine;
308 long nr_end, nr = open_files_cnt();
309 int fd, fd_extra;
310
311#define dso_0 (dsos[0])
312#define dso_1 (dsos[1])
313#define dso_2 (dsos[2])
314
315 memset(&machine, 0, sizeof(machine));
316
317
318
319
320
321
322
323
324
325
326
327 TEST_ASSERT_VAL("failed to set file limit",
328 !set_fd_limit((nr + 3)));
329
330 TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
331
332
333 fd = dso__data_fd(dso_0, &machine);
334 TEST_ASSERT_VAL("failed to get fd", fd > 0);
335
336
337 fd = dso__data_fd(dso_1, &machine);
338 TEST_ASSERT_VAL("failed to get fd", fd > 0);
339
340
341
342
343
344 fd_extra = open("/dev/null", O_RDONLY);
345 TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0);
346
347
348 fd = dso__data_fd(dso_2, &machine);
349 TEST_ASSERT_VAL("failed to get fd", fd > 0);
350
351
352
353
354
355 TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1);
356
357
358 fd = dso__data_fd(dso_0, &machine);
359 TEST_ASSERT_VAL("failed to get fd", fd > 0);
360
361
362
363
364
365 TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1);
366
367
368 close(fd_extra);
369 dsos__delete(3);
370
371
372 nr_end = open_files_cnt();
373 pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
374 TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
375 return 0;
376}
377