root/tools/perf/tests/dso-data.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_file
  2. dso__data_fd
  3. test__dso_data
  4. open_files_cnt
  5. dsos__create
  6. dsos__delete
  7. set_fd_limit
  8. test__dso_data_cache
  9. test__dso_data_reopen

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

/* [<][>][^][v][top][bottom][index][help] */