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