Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf8102f6 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'perf-fdarray-for-mingo' of...

Merge tag 'perf-fdarray-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/core

Pull perf tooling updates from Arnaldo Carvalho de Melo.

Infrastructure changes:

  * We were not handling POLLHUP notifications for event file descriptors.

    Fix it by filtering entries in the events file descriptor array after
    poll() returns, refcounting mmaps so that when the last fd pointing to
    a perf mmap goes away we do the unmap. (Arnaldo Carvalho de Melo)

User visible changes:

  * Now 'record' and 'trace' properly exit when a target thread exits.
    (Arnaldo Carvalho de Melo)

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 521e8bac 46fb3c21
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -10,9 +10,14 @@ LIB_OBJS=

LIB_H += fs/debugfs.h
LIB_H += fs/fs.h
# See comment below about piggybacking...
LIB_H += fd/array.h

LIB_OBJS += $(OUTPUT)fs/debugfs.o
LIB_OBJS += $(OUTPUT)fs/fs.o
# XXX piggybacking here, need to introduce libapikfd, or rename this
# to plain libapik.a and make it have it all api goodies
LIB_OBJS += $(OUTPUT)fd/array.o

LIBFILE = libapikfs.a

@@ -29,7 +34,7 @@ $(LIBFILE): $(LIB_OBJS)
$(LIB_OBJS): $(LIB_H)

libapi_dirs:
	$(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
	$(QUIET_MKDIR)mkdir -p $(OUTPUT)fd $(OUTPUT)fs

$(OUTPUT)%.o: %.c libapi_dirs
	$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+127 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
 *
 * Released under the GPL v2. (and only v2, not any later version)
 */
#include "array.h"
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <unistd.h>

void fdarray__init(struct fdarray *fda, int nr_autogrow)
{
	fda->entries	 = NULL;
	fda->priv	 = NULL;
	fda->nr		 = fda->nr_alloc = 0;
	fda->nr_autogrow = nr_autogrow;
}

int fdarray__grow(struct fdarray *fda, int nr)
{
	void *priv;
	int nr_alloc = fda->nr_alloc + nr;
	size_t psize = sizeof(fda->priv[0]) * nr_alloc;
	size_t size  = sizeof(struct pollfd) * nr_alloc;
	struct pollfd *entries = realloc(fda->entries, size);

	if (entries == NULL)
		return -ENOMEM;

	priv = realloc(fda->priv, psize);
	if (priv == NULL) {
		free(entries);
		return -ENOMEM;
	}

	fda->nr_alloc = nr_alloc;
	fda->entries  = entries;
	fda->priv     = priv;
	return 0;
}

struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow)
{
	struct fdarray *fda = calloc(1, sizeof(*fda));

	if (fda != NULL) {
		if (fdarray__grow(fda, nr_alloc)) {
			free(fda);
			fda = NULL;
		} else {
			fda->nr_autogrow = nr_autogrow;
		}
	}

	return fda;
}

void fdarray__exit(struct fdarray *fda)
{
	free(fda->entries);
	free(fda->priv);
	fdarray__init(fda, 0);
}

void fdarray__delete(struct fdarray *fda)
{
	fdarray__exit(fda);
	free(fda);
}

int fdarray__add(struct fdarray *fda, int fd, short revents)
{
	int pos = fda->nr;

	if (fda->nr == fda->nr_alloc &&
	    fdarray__grow(fda, fda->nr_autogrow) < 0)
		return -ENOMEM;

	fda->entries[fda->nr].fd     = fd;
	fda->entries[fda->nr].events = revents;
	fda->nr++;
	return pos;
}

int fdarray__filter(struct fdarray *fda, short revents,
		    void (*entry_destructor)(struct fdarray *fda, int fd))
{
	int fd, nr = 0;

	if (fda->nr == 0)
		return 0;

	for (fd = 0; fd < fda->nr; ++fd) {
		if (fda->entries[fd].revents & revents) {
			if (entry_destructor)
				entry_destructor(fda, fd);

			continue;
		}

		if (fd != nr) {
			fda->entries[nr] = fda->entries[fd];
			fda->priv[nr]	 = fda->priv[fd];
		}

		++nr;
	}

	return fda->nr = nr;
}

int fdarray__poll(struct fdarray *fda, int timeout)
{
	return poll(fda->entries, fda->nr, timeout);
}

