diff mbox series

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

Message ID 20210416164653.2949-1-stefano.devenuto99@gmail.com (mailing list archive)
State RFC
Headers show
Series [RFC] Simple tool for VMEnters/VMExits matching and trace validation | expand

Commit Message

Stefano De Venuto April 16, 2021, 4:46 p.m. UTC
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@gmail.com>
---
 examples/checker.c | 202 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 202 insertions(+)
 create mode 100644 examples/checker.c

Comments

Dario Faggioli April 16, 2021, 5:47 p.m. UTC | #1
On Fri, 2021-04-16 at 18:46 +0200, 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@gmail.com>
>
Just as an example, by using this tool we noticed that there are a
bunch of host events that, despite happening before a VMEnter (and
after a VMExit) were shown in the trace inside of a kvm_enter -
kvm_exit "block".

Stefano, do you still have an example of how the trace looks like? Can
you paste it here?

Stefano has also already developed the attached kernel patch. Which we
plan to submit upstream as soon as we've tested properly on Intel
hardware as well. But that's another story (although, feel free to
provide any feedback already, if interested).

Thanks and Regards
Stefano De Venuto April 16, 2021, 8:48 p.m. UTC | #2
On 4/16/21 7:47 PM, Dario Faggioli wrote:
> On Fri, 2021-04-16 at 18:46 +0200, 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@gmail.com>
>>
> Just as an example, by using this tool we noticed that there are a
> bunch of host events that, despite happening before a VMEnter (and
> after a VMExit) were shown in the trace inside of a kvm_enter -
> kvm_exit "block".
> 
> Stefano, do you still have an example of how the trace looks like? Can
> you paste it here?
> 

Yes. An example of those events is visible in this trace:

	   trace.dat:        CPU 0/KVM-1567  [001]14320175367012: kvm_entry:            vcpu 0, rip 0xffffffff84a792b6
	   trace.dat:        CPU 0/KVM-1567  [001]14320175253942: write_msr:            c0011020, value 0
trace-tumbleweed.dat:           <idle>-0     [000]14320175283462: hrtimer_cancel:       hrtimer=0xffff9002fdc21a00
trace-tumbleweed.dat:           <idle>-0     [000]14320175291336: hrtimer_expire_entry: hrtimer=0xffff9002fdc21a00 function=tick_sched_timer now=3601121397289
trace-tumbleweed.dat:           <idle>-0     [000]14320175317345: hrtimer_expire_exit:  hrtimer=0xffff9002fdc21a00
trace-tumbleweed.dat:           <idle>-0     [000]14320175319329: hrtimer_start:        hrtimer=0xffff9002fdc21a00 function=tick_sched_timer expires=3601125253926 softexpires=3601125253926 mode=0x0
           trace.dat:        CPU 0/KVM-1567  [001]14320175331517: write_msr:            c0011020, value 40000000000000
           trace.dat:        CPU 0/KVM-1567  [001]14320175338548: kvm_wait_lapic_expire: vcpu 0: delta 534432 (late)
           trace.dat:        CPU 0/KVM-1567  [001]14320175341750: kvm_eoi:              apicid 0 vector 236
           trace.dat:        CPU 0/KVM-1567  [001]14320175343465: kvm_pv_eoi:           apicid 0 vector 236
           trace.dat:        CPU 0/KVM-1567  [001]14320175345704: kvm_exit:             vcpu 0 reason msr rip 0xffffffff84a792b4 info1 0x0000000000000001 info2 0x0000000000000000 intr_info 0x00000000 error_code 0x00000000

> Stefano has also already developed the attached kernel patch. Which we
> plan to submit upstream as soon as we've tested properly on Intel
> hardware as well. But that's another story (although, feel free to
> provide any feedback already, if interested).
> 
> Thanks and Regards
>
Steven Rostedt April 16, 2021, 9:32 p.m. UTC | #3
On Fri, 16 Apr 2021 22:48:38 +0200
Stefano De Venuto <stefano.devenuto99@gmail.com> wrote:

