diff options
Diffstat (limited to 'tools/perf/tests/dso-data.c')
| -rw-r--r-- | tools/perf/tests/dso-data.c | 217 | 
1 files changed, 212 insertions, 5 deletions
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index dffe0551aca..630808cd7cc 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -1,22 +1,27 @@ -#include "util.h" -  #include <stdlib.h> -#include <sys/types.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"  static char *test_file(int size)  { -	static char buf_templ[] = "/tmp/test-XXXXXX"; +#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"); @@ -35,6 +40,7 @@ static char *test_file(int size)  	if (size != write(fd, buf, size))  		templ = NULL; +	free(buf);  	close(fd);  	return templ;  } @@ -149,3 +155,204 @@ int test__dso_data(void)  	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__delete(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 + 1 extra */ +	dso_cnt = limit / 2 + 1; +	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 or dso__data_read_offset. +		 * Both opens the data file and keep it open. +		 */ +		if (i % 2) { +			fd = dso__data_fd(dso, &machine); +			TEST_ASSERT_VAL("failed to get fd", fd > 0); +		} else { +			#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); +		} +	} + +	/* open +1 dso over 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; +}  | 