int fdarray__fprintf(struct fdarray *fda, FILE *fp)
{
	int fd, printed = fprintf(fp, "%d [ ", fda->nr);

	for (fd = 0; fd < fda->nr; ++fd)
		printed += fprintf(fp, "%s%d", fd ? ", " : "", fda->entries[fd].fd);

	return printed + fprintf(fp, " ]");
}
+46 −0
Original line number Diff line number Diff line
#ifndef __API_FD_ARRAY__
#define __API_FD_ARRAY__

#include <stdio.h>

struct pollfd;

/**
 * struct fdarray: Array of file descriptors
 *
 * @priv: Per array entry priv area, users should access just its contents,
 *	  not set it to anything, as it is kept in synch with @entries, being
 *	  realloc'ed, * for instance, in fdarray__{grow,filter}.
 *
 *	  I.e. using 'fda->priv[N].idx = * value' where N < fda->nr is ok,
 *	  but doing 'fda->priv = malloc(M)' is not allowed.
 */
struct fdarray {
	int	       nr;
	int	       nr_alloc;
	int	       nr_autogrow;
	struct pollfd *entries;
	union {
		int    idx;
	} *priv;
};

void fdarray__init(struct fdarray *fda, int nr_autogrow);
void fdarray__exit(struct fdarray *fda);

struct fdarray *fdarray__new(int nr_alloc, int nr_autogrow);
void fdarray__delete(struct fdarray *fda);

int fdarray__add(struct fdarray *fda, int fd, short revents);
int fdarray__poll(struct fdarray *fda, int timeout);
int fdarray__filter(struct fdarray *fda, short revents,
		    void (*entry_destructor)(struct fdarray *fda, int fd));
int fdarray__grow(struct fdarray *fda, int extra);
int fdarray__fprintf(struct fdarray *fda, FILE *fp);

static inline int fdarray__available_entries(struct fdarray *fda)
{
	return fda->nr_alloc - fda->nr;
}

#endif /* __API_FD_ARRAY__ */
+2 −1
Original line number Diff line number Diff line
@@ -402,6 +402,7 @@ LIB_OBJS += $(OUTPUT)tests/perf-record.o
LIB_OBJS += $(OUTPUT)tests/rdpmc.o
LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
LIB_OBJS += $(OUTPUT)tests/fdarray.o
LIB_OBJS += $(OUTPUT)tests/pmu.o
LIB_OBJS += $(OUTPUT)tests/hists_common.o
LIB_OBJS += $(OUTPUT)tests/hists_link.o
@@ -769,7 +770,7 @@ $(LIBTRACEEVENT)-clean:
install-traceevent-plugins: $(LIBTRACEEVENT)
	$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins

LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch])

# if subdir is set, we've been called from above so target has been built
# already
+10 −14
Original line number Diff line number Diff line
@@ -919,15 +919,8 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
	signal(SIGINT, sig_handler);
	signal(SIGTERM, sig_handler);

	/* copy pollfds -- need to add timerfd and stdin */
	nr_fds = kvm->evlist->nr_fds;
	pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2));
	if (!pollfds) {
		err = -ENOMEM;
		goto out;
	}
	memcpy(pollfds, kvm->evlist->pollfd,
		sizeof(struct pollfd) * kvm->evlist->nr_fds);
	/* use pollfds -- need to add timerfd and stdin */
	nr_fds = kvm->evlist->pollfd.nr;

	/* add timer fd */
	if (perf_kvm__timerfd_create(kvm) < 0) {
@@ -935,17 +928,21 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
		goto out;
	}

	pollfds[nr_fds].fd = kvm->timerfd;
	pollfds[nr_fds].events = POLLIN;
	if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd))
		goto out;

	nr_fds++;

	pollfds[nr_fds].fd = fileno(stdin);
	pollfds[nr_fds].events = POLLIN;
	if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
		goto out;

	nr_stdin = nr_fds;
	nr_fds++;
	if (fd_set_nonblock(fileno(stdin)) != 0)
		goto out;

	pollfds	 = kvm->evlist->pollfd.entries;

	/* everything is good - enable the events and process */
	perf_evlist__enable(kvm->evlist);

@@ -979,7 +976,6 @@ out:
		close(kvm->timerfd);

	tcsetattr(0, TCSAFLUSH, &save);
	free(pollfds);
	return err;
}

Loading