> On 4/16/21 7:47 PM, Dario Faggioli wrote:
> > On Fri, 2021-04-16 at 18:46 +0200, 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@gmail.com>
> >>  
> > Just as an example, by using this tool we noticed that there are a
> > bunch of host events that, despite happening before a VMEnter (and
> > after a VMExit) were shown in the trace inside of a kvm_enter -
> > kvm_exit "block".
> > 
> > Stefano, do you still have an example of how the trace looks like? Can
> > you paste it here?
> >   
> 
> Yes. An example of those events is visible in this trace:
> 
> 	   trace.dat:        CPU 0/KVM-1567  [001]14320175367012: kvm_entry:            vcpu 0, rip 0xffffffff84a792b6
> 	   trace.dat:        CPU 0/KVM-1567  [001]14320175253942: write_msr:            c0011020, value 0
> trace-tumbleweed.dat:           <idle>-0     [000]14320175283462: hrtimer_cancel:       hrtimer=0xffff9002fdc21a00
> trace-tumbleweed.dat:           <idle>-0     [000]14320175291336: hrtimer_expire_entry: hrtimer=0xffff9002fdc21a00 function=tick_sched_timer now=3601121397289
> trace-tumbleweed.dat:           <idle>-0     [000]14320175317345: hrtimer_expire_exit:  hrtimer=0xffff9002fdc21a00
> trace-tumbleweed.dat:           <idle>-0     [000]14320175319329: hrtimer_start:        hrtimer=0xffff9002fdc21a00 function=tick_sched_timer expires=3601125253926 softexpires=3601125253926 mode=0x0
>            trace.dat:        CPU 0/KVM-1567  [001]14320175331517: write_msr:            c0011020, value 40000000000000
>            trace.dat:        CPU 0/KVM-1567  [001]14320175338548: kvm_wait_lapic_expire: vcpu 0: delta 534432 (late)
>            trace.dat:        CPU 0/KVM-1567  [001]14320175341750: kvm_eoi:              apicid 0 vector 236
>            trace.dat:        CPU 0/KVM-1567  [001]14320175343465: kvm_pv_eoi:           apicid 0 vector 236
>            trace.dat:        CPU 0/KVM-1567  [001]14320175345704: kvm_exit:             vcpu 0 reason msr rip 0xffffffff84a792b4 info1 0x0000000000000001 info2 0x0000000000000000 intr_info 0x00000000 error_code 0x00000000

Is the above with the time negotiations working fine?

We do not yet support the guest shift, as we found that it was broken (I
believe you reported that) and we do not have a machine available to that
has that feature :-/

-- Steve


> 
> > Stefano has also already developed the attached kernel patch. Which we
> > plan to submit upstream as soon as we've tested properly on Intel
> > hardware as well. But that's another story (although, feel free to
> > provide any feedback already, if interested).
> > 
> > Thanks and Regards
> >
Dario Faggioli April 17, 2021, 6:43 a.m. UTC | #4
On Fri, 2021-04-16 at 17:32 -0400, Steven Rostedt wrote:
> On Fri, 16 Apr 2021 22:48:38 +0200
> Stefano De Venuto <stefano.devenuto99@gmail.com> wrote:
> > 
> > Yes. An example of those events is visible in this trace:
> > 
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175367012:
> > kvm_entry:            vcpu 0, rip 0xffffffff84a792b6
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175253942:
> > write_msr:            c0011020, value 0
> > trace-tumbleweed.dat:           <idle>-0     [000]14320175283462:
> > hrtimer_cancel:       hrtimer=0xffff9002fdc21a00
> > trace-tumbleweed.dat:           <idle>-0     [000]14320175291336:
> > hrtimer_expire_entry: hrtimer=0xffff9002fdc21a00
> > function=tick_sched_timer now=3601121397289
> > trace-tumbleweed.dat:           <idle>-0     [000]14320175317345:
> > hrtimer_expire_exit:  hrtimer=0xffff9002fdc21a00
> > trace-tumbleweed.dat:           <idle>-0     [000]14320175319329:
> > hrtimer_start:        hrtimer=0xffff9002fdc21a00
> > function=tick_sched_timer expires=3601125253926
> > softexpires=3601125253926 mode=0x0
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175331517:
> > write_msr:            c0011020, value 40000000000000
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175338548:
> > kvm_wait_lapic_expire: vcpu 0: delta 534432 (late)
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175341750:
> > kvm_eoi:              apicid 0 vector 236
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175343465:
> > kvm_pv_eoi:           apicid 0 vector 236
> >            trace.dat:        CPU 0/KVM-1567  [001]14320175345704:
> > kvm_exit:             vcpu 0 reason msr rip 0xffffffff84a792b4
> > info1 0x0000000000000001 info2 0x0000000000000000 intr_info
> > 0x00000000 error_code 0x00000000
> 
> Is the above with the time negotiations working fine?
> 
Yes. I think this is still with PTP.

But this time, this is actually all about the host.

> We do not yet support the guest shift, as we found that it was broken
> (I
> believe you reported that) and we do not have a machine available to
> that
> has that feature :-/
> 
Sure, but the problem here is that write_msr, kvm_wait_lapic_expire,
kvm_eoi, kvm_pv_eoi in trace.dat (which is the host trace), despite
happening after the VMExit, are shown before kvm_exit.

This, we think, has to do to where the call to trace_kvm_exit() is in
the kernel, and that's why we said we'll send a patch to move it.

It was just an example of what and how one can use the simple little
tool that Stefano has made on top of libkshark, as it was what helped
us spot this problem. :-)

Regards
Yordan Karadzhov April 20, 2021, 8:12 a.m. UTC | #5
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@gmail.com>
> ---
>   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
Steven Rostedt April 21, 2021, 2:17 a.m. UTC | #6
On Tue, 20 Apr 2021 11:12:59 +0300
Yordan Karadzhov <y.karadz@gmail.com> wrote:


> > 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.

Or hand edit the patches using emacs ;-)

That's because emacs has a "patch mode" that updates those numbers when
you modify the patch!

-- Steve
Yordan Karadzhov April 21, 2021, 9:14 a.m. UTC | #7
On 21.04.21 г. 5:17, Steven Rostedt wrote:
> On Tue, 20 Apr 2021 11:12:59 +0300
> Yordan Karadzhov <y.karadz@gmail.com> wrote:
>
>
>>> 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.
> Or hand edit the patches using emacs ;-)
>
> That's because emacs has a "patch mode" that updates those numbers when
> you modify the patch!

Cool! I didn't know that.

Y.



> -- Steve
Stefano De Venuto May 1, 2021, 6:11 a.m. UTC | #8
Ciao Yordan,

Thanks so much for the comments!
I've just sent the version 2 addressing them.

On 4/20/21 10:12 AM, Yordan Karadzhov wrote:
> 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@gmail.com>
>> ---
>>   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.
> 

Ok, thanks for the advice!

>> +
>> +        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.
> 

I totally replaced that method since with
kshark_read_event_field_int(entry, "vcpu_id", &vcpu) I can get this
information in such a cleaner way!
Also more robust, since plugins can remove the vcpu field from the info.

Regards,
Stefano
Stefano De Venuto May 1, 2021, 6:11 a.m. UTC | #9
On 4/21/21 4:17 AM, Steven Rostedt wrote:
> On Tue, 20 Apr 2021 11:12:59 +0300
> Yordan Karadzhov <y.karadz@gmail.com> wrote:
> 
> 
>>> 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.
> 
> Or hand edit the patches using emacs ;-)
> 
> That's because emacs has a "patch mode" that updates those numbers when
> you modify the patch!

Oh, I didn't know about this kind of mode in emacs. :-O
I will surely try it, thanks!

Regards,
Stefano

> 
> -- Steve
>
diff mbox series

Patch

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 @@ 
+#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));
+
+}
+
+void print_entries(struct kshark_entry **entries, ssize_t n_entries)
+{
+	for (int i = 0; i < n_entries; ++i
+		print_entry(entries[i]);
+}
+
+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);
+}
+
+int main(int argc, char **argv)
+{
+
+	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));
+
+		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);
+
+				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);
+}
-- 
2.30.2