Re: [RFC] Simple tool for VMEnters/VMExits matching and trace validation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ciao Stefano,

First of all, I am very happy to see you progressing so fast in the development of your VMEnters/VMExits matching analysis. I have several comments concerning the code (see below).

On 16.04.21 г. 19:46, Stefano De Venuto wrote:
Add a tool in examples/ that scans a merged host + guest trace and
search for host events that are inside a vmentry/vmexit block (and
vice-versa for guest events ouside the block) and report the found
ones.

It can be useful as a starting point for identifying issues of for
checking the effectiveness of host/guest traces synchronization, or
even for improving the placing of the tracepoints in the kernel.

Signed-off-by: Stefano De Venuto <stefano.devenuto99@xxxxxxxxx>
---
  examples/checker.c | 202 +++++++++++++++++++++++++++++++++++++++++++++
  1 file changed, 202 insertions(+)
  create mode 100644 examples/checker.c

diff --git a/examples/checker.c b/examples/checker.c
new file mode 100644
index 0000000..0b04343
--- /dev/null
+++ b/examples/checker.c
@@ -0,0 +1,202 @@

The first problem is that this patch fails to apply. My guess is that you hand-edited the patch and removed some lines starting with "+". Note that the total number of additions and removals in the file is indicated in the line above. If this number does not match the number of lines starting with "+", the patch will fail to apply.

As a general advise - try to avoid hand-editing patches unless you are certain you know what you are doing.

Another general problem is that your patch seems to use CRLF for indicating new lines. This makes git produce a lot of warnings.

Please fix this in version 2.

