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