Skip to content

Commit 37862d6

Browse files
captain5050acmel
authored andcommitted
perf dso: Use container_of() to avoid a pointer in 'struct dso_data'
The dso pointer in 'struct dso_data' is necessary for reference count checking to account for the dso_data forming a global list of open dso's with references to the dso. The dso pointer also allows for the indirection that reference count checking needs. Outside of reference count checking the indirection isn't needed and container_of() is more efficient and saves space. The reference count won't be increased by placing items onto the global list, matching how things were before the reference count checking change, but we assert the dso is in dsos holding it live (and that the set of open dsos is a subset of all dsos for the machine). Update the DSO data tests so that they use a dsos struct to make the invariant true. Signed-off-by: Ian Rogers <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Athira Rajeev <[email protected]> Cc: Changbin Du <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Tiezhu Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 23106e3 commit 37862d6

File tree

3 files changed

+46
-32
lines changed

3 files changed

+46
-32
lines changed

tools/perf/tests/dso-data.c

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sys/resource.h>
1111
#include <api/fs/fs.h>
1212
#include "dso.h"
13+
#include "dsos.h"
1314
#include "machine.h"
1415
#include "symbol.h"
1516
#include "tests.h"
@@ -123,9 +124,10 @@ static int test__dso_data(struct test_suite *test __maybe_unused, int subtest __
123124
TEST_ASSERT_VAL("No test file", file);
124125

125126
memset(&machine, 0, sizeof(machine));
127+
dsos__init(&machine.dsos);
126128

127-
dso = dso__new((const char *)file);
128-
129+
dso = dso__new(file);
130+
TEST_ASSERT_VAL("Failed to add dso", !dsos__add(&machine.dsos, dso));
129131
TEST_ASSERT_VAL("Failed to access to dso",
130132
dso__data_fd(dso, &machine) >= 0);
131133

@@ -170,6 +172,7 @@ static int test__dso_data(struct test_suite *test __maybe_unused, int subtest __
170172
}
171173

172174
dso__put(dso);
175+
dsos__exit(&machine.dsos);
173176
unlink(file);
174177
return 0;
175178
}
@@ -199,41 +202,35 @@ static long open_files_cnt(void)
199202
return nr - 1;
200203
}
201204

202-
static struct dso **dsos;
203-
204-
static int dsos__create(int cnt, int size)
205+
static int dsos__create(int cnt, int size, struct dsos *dsos)
205206
{
206207
int i;
207208

208-
dsos = malloc(sizeof(*dsos) * cnt);
209-
TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
209+
dsos__init(dsos);
210210

211211
for (i = 0; i < cnt; i++) {
212-
char *file;
212+
struct dso *dso;
213+
char *file = test_file(size);
213214

214-
file = test_file(size);
215215
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]);
216+
dso = dso__new(file);
217+
TEST_ASSERT_VAL("failed to get dso", dso);
218+
TEST_ASSERT_VAL("failed to add dso", !dsos__add(dsos, dso));
219+
dso__put(dso);
219220
}
220221

221222
return 0;
222223
}
223224

224-
static void dsos__delete(int cnt)
225+
static void dsos__delete(struct dsos *dsos)
225226
{
226-
int i;
227-
228-
for (i = 0; i < cnt; i++) {
229-
struct dso *dso = dsos[i];
227+
for (unsigned int i = 0; i < dsos->cnt; i++) {
228+
struct dso *dso = dsos->dsos[i];
230229

231230
dso__data_close(dso);
232231
unlink(dso__name(dso));
233-
dso__put(dso);
234232
}
235-
236-
free(dsos);
233+
dsos__exit(dsos);
237234
}
238235

239236
static int set_fd_limit(int n)
@@ -267,10 +264,10 @@ static int test__dso_data_cache(struct test_suite *test __maybe_unused, int subt
267264
/* and this is now our dso open FDs limit */
268265
dso_cnt = limit / 2;
269266
TEST_ASSERT_VAL("failed to create dsos\n",
270-
!dsos__create(dso_cnt, TEST_FILE_SIZE));
267+
!dsos__create(dso_cnt, TEST_FILE_SIZE, &machine.dsos));
271268

272269
for (i = 0; i < (dso_cnt - 1); i++) {
273-
struct dso *dso = dsos[i];
270+
struct dso *dso = machine.dsos.dsos[i];
274271

275272
/*
276273
* Open dsos via dso__data_fd(), it opens the data
@@ -290,17 +287,17 @@ static int test__dso_data_cache(struct test_suite *test __maybe_unused, int subt
290287
}
291288

292289
/* verify the first one is already open */
293-
TEST_ASSERT_VAL("dsos[0] is not open", dso__data(dsos[0])->fd != -1);
290+
TEST_ASSERT_VAL("dsos[0] is not open", dso__data(machine.dsos.dsos[0])->fd != -1);
294291

295292
/* open +1 dso to reach the allowed limit */
296-
fd = dso__data_fd(dsos[i], &machine);
293+
fd = dso__data_fd(machine.dsos.dsos[i], &machine);
297294
TEST_ASSERT_VAL("failed to get fd", fd > 0);
298295

299296
/* should force the first one to be closed */
300-
TEST_ASSERT_VAL("failed to close dsos[0]", dso__data(dsos[0])->fd == -1);
297+
TEST_ASSERT_VAL("failed to close dsos[0]", dso__data(machine.dsos.dsos[0])->fd == -1);
301298

302299
/* cleanup everything */
303-
dsos__delete(dso_cnt);
300+
dsos__delete(&machine.dsos);
304301

305302
/* Make sure we did not leak any file descriptor. */
306303
nr_end = open_files_cnt();
@@ -325,9 +322,9 @@ static int test__dso_data_reopen(struct test_suite *test __maybe_unused, int sub
325322
long nr_end, nr = open_files_cnt(), lim = new_limit(3);
326323
int fd, fd_extra;
327324

328-
#define dso_0 (dsos[0])
329-
#define dso_1 (dsos[1])
330-
#define dso_2 (dsos[2])
325+
#define dso_0 (machine.dsos.dsos[0])
326+
#define dso_1 (machine.dsos.dsos[1])
327+
#define dso_2 (machine.dsos.dsos[2])
331328

332329
/* Rest the internal dso open counter limit. */
333330
reset_fd_limit();
@@ -347,7 +344,8 @@ static int test__dso_data_reopen(struct test_suite *test __maybe_unused, int sub
347344
TEST_ASSERT_VAL("failed to set file limit",
348345
!set_fd_limit((lim)));
349346

350-
TEST_ASSERT_VAL("failed to create dsos\n", !dsos__create(3, TEST_FILE_SIZE));
347+
TEST_ASSERT_VAL("failed to create dsos\n",
348+
!dsos__create(3, TEST_FILE_SIZE, &machine.dsos));
351349

352350
/* open dso_0 */
353351
fd = dso__data_fd(dso_0, &machine);
@@ -386,7 +384,7 @@ static int test__dso_data_reopen(struct test_suite *test __maybe_unused, int sub
386384

387385
/* cleanup everything */
388386
close(fd_extra);
389-
dsos__delete(3);
387+
dsos__delete(&machine.dsos);
390388

391389
/* Make sure we did not leak any file descriptor. */
392390
nr_end = open_files_cnt();

tools/perf/util/dso.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,14 +497,20 @@ static pthread_mutex_t dso__data_open_lock = PTHREAD_MUTEX_INITIALIZER;
497497
static void dso__list_add(struct dso *dso)
498498
{
499499
list_add_tail(&dso__data(dso)->open_entry, &dso__data_open);
500+
#ifdef REFCNT_CHECKING
500501
dso__data(dso)->dso = dso__get(dso);
502+
#endif
503+
/* Assume the dso is part of dsos, hence the optional reference count above. */
504+
assert(dso__dsos(dso));
501505
dso__data_open_cnt++;
502506
}
503507

504508
static void dso__list_del(struct dso *dso)
505509
{
506510
list_del_init(&dso__data(dso)->open_entry);
511+
#ifdef REFCNT_CHECKING
507512
dso__put(dso__data(dso)->dso);
513+
#endif
508514
WARN_ONCE(dso__data_open_cnt <= 0,
509515
"DSO data fd counter out of bounds.");
510516
dso__data_open_cnt--;
@@ -654,9 +660,15 @@ static void close_dso(struct dso *dso)
654660
static void close_first_dso(void)
655661
{
656662
struct dso_data *dso_data;
663+
struct dso *dso;
657664

658665
dso_data = list_first_entry(&dso__data_open, struct dso_data, open_entry);
659-
close_dso(dso_data->dso);
666+
#ifdef REFCNT_CHECKING
667+
dso = dso_data->dso;
668+
#else
669+
dso = container_of(dso_data, struct dso, data);
670+
#endif
671+
close_dso(dso);
660672
}
661673

662674
static rlim_t get_fd_limit(void)
@@ -1449,7 +1461,9 @@ struct dso *dso__new_id(const char *name, struct dso_id *id)
14491461
data->fd = -1;
14501462
data->status = DSO_DATA_STATUS_UNKNOWN;
14511463
INIT_LIST_HEAD(&data->open_entry);
1464+
#ifdef REFCNT_CHECKING
14521465
data->dso = NULL; /* Set when on the open_entry list. */
1466+
#endif
14531467
}
14541468
return res;
14551469
}

tools/perf/util/dso.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ struct dso_cache {
147147
struct dso_data {
148148
struct rb_root cache;
149149
struct list_head open_entry;
150+
#ifdef REFCNT_CHECKING
150151
struct dso *dso;
152+
#endif
151153
int fd;
152154
int status;
153155
u32 status_seen;

0 commit comments

Comments
 (0)