123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- #include <stdlib.h>
- #include <linux/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <string.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <api/fs/fs.h>
- #include "util.h"
- #include "machine.h"
- #include "symbol.h"
- #include "tests.h"
- #include "debug.h"
- static char *test_file(int size)
- {
- #define TEMPL "/tmp/perf-test-XXXXXX"
- static char buf_templ[sizeof(TEMPL)];
- char *templ = buf_templ;
- int fd, i;
- unsigned char *buf;
- strcpy(buf_templ, TEMPL);
- #undef TEMPL
- fd = mkstemp(templ);
- if (fd < 0) {
- perror("mkstemp failed");
- return NULL;
- }
- buf = malloc(size);
- if (!buf) {
- close(fd);
- return NULL;
- }
- for (i = 0; i < size; i++)
- buf[i] = (unsigned char) ((int) i % 10);
- if (size != write(fd, buf, size))
- templ = NULL;
- free(buf);
- close(fd);
- return templ;
- }
- #define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
- struct test_data_offset {
- off_t offset;
- u8 data[10];
- int size;
- };
- struct test_data_offset offsets[] = {
- /* Fill first cache page. */
- {
- .offset = 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Read first cache page. */
- {
- .offset = 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Fill cache boundary pages. */
- {
- .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Read cache boundary pages. */
- {
- .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Fill final cache page. */
- {
- .offset = TEST_FILE_SIZE - 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Read final cache page. */
- {
- .offset = TEST_FILE_SIZE - 10,
- .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .size = 10,
- },
- /* Read final cache page. */
- {
- .offset = TEST_FILE_SIZE - 3,
- .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
- .size = 3,
- },
- };
- /* move it from util/dso.c for compatibility */
- static int dso__data_fd(struct dso *dso, struct machine *machine)
- {
- int fd = dso__data_get_fd(dso, machine);
- if (fd >= 0)
- dso__data_put_fd(dso);
- return fd;
- }
- int test__dso_data(void)
- {
- struct machine machine;
- struct dso *dso;
- char *file = test_file(TEST_FILE_SIZE);
- size_t i;
- TEST_ASSERT_VAL("No test file", file);
- memset(&machine, 0, sizeof(machine));
- dso = dso__new((const char *)file);
- TEST_ASSERT_VAL("Failed to access to dso",
- dso__data_fd(dso, &machine) >= 0);
- /* Basic 10 bytes tests. */
- for (i = 0; i < ARRAY_SIZE(offsets); i++) {
- struct test_data_offset *data = &offsets[i];
- ssize_t size;
- u8 buf[10];
- memset(buf, 0, 10);
- size = dso__data_read_offset(dso, &machine, data->offset,
- buf, 10);
- TEST_ASSERT_VAL("Wrong size", size == data->size);
- TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
- }
- /* Read cross multiple cache pages. */
- {
- ssize_t size;
- int c;
- u8 *buf;
- buf = malloc(TEST_FILE_SIZE);
- TEST_ASSERT_VAL("ENOMEM\n", buf);
- /* First iteration to fill caches, second one to read them. */
- for (c = 0; c < 2; c++) {
- memset(buf, 0, TEST_FILE_SIZE);
- size = dso__data_read_offset(dso, &machine, 10,
- buf, TEST_FILE_SIZE);
- TEST_ASSERT_VAL("Wrong size",
- size == (TEST_FILE_SIZE - 10));
- for (i = 0; i < (size_t)size; i++)
- TEST_ASSERT_VAL("Wrong data",
- buf[i] == (i % 10));
- }
- free(buf);
- }
- dso__put(dso);
- unlink(file);
- return 0;
- }
- static long open_files_cnt(void)
- {
- char path[PATH_MAX];
- struct dirent *dent;
- DIR *dir;
- long nr = 0;
- scnprintf(path, PATH_MAX, "%s/self/fd", procfs__mountpoint());
- pr_debug("fd path: %s\n", path);
- dir = opendir(path);
- TEST_ASSERT_VAL("failed to open fd directory", dir);
- while ((dent = readdir(dir)) != NULL) {
- if (!strcmp(dent->d_name, ".") ||
- !strcmp(dent->d_name, ".."))
- continue;
- nr++;
- }
- closedir(dir);
- return nr - 1;
- }
- static struct dso **dsos;
- static int dsos__create(int cnt, int size)
- {
- int i;
- dsos = malloc(sizeof(dsos) * cnt);
- TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
- for (i = 0; i < cnt; i++) {
- char *file;
- file = test_file(size);
- TEST_ASSERT_VAL("failed to get dso file", file);
- dsos[i] = dso__new(file);
- TEST_ASSERT_VAL("failed to get dso", dsos[i]);
- }
- return 0;
- }
- static void dsos__delete(int cnt)
- {
- int i;
- for (i = 0; i < cnt; i++) {
- struct dso *dso = dsos[i];
- unlink(dso->name);
- dso__put(dso);
- }
- free(dsos);
- }
- static int set_fd_limit(int n)
- {
- struct rlimit rlim;
- if (getrlimit(RLIMIT_NOFILE, &rlim))
- return -1;
- pr_debug("file limit %ld, new %d\n", (long) rlim.rlim_cur, n);
- rlim.rlim_cur = n;
- return setrlimit(RLIMIT_NOFILE, &rlim);
- }
- int test__dso_data_cache(void)
- {
- struct machine machine;
- long nr_end, nr = open_files_cnt();
- int dso_cnt, limit, i, fd;
- memset(&machine, 0, sizeof(machine));
- /* set as system limit */
- limit = nr * 4;
- TEST_ASSERT_VAL("failed to set file limit", !set_fd_limit(limit));
- /* and this is now our dso open FDs limit */
- dso_cnt = limit / 2;
- TEST_ASSERT_VAL("failed to create dsos\n",
- !dsos__create(dso_cnt, TEST_FILE_SIZE));
- for (i = 0; i < (dso_cnt - 1); i++) {
- struct dso *dso = dsos[i];
- /*
- * Open dsos via dso__data_fd(), it opens the data
- * file and keep it open (unless open file limit).
- */
- fd = dso__data_fd(dso, &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- if (i % 2) {
- #define BUFSIZE 10
- u8 buf[BUFSIZE];
- ssize_t n;
- n = dso__data_read_offset(dso, &machine, 0, buf, BUFSIZE);
- TEST_ASSERT_VAL("failed to read dso", n == BUFSIZE);
- }
- }
- /* verify the first one is already open */
- TEST_ASSERT_VAL("dsos[0] is not open", dsos[0]->data.fd != -1);
- /* open +1 dso to reach the allowed limit */
- fd = dso__data_fd(dsos[i], &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- /* should force the first one to be closed */
- TEST_ASSERT_VAL("failed to close dsos[0]", dsos[0]->data.fd == -1);
- /* cleanup everything */
- dsos__delete(dso_cnt);
- /* Make sure we did not leak any file descriptor. */
- nr_end = open_files_cnt();
- pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
- TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
- return 0;
- }
- int test__dso_data_reopen(void)
- {
- struct machine machine;
- long nr_end, nr = open_files_cnt();
- int fd, fd_extra;
- #define dso_0 (dsos[0])
- #define dso_1 (dsos[1])
- #define dso_2 (dsos[2])
- memset(&machine, 0, sizeof(machine));
- /*
- * Test scenario:
- * - create 3 dso objects
- * - set process file descriptor limit to current
- * files count + 3
- * - test that the first dso gets closed when we
- * reach the files count limit
- */
- /* Make sure we are able to open 3 fds anyway */
- TEST_ASSERT_VAL("failed to set file limit",
- !set_fd_limit((nr + 3)));
- TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
- /* open dso_0 */
- fd = dso__data_fd(dso_0, &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- /* open dso_1 */
- fd = dso__data_fd(dso_1, &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- /*
- * open extra file descriptor and we just
- * reached the files count limit
- */
- fd_extra = open("/dev/null", O_RDONLY);
- TEST_ASSERT_VAL("failed to open extra fd", fd_extra > 0);
- /* open dso_2 */
- fd = dso__data_fd(dso_2, &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- /*
- * dso_0 should get closed, because we reached
- * the file descriptor limit
- */
- TEST_ASSERT_VAL("failed to close dso_0", dso_0->data.fd == -1);
- /* open dso_0 */
- fd = dso__data_fd(dso_0, &machine);
- TEST_ASSERT_VAL("failed to get fd", fd > 0);
- /*
- * dso_1 should get closed, because we reached
- * the file descriptor limit
- */
- TEST_ASSERT_VAL("failed to close dso_1", dso_1->data.fd == -1);
- /* cleanup everything */
- close(fd_extra);
- dsos__delete(3);
- /* Make sure we did not leak any file descriptor. */
- nr_end = open_files_cnt();
- pr_debug("nr start %ld, nr stop %ld\n", nr, nr_end);
- TEST_ASSERT_VAL("failed leadking files", nr == nr_end);
- return 0;
- }
|