+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libkshark.h"
+#include "libkshark-tepdata.h"
+
+#define KVM_ENTRY "kvm/kvm_entry"
+#define KVM_EXIT "kvm/kvm_exit"
+
+struct custom_stream
+{
+	struct kshark_data_stream* original_stream;
+	int* cpus;
+};
+
+int is_guest(int stream_id,
+	      struct kshark_host_guest_map* mapping,
+	      int n_mapping, int* host)
+{
+	for (int i = 0; i < n_mapping; i++) {
+		if (mapping[i].guest_id == stream_id) {
+			*host = mapping[i].host_id;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+void print_entry(struct kshark_entry* entry)
+{
+	struct kshark_data_stream* stream;
+	char* event_name;
+	int stream_id;
+
+	stream = kshark_get_stream_from_entry(entry);
+	event_name = kshark_get_event_name(entry);
+
+	stream_id = stream->stream_id;
+	printf("%d: %s-%d, %lld [%03d]:%s\t%s\n",
+		stream->stream_id,
+		kshark_get_task(entry),
+		kshark_get_pid(entry),
+		entry->ts,
+		entry->cpu,
+		event_name,
+		kshark_get_info(entry));
+
+}
+

Remove the empty line at the end of the function.


+void print_entries(struct kshark_entry **entries, ssize_t n_entries)
+{
+	for (int i = 0; i < n_entries; ++i
+		print_entry(entries[i]);
+}
+

This function looks like a dead code. It must be removed if you don't use it.

+void free_data(struct kshark_context *kshark_ctx,
+	       struct custom_stream** custom_streams,
+	       struct kshark_entry** entries, int n_entries,
+	       struct kshark_host_guest_map* host_guest_mapping,
+	       int n_guest)
+{
+	struct custom_stream* custom_stream;
+
+	for (int i = 0; i < kshark_ctx->n_streams; i++) {
+		custom_stream = custom_streams[i];
+
+		free(custom_stream->cpus);
+		free(custom_stream);
+	}
+	free(custom_streams);
+
+	for (int i = 0; i < n_entries; i++)
+		free(entries[i]);
+	free(entries);
+
+	kshark_tracecmd_free_hostguest_map(host_guest_mapping, n_guest);
+
+	kshark_close_all(kshark_ctx);
+	kshark_free(kshark_ctx);

kshark_free() calls kshark_close_all() internally. No need to have both.

Also, since this function is called "free_data" and kshark_free() has nothing to do with "data", it may be better to move the call of kshark_free() outside, and place it in main().


+}
+
+int main(int argc, char **argv)
+{
+
Remove the empty line here.
+	struct kshark_host_guest_map* host_guest_mapping;
+	struct custom_stream** custom_streams;
+	struct custom_stream* custom_stream;
+	struct custom_stream* host_stream;
+	struct kshark_data_stream* stream;
+	struct kshark_context* kshark_ctx;
+	struct kshark_entry** entries;
+	struct kshark_entry* current;
+	ssize_t n_entries;
+	char* event_name;
+	char* token;
+	int n_guest;
+	char* info;
+	int host;
+	int v_i;
+	int sd;
+
+	kshark_ctx = NULL;
+	if (!kshark_instance(&kshark_ctx))
+		return 1;
+
+	custom_streams = malloc(sizeof(*custom_streams) * (argc-1));
+
+	for (int i = 1; i < argc; i++) {
+		sd = kshark_open(kshark_ctx, argv[i]);
+		if (sd < 0) {
+			kshark_free(kshark_ctx);
+			return 1;
+		}
+
+		kshark_tep_init_all_buffers(kshark_ctx, sd);
+
+		custom_stream = malloc(sizeof(*custom_stream));
+		custom_stream->original_stream = kshark_get_data_stream(kshark_ctx, sd);
+		custom_stream->cpus = malloc(custom_stream->original_stream->n_cpus * sizeof(int));
+		memset(custom_stream->cpus, -1, custom_stream->original_stream->n_cpus * sizeof(int));

Add a comment explaining why you are doing this.


+
+		custom_streams[i-1] = custom_stream;
+	}
+
+	host_guest_mapping = NULL;
+	n_guest = kshark_tracecmd_get_hostguest_mapping(&host_guest_mapping);
+	if (n_guest < 0) {
+	  printf("Failed mapping: %d\n", n_guest);
+	  return 1;
+	}
+
+	entries = NULL;
+	n_entries = kshark_load_all_entries(kshark_ctx, &entries);
+
+	for (int i = 0; i < n_entries; ++i) {
+		current = entries[i];
+
+		stream = kshark_get_stream_from_entry(current);
+		event_name = kshark_get_event_name(current);
+
+		custom_stream = custom_streams[stream->stream_id];
+
+		if (!strcmp(event_name, KVM_ENTRY) || !strcmp(event_name, KVM_EXIT)) {
+			if (!strcmp(event_name, KVM_ENTRY)) {
+
+				/*
+				 * The recovering process of the vCPU field of the kvm_entry event
+				 * is done by splitting the info field.
+				 */
+				info = kshark_get_info(current);
+
+				token = strtok(info, " ");
+				token = strtok(NULL, " ");
+
+				/* Removing the last comma */
+				token[strlen(token) - 1] = '\0';
+
+				custom_stream->cpus[current->cpu] = atoi(token);

It will be better if you make the recovering of the vCPU above a static helper function.


+
+				free(info);
+			} else {
+				custom_stream->cpus[current->cpu] = -1;
+			}
+
+		} else {
+
+			/*
+			 * If the event comes from a guest, recover the pCPU where the event was executed
+			 * and check if it's NOT OUTSIDE a kvm_entry/kvm_exit block.
+			 */
+			if (is_guest(stream->stream_id, host_guest_mapping, n_guest, &host)) {
+				host_stream = custom_streams[host];
+
+				for (v_i = 0; v_i < host_stream->original_stream->n_cpus; v_i++) {
+					if (current->cpu == host_stream->cpus[v_i])
+					break;
+				}
+
+				if (v_i == host_stream->original_stream->n_cpus) {
+					printf("%d G out:\t", i);
+					print_entry(entries[i]);
+				}
+
+			/*
+			* If the event comes from a host, recover the CPU that executed the event
+			* and check if it's NOT INSIDE a kvm_entry/kvm_exit block.
+			*/
+			} else {
+				if (custom_stream->cpus[current->cpu] != -1) {
+					printf("%d H in:\t", i);
+					print_entry(entries[i]);
+				}
+			}
+		}
+	}
+
+	free_data(kshark_ctx, custom_streams, entries, n_entries, host_guest_mapping, n_guest);
+}

I do not see how you build the tool. I guess you edited CMakeLists.txt. This must be part of the patch as well.

Looking forward to see version 2.

Best,
Yordan






[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux