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