diff mbox series

[v21,01/13] trace-cmd: Find and store pids of tasks, which run virtual CPUs of given VM

Message ID 20200302101404.150035-2-tz.stoyanov@gmail.com (mailing list archive)
State Superseded
Headers show
Series Timestamp synchronization of host - guest tracing session | expand

Commit Message

Tzvetomir Stoyanov (VMware) March 2, 2020, 10:13 a.m. UTC
From: Tzvetomir Stoyanov <tstoyanov@vmware.com>

In order to match host and guest events, a mapping between guest VCPU
and the host task, running this VCPU is needed. Extended existing
struct guest to hold such mapping and added logic in read_qemu_guests()
function to initialize it. Implemented a new internal API,
get_guest_vcpu_pid(), to retrieve VCPU-task mapping for given VM.

Signed-off-by: Tzvetomir Stoyanov <tstoyanov@vmware.com>
---
 tracecmd/include/trace-local.h |  2 +
 tracecmd/trace-record.c        | 84 ++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

Comments

Steven Rostedt March 2, 2020, 4:25 p.m. UTC | #1
On Mon,  2 Mar 2020 12:13:52 +0200
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:

> +static int read_qemu_guests_pids(char *guest_task, struct guest *guest)
> +{
> +	struct dirent *entry;
> +	char path[PATH_MAX];
> +	char *buf = NULL;
> +	size_t n = 0;
> +	long vcpu;
> +	long pid;
> +	DIR *dir;
> +	FILE *f;

	int ret = 0;

> +
> +	snprintf(path, sizeof(path), "/proc/%s/task", guest_task);
> +	dir = opendir(path);
> +	if (!dir)
> +		return -1;
> +
> +	while ((entry = readdir(dir))) {

	while (!ret && (entry = readdir(dir)) {

> +		if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
> +			continue;
> +
> +		snprintf(path, sizeof(path), "/proc/%s/task/%s/comm",
> +			 guest_task, entry->d_name);
> +		f = fopen(path, "r");
> +		if (!f)
> +			continue;
> +
> +		if (getline(&buf, &n, f) >= 0 &&
> +		    strncmp(buf, "CPU ", 4) == 0) {
> +			vcpu = strtol(buf + 4, NULL, 10);
> +			pid = strtol(entry->d_name, NULL, 10);
> +			if (vcpu < INT_MAX && pid < INT_MAX &&
> +			    vcpu >= 0 && pid >= 0) {
> +				if (set_vcpu_pid_mapping(guest, vcpu, pid))
> +					return -1;
> +			}

Perhaps this should error on else. Also, you don't want a return here, but
instead, a break.

				if (...) {
					ret = -1;
					break;
				}

> +		}
> +
> +		fclose(f);
> +	}
> +	free(buf);
> +	return 0;

	return ret;

Otherwise you don't close the file descriptor and free buf.

-- Steve


> +}
> +
>  static void read_qemu_guests(void)
>  {
>  	static bool initialized;
> @@ -3115,6 +3179,10 @@ static void read_qemu_guests(void)
>  		if (!is_qemu)
>  			goto next;
>  
> +		if (read_qemu_guests_pids(entry->d_name, &guest))
> +			warning("Failed to retrieve VPCU - PID mapping for guest %s",
> +					guest.name ? guest.name : "Unknown");
> +
>  		guests = realloc(guests, (guests_len + 1) * sizeof(*guests));
>  		if (!guests)
>  			die("Can not allocate guest buffer");
> @@ -3160,6 +3228,22 @@ static char *parse_guest_name(char *guest, int *cid, int *port)
>  	return guest;
>  }
>  
> +int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu)
> +{
> +	int i;
> +
> +	if (!guests)
> +		return -1;
> +
> +	for (i = 0; i < guests_len; i++) {
> +		if (guests[i].cpu_pid < 0 || guest_vcpu >= guests[i].cpu_max)
> +			continue;
> +		if (guest_cid == guests[i].cid)
> +			return guests[i].cpu_pid[guest_vcpu];
> +	}
> +	return -1;
> +}
> +
>  static void set_prio(int prio)
>  {
>  	struct sched_param sp;
Steven Rostedt March 2, 2020, 4:33 p.m. UTC | #2
On Mon,  2 Mar 2020 12:13:52 +0200
"Tzvetomir Stoyanov (VMware)" <tz.stoyanov@gmail.com> wrote:

> +static int set_vcpu_pid_mapping(struct guest *guest, int cpu, int pid)
> +{
> +	int *cpu_pid;
> +	int i;
> +
> +	if (cpu >= guest->cpu_max) {
> +		cpu_pid = realloc(guest->cpu_pid, (cpu + 1) * sizeof(int));
> +		if (!cpu_pid)
> +			return -1;
> +		/* Handle sparse CPU numbers */
> +		for (i = guest->cpu_max; i < cpu; i++)
> +			guest->cpu_pid[i] = -1;

That needs to be: cpu_pid[i] = -1; as realloc() may have freed
guest->cpu_pid here.

-- Steve

> +		guest->cpu_max = cpu + 1;
> +		guest->cpu_pid = cpu_pid;
> +	}
> +	guest->cpu_pid[cpu] = pid;
> +	return 0;
> +}
diff mbox series

Patch

diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h
index 29f27793..a5cf0640 100644
--- a/tracecmd/include/trace-local.h
+++ b/tracecmd/include/trace-local.h
@@ -247,6 +247,8 @@  void update_first_instance(struct buffer_instance *instance, int topt);
 
 void show_instance_file(struct buffer_instance *instance, const char *name);
 
+int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu);
+
 /* moved from trace-cmd.h */
 void tracecmd_create_top_instance(char *name);
 void tracecmd_remove_instances(void);
diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c
index 0a3851ad..3cbc832c 100644
--- a/tracecmd/trace-record.c
+++ b/tracecmd/trace-record.c
@@ -3035,11 +3035,32 @@  struct guest {
 	char *name;
 	int cid;
 	int pid;
+	int cpu_max;
+	int *cpu_pid;
 };
 
 static struct guest *guests;
 static size_t guests_len;
 
+static int set_vcpu_pid_mapping(struct guest *guest, int cpu, int pid)
+{
+	int *cpu_pid;
+	int i;
+
+	if (cpu >= guest->cpu_max) {
+		cpu_pid = realloc(guest->cpu_pid, (cpu + 1) * sizeof(int));
+		if (!cpu_pid)
+			return -1;
+		/* Handle sparse CPU numbers */
+		for (i = guest->cpu_max; i < cpu; i++)
+			guest->cpu_pid[i] = -1;
+		guest->cpu_max = cpu + 1;
+		guest->cpu_pid = cpu_pid;
+	}
+	guest->cpu_pid[cpu] = pid;
+	return 0;
+}
+
 static char *get_qemu_guest_name(char *arg)
 {
 	char *tok, *end = arg;
@@ -3052,6 +3073,49 @@  static char *get_qemu_guest_name(char *arg)
 	return arg;
 }
 
+static int read_qemu_guests_pids(char *guest_task, struct guest *guest)
+{
+	struct dirent *entry;
+	char path[PATH_MAX];
+	char *buf = NULL;
+	size_t n = 0;
+	long vcpu;
+	long pid;
+	DIR *dir;
+	FILE *f;
+
+	snprintf(path, sizeof(path), "/proc/%s/task", guest_task);
+	dir = opendir(path);
+	if (!dir)
+		return -1;
+
+	while ((entry = readdir(dir))) {
+		if (!(entry->d_type == DT_DIR && is_digits(entry->d_name)))
+			continue;
+
+		snprintf(path, sizeof(path), "/proc/%s/task/%s/comm",
+			 guest_task, entry->d_name);
+		f = fopen(path, "r");
+		if (!f)
+			continue;
+
+		if (getline(&buf, &n, f) >= 0 &&
+		    strncmp(buf, "CPU ", 4) == 0) {
+			vcpu = strtol(buf + 4, NULL, 10);
+			pid = strtol(entry->d_name, NULL, 10);
+			if (vcpu < INT_MAX && pid < INT_MAX &&
+			    vcpu >= 0 && pid >= 0) {
+				if (set_vcpu_pid_mapping(guest, vcpu, pid))
+					return -1;
+			}
+		}
+
+		fclose(f);
+	}
+	free(buf);
+	return 0;
+}
+
 static void read_qemu_guests(void)
 {
 	static bool initialized;
@@ -3115,6 +3179,10 @@  static void read_qemu_guests(void)
 		if (!is_qemu)
 			goto next;
 
+		if (read_qemu_guests_pids(entry->d_name, &guest))
+			warning("Failed to retrieve VPCU - PID mapping for guest %s",
+					guest.name ? guest.name : "Unknown");
+
 		guests = realloc(guests, (guests_len + 1) * sizeof(*guests));
 		if (!guests)
 			die("Can not allocate guest buffer");
@@ -3160,6 +3228,22 @@  static char *parse_guest_name(char *guest, int *cid, int *port)
 	return guest;
 }
 
+int get_guest_vcpu_pid(unsigned int guest_cid, unsigned int guest_vcpu)
+{
+	int i;
+
+	if (!guests)
+		return -1;
+
+	for (i = 0; i < guests_len; i++) {
+		if (guests[i].cpu_pid < 0 || guest_vcpu >= guests[i].cpu_max)
+			continue;
+		if (guest_cid == guests[i].cid)
+			return guests[i].cpu_pid[guest_vcpu];
+	}
+	return -1;
+}
+
 static void set_prio(int prio)
 {
 	struct sched_param sp;