perf & kvm: Enhance perf to collect KVM guest os statistics from host side
Subsystems (4)
PATCH v3 1/1 perf & kvm: Enhance perf to collect KVM guest os statistics from host side
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
ChangeLog V3:
1) Add --guestmount=/dir/to/all/guestos parameter. Admin mounts guest os root directories under /dir/to/all/guestos by sshfs. For example, I start 2 guest os. The one's pid is 8888 and the other's is 9999. #mkdir ~/guestmount; cd ~/guestmount
#sshfs -o allow_other,direct_io -p 5551 localhost:/ 8888/ #sshfs -o allow_other,direct_io -p 5552 localhost:/ 9999/ #perf kvm --host --guest --guestmount=~/guestmount top
The old --guestkallsyms and --guestmodules are still supported as default guest os symbol parsing.
2) Add guest os buildid support.
3) Add sub command 'perf kvm buildid-list'.
4) Delete sub command 'perf kvm stat', because our current implementation doesn't transfer guest/host requirement to kernel, and kernel always collects both host and guest statistics. So regular 'perf stat' is ok.
5) Fix a couple of perf bugs.
6) We still have no support on command with parameter 'any' as current KVM just uses process id to identify specific guest os instance. Users could uses parameter -p to collect specific guest os instance statistics.
ChangeLog V2:
1) Based on Avi's suggestion, I moved callback functions to generic code area. So the kernel part of the patch is clearer.
2) Add 'perf kvm stat'.
From: Zhang, Yanmin <[email protected]>
Based on the discussion in KVM community, I worked out the patch to support perf to collect guest os statistics from host side. This patch is implemented with Ingo, Peter and some other guys' kind help. Yang Sheng pointed out a critical bug and provided good suggestions with other guys. I really appreciate their kind help.
The patch adds new sub command kvm to perf.
perf kvm top
perf kvm record
perf kvm report
perf kvm diff
perf kvm buildid-list
The new perf could profile guest os kernel except guest os user space, but it could summarize guest os user space utilization per guest os.
Below are some examples.
1) perf kvm top
[root@lkp-ne01 norm]# perf kvm --host --guest --guestkallsyms=/home/ymzhang/guest/kallsyms --guestmodules=/home/ymzhang/guest/modules top
--------------------------------------------------------------------------------------------------------------------------
PerfTop: 16010 irqs/sec kernel:59.1% us: 1.5% guest kernel:31.9% guest us: 7.5% exact: 0.0% [1000Hz cycles], (all, 16 CPUs)
--------------------------------------------------------------------------------------------------------------------------
samples pcnt function DSO
_______ _____ _________________________ _______________________
38770.00 20.4% __ticket_spin_lock [guest.kernel.kallsyms]
22560.00 11.9% ftrace_likely_update [kernel.kallsyms]
9208.00 4.8% __lock_acquire [kernel.kallsyms]
5473.00 2.9% trace_hardirqs_off_caller [kernel.kallsyms]
5222.00 2.7% copy_user_generic_string [guest.kernel.kallsyms]
4450.00 2.3% validate_chain [kernel.kallsyms]
4262.00 2.2% trace_hardirqs_on_caller [kernel.kallsyms]
4239.00 2.2% do_raw_spin_lock [kernel.kallsyms]
3548.00 1.9% do_raw_spin_unlock [kernel.kallsyms]
2487.00 1.3% lock_release [kernel.kallsyms]
2165.00 1.1% __local_bh_disable [kernel.kallsyms]
1905.00 1.0% check_chain_key [kernel.kallsyms]
1737.00 0.9% lock_acquire [kernel.kallsyms]
1604.00 0.8% tcp_recvmsg [kernel.kallsyms]
1524.00 0.8% mark_lock [kernel.kallsyms]
1464.00 0.8% schedule [kernel.kallsyms]
1423.00 0.7% __d_lookup [guest.kernel.kallsyms]If you want to just show host data, pls. don't use parameter --guest. The headline includes guest os kernel and userspace percentage.
2) perf kvm record
[root@lkp-ne01 norm]# perf kvm --host --guest --guestkallsyms=/home/ymzhang/guest/kallsyms --guestmodules=/home/ymzhang/guest/modules record -f -a sleep 60
[ perf record: Woken up 15 times to write data ]
[ perf record: Captured and wrote 29.385 MB perf.data.kvm (~1283837 samples) ]
3) perf kvm report
3.1) [root@lkp-ne01 norm]# perf kvm --host --guest --guestkallsyms=/home/ymzhang/guest/kallsyms
--guestmodules=/home/ymzhang/guest/modules report --sort pid --showcpuutilization>norm.host.guest.report.pid # Samples: 424719292247
#
# Overhead sys us guest sys guest us Command: Pid
# ........ .....................
#
50.57% 1.02% 0.00% 39.97% 9.58% qemu-system-x86: 3587
49.32% 1.35% 0.01% 35.20% 12.76% qemu-system-x86: 3347
0.07% 0.07% 0.00% 0.00% 0.00% perf: 5217Some performance guys require perf to show sys/us/guest_sys/guest_us per KVM guest instance which is actually just a multi-threaded process. Above sub parameter --showcpuutilization does so.
3.2) [root@lkp-ne01 norm]# perf kvm --host --guest --guestkallsyms=/home/ymzhang/guest/kallsyms
--guestmodules=/home/ymzhang/guest/modules report >norm.host.guest.report # Samples: 2466991384118
#
# Overhead Command Shared Object Symbol
# ........ ............... ........................................................................ ......
#
29.11% qemu-system-x86 [guest.kernel.kallsyms] [g] __ticket_spin_lock
5.88% tbench_srv [kernel.kallsyms] [k] ftrace_likely_update
5.76% tbench [kernel.kallsyms] [k] ftrace_likely_update
3.88% qemu-system-x86 34c3255482 [u] 0x000034c3255482
1.83% tbench [kernel.kallsyms] [k] __lock_acquire
1.81% tbench_srv [kernel.kallsyms] [k] __lock_acquire
1.38% tbench_srv [kernel.kallsyms] [k] trace_hardirqs_off_caller
1.37% tbench [kernel.kallsyms] [k] trace_hardirqs_off_caller
1.13% qemu-system-x86 [guest.kernel.kallsyms] [g] copy_user_generic_string
1.04% tbench_srv [kernel.kallsyms] [k] validate_chain
1.00% tbench [kernel.kallsyms] [k] trace_hardirqs_on_caller
1.00% tbench_srv [kernel.kallsyms] [k] trace_hardirqs_on_caller
0.95% tbench [kernel.kallsyms] [k] do_raw_spin_lock[u] means it's in guest os user space. [g] means in guest os kernel. Other info is very direct. If it shows a module such like [ext4], it means guest kernel module, because native host kernel's modules are start from something like /lib/modules/XXX.
4) --guestmount example. I started 2 guest os. Run dbench testing in the 1st and tbench in 2nd guest os. [root@lkp-ne01 norm]#perf kvm --host --guest --guestmount=/home/ymzhang/guestmount/ top
---------------------------------------------------------------------------------------------------------------------------------------
PerfTop: 15972 irqs/sec kernel: 8.3% us: 0.5% guest kernel:73.9% guest us:17.3% exact: 0.0% [1000Hz cycles], (all, 16 CPUs)
---------------------------------------------------------------------------------------------------------------------------------------
samples pcnt function DSO
_______ _____ _________________________ __________________________________________________
32960.00 17.4% __ticket_spin_lock [guest.kernel.kallsyms]
5464.00 2.9% copy_user_generic_string [guest.kernel.kallsyms]
4069.00 2.1% copy_user_generic_string [guest.kernel.kallsyms]
3238.00 1.7% ftrace_likely_update /lib/modules/2.6.34-rc4-tip-yangkvm+/build/vmlinux
2997.00 1.6% __lock_acquire /lib/modules/2.6.34-rc4-tip-yangkvm+/build/vmlinux
2797.00 1.5% tcp_sendmsg [guest.kernel.kallsyms]
2703.00 1.4% schedule [guest.kernel.kallsyms]
2384.00 1.3% __switch_to [guest.kernel.kallsyms]
2125.00 1.1% tcp_ack [guest.kernel.kallsyms]
2045.00 1.1% tcp_recvmsg [guest.kernel.kallsyms]
1862.00 1.0% tcp_transmit_skb [guest.kernel.kallsyms]
1734.00 0.9% __ticket_spin_lock [guest.kernel.kallsyms]
1388.00 0.7% lock_release /lib/modules/2.6.34-rc4-tip-yangkvm+/build/vmlinux
1367.00 0.7% update_curr [guest.kernel.kallsyms]
1339.00 0.7% fget_light [guest.kernel.kallsyms]
1332.00 0.7% put_page [guest.kernel.kallsyms]
1324.00 0.7% ip_queue_xmit [guest.kernel.kallsyms]
1296.00 0.7% __d_lookup [guest.kernel.kallsyms]
1296.00 0.7% tcp_rcv_established [guest.kernel.kallsyms]
1230.00 0.6% tcp_v4_rcv [guest.kernel.kallsyms]
1092.00 0.6% dev_queue_xmit [guest.kernel.kallsyms]
1073.00 0.6% kmem_cache_alloc [guest.kernel.kallsyms]
1066.00 0.6% ip_rcv [guest.kernel.kallsyms]
1049.00 0.6% __inet_lookup_established [guest.kernel.kallsyms]
1048.00 0.6% tcp_write_xmit [guest.kernel.kallsyms] Below is the patch against tip/master tree of 13th April.
---
arch/x86/include/asm/perf_event.h +4 -11
@@ -135,17 +135,10 @@ extern void perf_events_lapic_init(void)*/ #define PERF_EFLAGS_EXACT (1UL << 3) -#define perf_misc_flags (regs) \ -({ int misc = 0; \ - if (user_mode(regs)) \ - misc |= PERF_RECORD_MISC_USER; \ - else \ - misc |= PERF_RECORD_MISC_KERNEL; \ - if (regs->flags & PERF_EFLAGS_EXACT) \ - misc |= PERF_RECORD_MISC_EXACT; \ - misc; }) - -#define perf_instruction_pointer (regs) ((regs)->ip) +struct pt_regs ; +extern unsigned long perf_instruction_pointer (struct pt_regs *regs); +extern unsigned long perf_misc_flags (struct pt_regs *regs); +#define perf_misc_flags (regs) perf_misc_flags(regs)#else static inline void init_hw_perf_events (void ) { }
arch/x86/kernel/cpu/perf_event.c +32 -0
@@ -1720,6 +1720,11 @@ struct perf_callchain_entry *perf_callch {struct perf_callchain_entry *entry; +if (perf_guest_cbs && perf_guest_cbs->is_in_guest ()) { +/* TODO: We don't support guest os callchain now */ +return NULL ; + } +if (in_nmi ()) entry = &__get_cpu_var (pmc_nmi_entry);else
@@ -1743,3 +1748,30 @@ void perf_arch_fetch_caller_regs(struct regs->cs = __KERNEL_CS;local_save_flags (regs->flags); } + +unsigned long perf_instruction_pointer (struct pt_regs *regs) +{ +unsigned long ip; +if (perf_guest_cbs && perf_guest_cbs->is_in_guest ()) + ip = perf_guest_cbs->get_guest_ip (); +else + ip =instruction_pointer (regs); +return ip; +} + +unsigned long perf_misc_flags (struct pt_regs *regs) +{ +int misc =0 ; +if (perf_guest_cbs && perf_guest_cbs->is_in_guest ()) { + misc |= perf_guest_cbs->is_user_mode () ? +PERF_RECORD_MISC_GUEST_USER : +PERF_RECORD_MISC_GUEST_KERNEL ; + }else + misc |=user_mode (regs) ?PERF_RECORD_MISC_USER : +PERF_RECORD_MISC_KERNEL ; +if (regs->flags &PERF_EFLAGS_EXACT ) + misc |=PERF_RECORD_MISC_EXACT ; + +return misc; +} +
arch/x86/kvm/x86.c +36 -0
@@ -3765,6 +3765,35 @@ static void kvm_timer_init(void) } } +static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); + +static int kvm_is_in_guest (void ) +{ +return percpu_read (current_vcpu) !=NULL ; +} + +static int kvm_is_user_mode (void ) +{ +int user_mode =3 ; +if (percpu_read (current_vcpu)) + user_mode = kvm_x86_ops->get_cpl (percpu_read (current_vcpu)); +return user_mode !=0 ; +} + +static unsigned long kvm_get_guest_ip (void ) +{ +unsigned long ip =0 ; +if (percpu_read (current_vcpu)) + ip =kvm_rip_read (percpu_read (current_vcpu)); +return ip; +} + +static struct perf_guest_info_callbacks kvm_guest_cbs = { + .is_in_guest = kvm_is_in_guest, + .is_user_mode = kvm_is_user_mode, + .get_guest_ip = kvm_get_guest_ip, +}; +int kvm_arch_init (void *opaque) {int r;
@@ -3801,6 +3830,8 @@ int kvm_arch_init(void *opaque)kvm_timer_init (); +perf_register_guest_info_callbacks (&kvm_guest_cbs); +return 0 ; out:
@@ -3809,6 +3840,8 @@ out:void kvm_arch_exit (void ) { +perf_unregister_guest_info_callbacks (&kvm_guest_cbs); +if (!boot_cpu_has (X86_FEATURE_CONSTANT_TSC ))cpufreq_unregister_notifier (&kvmclock_cpufreq_notifier_block,CPUFREQ_TRANSITION_NOTIFIER );
@@ -4339,7 +4372,10 @@ static int vcpu_enter_guest(struct kvm_v }trace_kvm_entry (vcpu->vcpu_id); + +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );/* * If the guest has used debug registers, at least dr7
include/linux/perf_event.h +20 -1
@@ -288,11 +288,13 @@ struct perf_event_mmap_page {__u64 data_tail;/* user-space written tail */ }; -#define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0) +#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)#define PERF_RECORD_MISC_KERNEL (1 << 0)#define PERF_RECORD_MISC_USER (2 << 0)#define PERF_RECORD_MISC_HYPERVISOR (3 << 0) +#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) +#define PERF_RECORD_MISC_GUEST_USER (5 << 0)#define PERF_RECORD_MISC_EXACT (1 << 14)/*
@@ -446,6 +448,12 @@ enum perf_callchain_context {# include <asm/perf_event.h> #endif +struct perf_guest_info_callbacks { +int (*is_in_guest) (void ); +int (*is_user_mode) (void ); +unsigned long (*get_guest_ip) (void ); +}; +#ifdef CONFIG_HAVE_HW_BREAKPOINT #include <asm/hw_breakpoint.h> #endif
@@ -920,6 +928,12 @@ static inline void perf_event_mmap(struc__perf_event_mmap (vma); } +extern struct perf_guest_info_callbacks *perf_guest_cbs; +extern int perf_register_guest_info_callbacks ( +struct perf_guest_info_callbacks *); +extern int perf_unregister_guest_info_callbacks ( +struct perf_guest_info_callbacks *); +extern void perf_event_comm (struct task_struct *tsk);extern void perf_event_fork (struct task_struct *tsk);
@@ -989,6 +1003,11 @@ perf_sw_event(u32 event_id, u64 nr, intstatic inline void perf_bp_event (struct perf_event *event,void *data) { } +static inline int perf_register_guest_info_callbacks +(struct perf_guest_info_callbacks *) {return 0 ; } +static inline int perf_unregister_guest_info_callbacks +(struct perf_guest_info_callbacks *) {return 0 ; } +static inline void perf_event_mmap (struct vm_area_struct *vma) { }static inline void perf_event_comm (struct task_struct *tsk) { }static inline void perf_event_fork (struct task_struct *tsk) { }
kernel/perf_event.c +22 -1
@@ -2797,6 +2797,27 @@ void perf_arch_fetch_caller_regs(struct/* +* We assume there is only KVM supporting the callbacks. +* Later on, we might change it to a list if there is +* another virtualization implementation supporting the callbacks. +*/ +struct perf_guest_info_callbacks *perf_guest_cbs; + +int perf_register_guest_info_callbacks (struct perf_guest_info_callbacks *cbs) +{ + perf_guest_cbs = cbs; +return 0 ; +} +EXPORT_SYMBOL_GPL (perf_register_guest_info_callbacks); + +int perf_unregister_guest_info_callbacks (struct perf_guest_info_callbacks *cbs) +{ + perf_guest_cbs =NULL ; +return 0 ; +} +EXPORT_SYMBOL_GPL (perf_unregister_guest_info_callbacks); + +/* * Output */ static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
@@ -3748,7 +3769,7 @@ void __perf_event_mmap(struct vm_area_st .event_id = { .header = { .type = PERF_RECORD_MMAP, - .misc = 0, + .misc = PERF_RECORD_MISC_USER, /* .size */ },/* .pid */
tools/perf/builtin-annotate.c +1 -1
@@ -571,7 +571,7 @@ static int __cmd_annotate(void)perf_session__fprintf (session, stdout);if (verbose >2 ) -dsos__fprintf (stdout); +dsos__fprintf (&session->kerninfo_root, stdout);perf_session__collapse_resort (&session->hists);perf_session__output_resort (&session->hists, session->event_total[0 ]);
tools/perf/builtin-buildid-list.c +1 -1
@@ -46,7 +46,7 @@ static int __cmd_buildid_list(void)if (with_hits)perf_session__process_events (session, &build_id__mark_dso_hit_ops); -dsos__fprintf_buildid (stdout, with_hits); +dsos__fprintf_buildid (&session->kerninfo_root, stdout, with_hits);perf_session__delete (session);return err;
tools/perf/builtin-diff.c +5 -1
@@ -33,7 +33,7 @@ static int perf_session__add_hist_entry(return -ENOMEM ;if (hit) - he->count += count; +__perf_session__add_count (he, al, count);return 0 ; }
@@ -225,6 +225,10 @@ int cmd_diff(int argc, const char **argv input_new = argv[1 ]; }else input_new = argv[0 ]; + }else if (symbol_conf.default_guest_vmlinux_name || + symbol_conf.default_guest_kallsyms) { + input_old ="perf.data.host" ; + input_new ="perf.data.guest" ; } symbol_conf.exclude_other = false;
tools/perf/builtin.h +1 -0
@@ -32,5 +32,6 @@ extern int cmd_version(int argc, const cextern int cmd_probe (int argc,const char **argv,const char *prefix);extern int cmd_kmem (int argc,const char **argv,const char *prefix);extern int cmd_lock (int argc,const char **argv,const char *prefix); +extern int cmd_kvm (int argc,const char **argv,const char *prefix);#endif
tools/perf/builtin-kmem.c +7 -1
@@ -351,6 +351,7 @@ static void __print_result(struct rb_roo int n_lines, int is_caller) {struct rb_node *next; +struct kernel_info *kerninfo;printf ("%.102s\n" , graph_dotted_line);printf (" %-34s |" , is_caller ?"Callsite" :"Alloc Ptr" );
@@ -359,6 +360,11 @@ static void __print_result(struct rb_roo next =rb_first (root); + kerninfo =kerninfo__findhost (&session->kerninfo_root); +if (!kerninfo) { +pr_err ("__print_result: couldn't find kernel information\n" ); +return ; + }while (next && n_lines--) { struct alloc_stat *data = rb_entry(next, struct alloc_stat, node);
@@ -370,7 +376,7 @@ static void __print_result(struct rb_rooif (is_caller) { addr = data->call_site;if (!raw_ip) - sym =map_groups__find_function (&session->kmaps, + sym =map_groups__find_function (&kerninfo->kmaps, addr, &map,NULL ); }else addr = data->ptr;
tools/perf/builtin-kvm.c +145 -0
145 lines not on this page · raw message
tools/perf/builtin-record.c +60 -3
93 lines not on this page · raw message
tools/perf/builtin-report.c +4 -2
@@ -108,7 +108,7 @@ static int perf_session__add_hist_entry(return -ENOMEM ;if (hit) - he->count += data->period; +__perf_session__add_count (he, al, data->period);if (symbol_conf.use_callchain) {if (!hit)
@@ -300,7 +300,7 @@ static int __cmd_report(void)perf_session__fprintf (session, stdout);if (verbose >2 ) -dsos__fprintf (stdout); +dsos__fprintf (&session->kerninfo_root, stdout); next =rb_first (&session->stats_by_id);while (next) {
@@ -437,6 +437,8 @@ static const struct option options[] = { "sort by key(s): pid, comm, dso, symbol, parent"),OPT_BOOLEAN ('P' ,"full-paths" , &symbol_conf.full_paths,"Don't shorten the pathnames taking into account the cwd" ), +OPT_BOOLEAN (0 ,"showcpuutilization" , &symbol_conf.show_cpu_utilization, +"Show sample percentage for different cpu modes" ),OPT_STRING ('p' ,"parent" , &parent_pattern,"regex" ,"regex filter to identify parent, see: '--sort parent'" ), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
tools/perf/builtin-top.c +52 -14
156 lines not on this page · raw message
tools/perf/Makefile +1 -0
@@ -472,6 +472,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-trace.o BUILTIN_OBJS += $(OUTPUT)builtin-probe.o BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o BUILTIN_OBJS += $(OUTPUT)builtin-lock.o +BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o PERFLIBS = $(LIB_FILE)
tools/perf/perf.c +1 -0
@@ -307,6 +307,7 @@ static void handle_internal_command(int { "probe", cmd_probe, 0 }, { "kmem", cmd_kmem, 0 }, { "lock", cmd_lock, 0 }, + { "kvm", cmd_kvm, 0 }, };unsigned int i;static const char ext[] =STRIP_EXTENSION ;
tools/perf/perf.h +2 -0
@@ -131,4 +131,6 @@ struct ip_callchain { u64 ips[0]; }; +extern int perf_host, perf_guest; +#endif
tools/perf/util/build-id.c +1 -1
@@ -24,7 +24,7 @@ static int build_id__mark_dso_hit(event_ }thread__find_addr_map (thread, session, cpumode,MAP__FUNCTION , - event->ip.ip, &al); + event->ip.pid, event->ip.ip, &al);if (al.map !=NULL ) al.map->dso->hit =1 ;
tools/perf/util/event.c +213 -86
409 lines not on this page · raw message
tools/perf/util/event.h +7 -3
@@ -79,6 +79,7 @@ struct sample_data {struct build_id_event {struct perf_event_header header; +pid_t pid;u8 build_id[ALIGN (BUILD_ID_SIZE ,sizeof (u64))];char filename[]; };
@@ -119,10 +120,13 @@ int event__synthesize_thread(pid_t pid,void event__synthesize_threads (event__handler_t process,struct perf_session *session);int event__synthesize_kernel_mmap (event__handler_t process, -struct perf_session *session, -const char *symbol_name); +struct perf_session *session, +struct kernel_info *kerninfo, +const char *symbol_name); +int event__synthesize_modules (event__handler_t process, -struct perf_session *session); +struct perf_session *session, +struct kernel_info *kerninfo);int event__process_comm (event_t *self,struct perf_session *session);int event__process_lost (event_t *self,struct perf_session *session);
tools/perf/util/header.c +127 -15
198 lines not on this page · raw message
tools/perf/util/hist.c +67 -1
101 lines not on this page · raw message
tools/perf/util/hist.h +3 -0
@@ -12,6 +12,9 @@ struct addr_location;struct symbol ;struct rb_root ; +void __perf_session__add_count (struct hist_entry *he, +struct addr_location *al, +u64 count); struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, struct addr_location *al, struct symbol *parent,
tools/perf/util/map.c +126 -2
157 lines not on this page · raw message
tools/perf/util/map.h +60 -14
118 lines not on this page · raw message
tools/perf/util/probe-event.c +7 -1
@@ -78,6 +78,8 @@ static struct map *kmaps[MAP__NR_TYPES];/* Initialize symbol maps and path of vmlinux */ static void init_vmlinux (void ) { +struct dso *kernel; + symbol_conf.sort_by_name = true;if (symbol_conf.vmlinux_name ==NULL ) symbol_conf.try_vmlinux_path = true;
@@ -86,8 +88,12 @@ static void init_vmlinux(void)if (symbol__init () <0 )die ("Failed to init symbol map." ); + kernel =dso__new_kernel (symbol_conf.vmlinux_name); +if (kernel ==NULL ) +die ("Failed to create kernel dso." ); +map_groups__init (&kmap_groups); -if (map_groups__create_kernel_maps (&kmap_groups, kmaps) <0 ) +if (__map_groups__create_kernel_maps (&kmap_groups, kmaps, kernel) <0 )die ("Failed to create kernel maps." ); }
tools/perf/util/session.c +28 -49
121 lines not on this page · raw message
tools/perf/util/session.h +3 -25
@@ -15,17 +15,15 @@ struct perf_session {struct perf_header header;unsigned long size;unsigned long mmap_window; -struct map_groups kmaps;struct rb_root threads;struct thread *last_match; -struct map *vmlinux_maps[MAP__NR_TYPES ]; +struct rb_root kerninfo_root;struct events_stats events_stats;struct rb_root stats_by_id;unsigned long event_total[PERF_RECORD_MAX ];unsigned long unknown_events;struct rb_root hists;u64 sample_type; -struct ref_reloc_sym ref_reloc_sym;int fd;int cwdlen;char *cwd;
@@ -64,33 +62,13 @@ struct map_symbol *perf_session__resolvebool perf_session__has_traces (struct perf_session *self,const char *msg); -int perf_header__read_build_ids (struct perf_header *self,int input, -u64 offset,u64 file_size); - -int perf_session__set_kallsyms_ref_reloc_sym (struct perf_session *self, +int perf_session__set_kallsyms_ref_reloc_sym (struct map ** maps,const char *symbol_name,u64 addr);void mem_bswap_64 (void *src,int byte_size); -static inline int __perf_session__create_kernel_maps (struct perf_session *self, -struct dso *kernel) -{ -return __map_groups__create_kernel_maps (&self->kmaps, - self->vmlinux_maps, kernel); -} - -static inline int perf_session__create_kernel_maps (struct perf_session *self) -{ -return map_groups__create_kernel_maps (&self->kmaps, self->vmlinux_maps); -} - -static inline struct map * -perf_session__new_module_map (struct perf_session *self, -u64 start,const char *filename) -{ -return map_groups__new_module (&self->kmaps, start, filename); -} +int perf_session__create_kernel_maps (struct perf_session *self);#ifdef NO_NEWT_SUPPORT static inline int perf_session__browse_hists(struct rb_root *hists __used,
tools/perf/util/sort.h +5 -0
@@ -44,6 +44,11 @@ extern enum sort_type sort__first_dimensstruct hist_entry {struct rb_node rb_node;u64 count; +u64 count_sys; +u64 count_us; +u64 count_guest_sys; +u64 count_guest_us; +/* * XXX WARNING! * thread _has_ to come after ms, see
tools/perf/util/symbol.c +308 -63
638 lines not on this page · raw message
tools/perf/util/symbol.h +30 -14
112 lines not on this page · raw message
tools/perf/util/thread.h +2 -2
@@ -33,12 +33,12 @@ static inline struct map *thread__find_mvoid thread__find_addr_map (struct thread *self,struct perf_session *session,u8 cpumode, -enum map_type type,u64 addr, +enum map_type type,pid_t pid,u64 addr,struct addr_location *al);void thread__find_addr_location (struct thread *self,struct perf_session *session,u8 cpumode, -enum map_type type,u64 addr, +enum map_type type,pid_t pid,u64 addr,struct addr_location *al,symbol_filter_t filter);#endif /* __PERF_THREAD_H */
Quoted 4 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate arch/x86/kvm part of the patch? That will make for easier reviewing, and will need to go through separate trees.
Sheng, did you make any progress with the NMI injection issue?
Quoted 5 lines
+
diff -Nrauplinux-2.6_tip0413/arch/x86/kvm/x86.clinux-2.6_tip0413_perfkvm/arch/x86/kvm/x86.c
arch/x86/kvm/x86.c static void kvm_timer_init(void) · line 3773
Quoted 9 lines
arch/x86/kvm/x86.c +5
-0@@ -3765,6 +3765,35 @@ static void kvm_timer_init(void) } } +static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); + +static int kvm_is_in_guest (void ) +{ +return percpu_read (current_vcpu) !=NULL ;
An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
arch/x86/kvm/x86.c static void kvm_timer_init(void)
Quoted 8 lines
arch/x86/kvm/x86.c +7
-0+static unsigned long kvm_get_guest_ip (void ) +{ +unsigned long ip =0 ; +if (percpu_read (current_vcpu)) + ip =kvm_rip_read (percpu_read (current_vcpu)); +return ip; +}
This may be racy. kvm_rip_read() accesses a cache in memory; if we're in the process of updating the cache, then we may read a stale value. See below.
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 7 lines
arch/x86/kvm/x86.c +3
-0trace_kvm_entry (vcpu->vcpu_id); + +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );
If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 10 lines · On Wednesday 14 April 2010 17:20:15 Avi Kivity wrote:
Quoted 2 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.Sheng, did you make any progress with the NMI injection issue?
Yes, though some other works interrupt me lately...
The very first version has issue due to SELF_IPI mode can't be used to send NMI according to SDM. That's the reason why x2apic don't have way to do this.
But later I found another issue of fail to inspect inside the guest. I think it's due to NMI is asynchronous event, though it should be triggered very quickly, you can't guarantee that the handler would be triggered before the state(current_vcpu) is cleared with current code.
Maybe just extended the "guest state" region would be fine, if the latency is stable enough(though I think it maybe platform depended). I am working on this now.
Signature · 2 lines
regards Yang, Sheng
Quoted 45 lines
Quoted 11 lines
+
diff -Nrauplinux-2.6_tip0413/arch/x86/kvm/x86.clinux-2.6_tip0413_perfkvm/arch/x86/kvm/x86.c---linux-2.6_tip0413/arch/x86/kvm/x86.c2010-04-14 11:11:04.341042024 +0800
+++linux-2.6_tip0413_perfkvm/arch/x86/kvm/x86.c2010-04-14
11:32:45.841278890 +0800 @@ -3765,6 +3765,35 @@ static voidkvm_timer_init(void)
}
}arch/x86/kvm/x86.c static void kvm_timer_init(void) · line 3772
Quoted 5 lines
arch/x86/kvm/x86.c +5
-0+static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); + +static int kvm_is_in_guest (void ) +{ +return percpu_read (current_vcpu) !=NULL ;An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
arch/x86/kvm/x86.c static void kvm_timer_init(void) · line 3789
Quoted 7 lines
arch/x86/kvm/x86.c +7
-0+static unsigned long kvm_get_guest_ip (void ) +{ +unsigned long ip =0 ; +if (percpu_read (current_vcpu)) + ip =kvm_rip_read (percpu_read (current_vcpu)); +return ip; +}This may be racy.
kvm_rip_read()accesses a cache in memory; if we're in the process of updating the cache, then we may read a stale value. See below.arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 5 lines
trace_kvm_entry(vcpu->vcpu_id);arch/x86/kvm/x86.c +3
-0+ +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Quoted 12 lines · Sheng Yang
Quoted 10 lines · On Wednesday 14 April 2010 17:20:15 Avi Kivity wrote:
Quoted 3 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.
Quoted 7 lines
Quoted 2 lines
Sheng, did you make any progress with the NMI injection issue?
Yes, though some other works interrupt me lately...
The very first version has issue due to
SELF_IPImode can't be used to send NMI according to SDM. That's the reason why x2apic don't have way to do this.
Yes, I see that now. Looks like others have the same questions...
Quoted 9 lines
But later I found another issue of fail to inspect inside the guest. I think it's due to NMI is asynchronous event, though it should be triggered very quickly, you can't guarantee that the handler would be triggered before the
state(current_vcpu)is cleared with current code.Maybe just extended the "guest state" region would be fine, if the latency is stable enough(though I think it maybe platform depended). I am working on this now.
I wouldn't like to depend on model specific behaviour.
One option is to read all the information synchronously and store it in a per-cpu area with atomic instructions, then queue the NMI. Another option is to have another callback which tells us that the NMI is done, and have a busy loop wait until the NMI is delivered.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 30 lines · On Wednesday 14 April 2010 17:57:50 Avi Kivity wrote:
Quoted 10 lines · Sheng Yang
Quoted 9 lines · On Wednesday 14 April 2010 17:20:15 Avi Kivity wrote:
Quoted 2 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.Quoted 7 lines
Quoted 1 line
Sheng, did you make any progress with the NMI injection issue?
Yes, though some other works interrupt me lately...
The very first version has issue due to
SELF_IPImode can't be used to send NMI according to SDM. That's the reason why x2apic don't have way to do this.Yes, I see that now. Looks like others have the same questions...
Quoted 8 lines
But later I found another issue of fail to inspect inside the guest. I think it's due to NMI is asynchronous event, though it should be triggered very quickly, you can't guarantee that the handler would be triggered before the
state(current_vcpu)is cleared with current code.Maybe just extended the "guest state" region would be fine, if the latency is stable enough(though I think it maybe platform depended). I am working on this now.
Quoted 7 lines
I wouldn't like to depend on model specific behaviour.
One option is to read all the information synchronously and store it in a per-cpu area with atomic instructions, then queue the NMI. Another option is to have another callback which tells us that the NMI is done, and have a busy loop wait until the NMI is delivered.
Callback seems too heavy, may affect the performance badly. Maybe a short queue would help, though this one is more complex.
But I am still curious if we extend the region, how much it would help. Would get a result soon...
Signature · 2 lines
regards Yang, Sheng
Quoted 12 lines · Sheng Yang
Quoted 9 lines
I wouldn't like to depend on model specific behaviour.
One option is to read all the information synchronously and store it in a per-cpu area with atomic instructions, then queue the NMI. Another option is to have another callback which tells us that the NMI is done, and have a busy loop wait until the NMI is delivered.
Callback seems too heavy, may affect the performance badly. Maybe a short queue would help, though this one is more complex.
The patch we're replying to adds callbacks (to read rip, etc.), so it's no big deal. For the queue solution, a queue of size one would probably be sufficient even if not guaranteed by the spec. I don't see how the cpu can do another guest entry without delivering the NMI.
Quoted 3 lines
But I am still curious if we extend the region, how much it would help. Would get a result soon...
Yes, interesting to see what the latency is. If it's reasonably short (and I expect it will be so), we can do the busy wait solution.
If we have an NMI counter somewhere, we can simply wait until it changes.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 16 lines · On Wednesday 14 April 2010 18:19:49 Avi Kivity wrote:
Quoted 9 lines · Sheng Yang
Quoted 6 lines
I wouldn't like to depend on model specific behaviour.
One option is to read all the information synchronously and store it in a per-cpu area with atomic instructions, then queue the NMI. Another option is to have another callback which tells us that the NMI is done, and have a busy loop wait until the NMI is delivered.
Callback seems too heavy, may affect the performance badly. Maybe a short queue would help, though this one is more complex.
The patch we're replying to adds callbacks (to read rip, etc.), so it's no big deal. For the queue solution, a queue of size one would probably be sufficient even if not guaranteed by the spec. I don't see how the cpu can do another guest entry without delivering the NMI.
Quoted 7 lines
Quoted 2 lines
But I am still curious if we extend the region, how much it would help. Would get a result soon...
Yes, interesting to see what the latency is. If it's reasonably short (and I expect it will be so), we can do the busy wait solution.
If we have an NMI counter somewhere, we can simply wait until it changes.
Good idea. Of course we have one(at least on x86). There is irq_stat.irq__nmi_count for per cpu. :)
Signature · 2 lines
regards Yang, Sheng
Quoted 10 lines · Sheng Yang
Quoted 6 lines
Yes, interesting to see what the latency is. If it's reasonably short (and I expect it will be so), we can do the busy wait solution.
If we have an NMI counter somewhere, we can simply wait until it changes.
Good idea. Of course we have one(at least on x86). There is irq_stat.irq__nmi_count for per cpu. :)
Okay, but kvm doesn't want to know about it. How about a new arch function, invoke_nmi_sync(), that will trigger the NMI and wait for it?
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 4 lines · On Wednesday 14 April 2010 18:33:37 Avi Kivity wrote:
Quoted 3 lines · Sheng Yang
Quoted 3 lines
Yes, interesting to see what the latency is. If it's reasonably short (and I expect it will be so), we can do the busy wait solution.
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
If we have an NMI counter somewhere, we can simply wait until it changes.
Good idea. Of course we have one(at least on x86). There is irq_stat.irq__nmi_count for per cpu. :)
Okay, but kvm doesn't want to know about it. How about a new arch function,
invoke_nmi_sync(), that will trigger the NMI and wait for it?
Sound reasonable. Would try it.
Signature · 2 lines
regards Yang, Sheng
Quoted 9 lines · Avi Kivity
Quoted 3 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.
Once it gets into a state that it can be applied could you please create a separate, -git based branch for it, so that i can pull it for testing and integration with the tools/perf/ bits?
Assuming there are no serious conflicts with pending KVM work.
(or i can do that too)
Thanks,
Ingo
Quoted 11 lines · Ingo Molnar
Quoted 6 lines
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.Once it gets into a state that it can be applied could you please create a separate, -git based branch for it, so that i can pull it for testing and integration with the
tools/perf/bits?
Sure.
Quoted 2 lines
Assuming there are no serious conflicts with pending KVM work.
There will be a conflict with the NMI fix (which has to go in first, we'll want to backport it), I'll put it on the same branch.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 10 lines · Avi Kivity
Quoted 4 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.
I should do so definitely, and will do so in next version which also fixes some issues pointed by Ingo.
Quoted 11 lines
Sheng, did you make any progress with the NMI injection issue?
Quoted 8 lines
+
diff -Nrauplinux-2.6_tip0413/arch/x86/kvm/x86.clinux-2.6_tip0413_perfkvm/arch/x86/kvm/x86.carch/x86/kvm/x86.c +0
-0@@ -3765,6 +3765,35 @@ static void kvm_timer_init(void) } }
Quoted 12 lines
arch/x86/kvm/x86.c static void kvm_timer_init(void)
Quoted 6 lines
arch/x86/kvm/x86.c +5
-0+static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); + +static int kvm_is_in_guest (void ) +{ +return percpu_read (current_vcpu) !=NULL ;An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
Yes. But the frame pointer checking seems a little complicated.
Quoted 13 lines
arch/x86/kvm/x86.c static void kvm_timer_init(void)
Quoted 9 lines
arch/x86/kvm/x86.c +7
-0+static unsigned long kvm_get_guest_ip (void ) +{ +unsigned long ip =0 ; +if (percpu_read (current_vcpu)) + ip =kvm_rip_read (percpu_read (current_vcpu)); +return ip; +}This may be racy.
kvm_rip_read()accesses a cache in memory; if we're in the process of updating the cache, then we may read a stale value. See below.
Right. The racy window seems too big.
Quoted 12 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 8 lines
arch/x86/kvm/x86.c +3
-0trace_kvm_entry (vcpu->vcpu_id); + +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Right. The kernel part has dependency on the self-IPI implementation. I will move above percpu_write(current_vcpu, vcpu) (or a new wrapper function) just around 'int $2'.
Sheng would find a solution on the self-IPI delivery. Let's separate my patch and self-IPI as 2 issues as we don't know when the self-IPI delivery would be resolved.
Thanks,
Yanmin
Quoted 10 lines · Avi Kivity
Quoted 4 lines · Yanmin
Here is the new patch of V3 against tip/master of April 13th if anyone wants to try it.
Thanks for persisting despite the flames.
Can you please separate
arch/x86/kvmpart of the patch? That will make for easier reviewing, and will need to go through separate trees.
I should do so definitely, and will do so in next version which also fixes some issues pointed by Ingo.
Quoted 11 lines
Sheng, did you make any progress with the NMI injection issue?
Quoted 8 lines
+
diff -Nrauplinux-2.6_tip0413/arch/x86/kvm/x86.clinux-2.6_tip0413_perfkvm/arch/x86/kvm/x86.carch/x86/kvm/x86.c +0
-0@@ -3765,6 +3765,35 @@ static void kvm_timer_init(void) } }
Quoted 12 lines
arch/x86/kvm/x86.c static void kvm_timer_init(void)
Quoted 6 lines
arch/x86/kvm/x86.c +5
-0+static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu); + +static int kvm_is_in_guest (void ) +{ +return percpu_read (current_vcpu) !=NULL ;An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
Yes. But the frame pointer checking seems a little complicated.
Quoted 13 lines
arch/x86/kvm/x86.c static void kvm_timer_init(void)
Quoted 9 lines
arch/x86/kvm/x86.c +7
-0+static unsigned long kvm_get_guest_ip (void ) +{ +unsigned long ip =0 ; +if (percpu_read (current_vcpu)) + ip =kvm_rip_read (percpu_read (current_vcpu)); +return ip; +}This may be racy.
kvm_rip_read()accesses a cache in memory; if we're in the process of updating the cache, then we may read a stale value. See below.
Right. The racy window seems too big.
Quoted 12 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 8 lines
arch/x86/kvm/x86.c +3
-0trace_kvm_entry (vcpu->vcpu_id); + +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Right. The kernel part has dependency on the self-IPI implementation. I will move above percpu_write(current_vcpu, vcpu) (or a new wrapper function) just around 'int $2'.
Sheng would find a solution on the self-IPI delivery. Let's separate my patch and self-IPI as 2 issues as we don't know when the self-IPI delivery would be resolved.
Thanks,
Yanmin
Quoted 9 lines · Yanmin
Quoted 7 lines
An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
Yes. But the frame pointer checking seems a little complicated.
An even bigger disadvantage is that it won't work with Sheng's patch, self-NMIs are not synchronous.
Quoted 11 lines
Quoted 11 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 7 lines
trace_kvm_entry(vcpu->vcpu_id);arch/x86/kvm/x86.c +3
-0+ +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Quoted 5 lines
Right. The kernel part has dependency on the self-IPI implementation. I will move above
percpu_write(current_vcpu, vcpu)(or a new wrapper function) just around 'int $2'.
Or create a new function to inject the interrupt in x86.c. That will reduce duplication between svm.c and vmx.c.
Quoted 4 lines
Sheng would find a solution on the self-IPI delivery. Let's separate my patch and self-IPI as 2 issues as we don't know when the self-IPI delivery would be resolved.
Sure.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 25 lines · Avi Kivity
Quoted 9 lines · Yanmin
Quoted 7 lines
An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
Yes. But the frame pointer checking seems a little complicated.
An even bigger disadvantage is that it won't work with Sheng's patch, self-NMIs are not synchronous.
Quoted 11 lines
Quoted 11 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 7 lines
trace_kvm_entry(vcpu->vcpu_id);arch/x86/kvm/x86.c +3
-0+ +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Quoted 8 lines
Quoted 5 lines
Right. The kernel part has dependency on the self-IPI implementation. I will move above
percpu_write(current_vcpu, vcpu)(or a new wrapper function) just around 'int $2'.Or create a new function to inject the interrupt in
x86.c. That will reduce duplication betweensvm.candvmx.c.
I checked svm.c and it seems svm.c doesn't trigger a NMI to host if the NMI happens in guest os. In addition, svm_complete_interrupts is called after interrupt is enabled.
Quoted 25 lines · Avi Kivity
Quoted 9 lines · Yanmin
Quoted 7 lines
An even more accurate way to determine this is to check whether the interrupt frame points back at the 'int $2' instruction. However we plan to switch to a self-IPI method to inject the NMI, and I'm not sure wether APIC NMIs are accepted on an instruction boundary or whether there's some latency involved.
Yes. But the frame pointer checking seems a little complicated.
An even bigger disadvantage is that it won't work with Sheng's patch, self-NMIs are not synchronous.
Quoted 11 lines
Quoted 11 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_v · line 4378
Quoted 7 lines
trace_kvm_entry(vcpu->vcpu_id);arch/x86/kvm/x86.c +3
-0+ +percpu_write (current_vcpu, vcpu); kvm_x86_ops->run (vcpu); +percpu_write (current_vcpu,NULL );If you move this around the 'int $2' instructions you will close the race, as a stray NMI won't catch us updating the rip cache. But that depends on whether self-IPI is accepted on the next instruction or not.
Quoted 8 lines
Quoted 5 lines
Right. The kernel part has dependency on the self-IPI implementation. I will move above
percpu_write(current_vcpu, vcpu)(or a new wrapper function) just around 'int $2'.Or create a new function to inject the interrupt in
x86.c. That will reduce duplication betweensvm.candvmx.c.
I checked svm.c and it seems svm.c doesn't trigger a NMI to host if the NMI happens in guest os. In addition, svm_complete_interrupts is called after interrupt is enabled.
Quoted 3 lines · Yanmin
I checked
svm.cand it seemssvm.cdoesn't trigger a NMI to host if the NMI happens in guest os. In addition,svm_complete_interruptsis called after interrupt is enabled.
Yes. The NMI is held pending by the hardware until the STGI instruction is executed.
And for nested svm the svm_complete_interrupts function needs to be executed after the nested exit handling. Therefore it is done late on svm.
Joerg
Quoted 7 lines · oerg Roedel
Quoted 4 lines · Yanmin
I checked
svm.cand it seemssvm.cdoesn't trigger a NMI to host if the NMI happens in guest os. In addition,svm_complete_interruptsis called after interrupt is enabled.
Quoted 6 lines
Yes. The NMI is held pending by the hardware until the STGI instruction is executed.
And for nested svm thesvm_complete_interruptsfunction needs to be executed after the nested exit handling. Therefore it is done late on svm.
So, we'd need something like the following:
if (exit == NMI)
__get_cpu_var(nmi_vcpu) = vcpu;
stgi();
if (exit == NMI) {
while (!nmi_handled())
cpu_relax();
__get_cpu_var(nmi_vcpu) = NULL;
}and no code sharing betweem vmx and svm.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 17 lines · Avi Kivity
Quoted 7 lines · oerg Roedel
Quoted 4 lines · Yanmin
I checked
svm.cand it seemssvm.cdoesn't trigger a NMI to host if the NMI happens in guest os. In addition,svm_complete_interruptsis called after interrupt is enabled.Quoted 6 lines
Yes. The NMI is held pending by the hardware until the STGI instruction is executed.
And for nested svm thesvm_complete_interruptsfunction needs to be executed after the nested exit handling. Therefore it is done late on svm.So, we'd need something like the following:
Quoted 10 lines
if (exit == NMI)
__get_cpu_var(nmi_vcpu) = vcpu;
stgi();
if (exit == NMI) {
while (!nmi_handled())
cpu_relax();
__get_cpu_var(nmi_vcpu) = NULL;
}Hmm, looks a bit complicated to me. The NMI should happen shortly after the stgi instruction. Interrupts are still disabled so we stay on this cpu. Can't we just set and erase the cpu_var at vcpu_load/vcpu_put time?
Joerg
Quoted 14 lines · oerg Roedel
Quoted 14 lines
So, we'd need something like the following:
if (exit == NMI) __get_cpu_var(nmi_vcpu) = vcpu; stgi(); if (exit == NMI) { while (!nmi_handled()) cpu_relax(); __get_cpu_var(nmi_vcpu) = NULL; }
Quoted 5 lines
Hmm, looks a bit complicated to me. The NMI should happen shortly after the stgi instruction. Interrupts are still disabled so we stay on this cpu. Can't we just set and erase the
cpu_varat vcpu_load/vcpu_put time?
That means an NMI that happens outside guest code (for example, in the mmu, or during the exit itself) would be counted as if in guest code.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 15 lines · Avi Kivity
Quoted 14 lines · oerg Roedel
Quoted 14 lines
So, we'd need something like the following:
if (exit == NMI) __get_cpu_var(nmi_vcpu) = vcpu; stgi(); if (exit == NMI) { while (!nmi_handled()) cpu_relax(); __get_cpu_var(nmi_vcpu) = NULL; }
Quoted 8 lines
Quoted 5 lines
Hmm, looks a bit complicated to me. The NMI should happen shortly after the stgi instruction. Interrupts are still disabled so we stay on this cpu. Can't we just set and erase the
cpu_varat vcpu_load/vcpu_put time?That means an NMI that happens outside guest code (for example, in the mmu, or during the exit itself) would be counted as if in guest code.
Hmm, true. The same is true for an NMI that happens between VMSAVE and STGI but that window is smaller. Anyway, I think we don't need the busy-wait loop. The NMI should be executed at a well defined point and we set the cpu_var back to NULL after that point.
Joerg
Quoted 9 lines · Joerg Roedel
Quoted 4 lines
That means an NMI that happens outside guest code (for example, in the mmu, or during the exit itself) would be counted as if in guest code.
Hmm, true. The same is true for an NMI that happens between VMSAVE and STGI but that window is smaller. Anyway, I think we don't need the busy-wait loop. The NMI should be executed at a well defined point and we set the
cpu_varback to NULL after that point.
The point is not well defined. Considering there are already at least two implementations svm, I don't want to rely on implementation details.
We could tune the position of the loop so that zero iterations are executed on the implementations we know about.
Signature · 2 lines
I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.
Quoted 11 lines · On Thursday 15 April 2010 18:44:15 Avi Kivity wrote:
Quoted 7 lines · Joerg Roedel
Quoted 2 lines
That means an NMI that happens outside guest code (for example, in the mmu, or during the exit itself) would be counted as if in guest code.
Hmm, true. The same is true for an NMI that happens between VMSAVE and STGI but that window is smaller. Anyway, I think we don't need the busy-wait loop. The NMI should be executed at a well defined point and we set the
cpu_varback to NULL after that point.The point is not well defined. Considering there are already at least two implementations svm, I don't want to rely on implementation details.
After more investigating, I realized that I had interpreted the SDM wrong. Sorry.
There is *no* risk with the original method of calling "int $2".
According to the SDM 24.1:
Quoted 1 line
The following bullets detail when architectural state is and is not updated
in response to VM exits:
[...]
Quoted 1 line
- An NMI causes subsequent NMIs to be blocked, but only after the VM exit
completes.
So the truth is, after NMI directly caused VMExit, the following NMIs would be blocked, until encountered next "iret". So execute "int $2" is safe in vmx_complete_interrupts(), no risk in causing nested NMI. And it would unblock the following NMIs as well due to "iret" it executed.
So there is unnecessary to make change to avoid "potential nested NMI".
Sorry for the mistake and caused confusing.
Signature · 2 lines
regards Yang, Sheng
Quoted 4 lines
We could tune the position of the loop so that zero iterations are executed on the implementations we know about.
Quoted 30 lines · Sheng Yang
Quoted 5 lines · On Thursday 15 April 2010 18:44:15 Avi Kivity wrote:
Quoted 3 lines · Joerg Roedel
Quoted 3 lines
That means an NMI that happens outside guest code (for example, in the mmu, or during the exit itself) would be counted as if in guest code.
Quoted 8 lines
Quoted 5 lines
Hmm, true. The same is true for an NMI that happens between VMSAVE and STGI but that window is smaller. Anyway, I think we don't need the busy-wait loop. The NMI should be executed at a well defined point and we set the
cpu_varback to NULL after that point.The point is not well defined. Considering there are already at least two implementations svm, I don't want to rely on implementation details.
After more investigating, I realized that I had interpreted the SDM wrong. Sorry.
There is *no* risk with the original method of calling "int $2".
According to the SDM 24.1:
Quoted 2 lines
The following bullets detail when architectural state is and is not updated
in response to VM exits:
[...]Quoted 2 lines
- An NMI causes subsequent NMIs to be blocked, but only after the VM exit
Quoted 9 lines
completes.
So the truth is, after NMI directly caused VMExit, the following NMIs would be blocked, until encountered next "iret". So execute "int $2" is safe in
vmx_complete_interrupts(), no risk in causing nested NMI. And it would unblock the following NMIs as well due to "iret" it executed.So there is unnecessary to make change to avoid "potential nested NMI".
Let's look at the surrounding text...
Quoted 14 lines
The following bullets detail when architectural state is and is not updated in response to VM exits:
• If an event causes a VM exit directly, it does not update architectural state as it
would have if it had it not caused the VM exit:
— A debug exception does not update DR6, DR7.GD, or IA32_DEBUGCTL.LBR.
(Information about the nature of the debug exception is saved
in the exit
qualification field.)
— A page fault does not update CR2. (The linear address causing
the page fault
is saved in the exit-qualification field.)
— An NMI causes subsequent NMIs to be blocked, but only after the
VM exit
Quoted 8 lines
completes.
— An external interrupt does not acknowledge the interrupt
controller and the
interrupt remains pending, unless the “acknowledge interrupt
on exit”
VM-exit control is 1. In such a case, the interrupt controller
is acknowledged
and the interrupt is no longer pending.
Everywhere it says state is _not_ updated, so I think what is meant is that NMIs are blocked, but only _until_ the VM exit completes.
I think you were right the first time around. Can you check with your architecture team?
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 3 lines · Avi Kivity
I think you were right the first time around.
Re-reading again (esp. the part about treatment of indirect NMI vmexits), I think this was wrong, and that the code is correct. I am now thoroughly confused.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 7 lines · On Monday 19 April 2010 16:25:17 Avi Kivity wrote:
Quoted 1 line · Avi Kivity
I think you were right the first time around.
Re-reading again (esp. the part about treatment of indirect NMI vmexits), I think this was wrong, and that the code is correct. I am now thoroughly confused.
My fault...
To my understanding now, "If an event causes a VM exit directly, it does not update architectural state as it would have if it had it not caused the VM exit:", means: in NMI case, NMI would involve the NMI handler, and change the "architectural state" to NMI block. In VMX non-root mode, the behavior of calling NMI handler changed(determine by some VMCS fields), but not the affection to the "architectural state". So the NMI block state would remain the same.
Signature · 2 lines
regards Yang, Sheng
Quoted 4 lines · Sheng Yang
Quoted 2 lines · On Monday 19 April 2010 16:25:17 Avi Kivity wrote:
On 04/17/2010 09:12 PM, Avi Kivity wrote:
Quoted 9 lines
Quoted 7 lines
Quoted 2 lines
I think you were right the first time around.
Re-reading again (esp. the part about treatment of indirect NMI vmexits), I think this was wrong, and that the code is correct. I am now thoroughly confused.
My fault...
Not at all, it's really confusingly worded.
Quoted 8 lines
To my understanding now, "If an event causes a VM exit directly, it does not update architectural state as it would have if it had it not caused the VM exit:", means: in NMI case, NMI would involve the NMI handler, and change the "architectural state" to NMI block. In VMX non-root mode, the behavior of calling NMI handler changed(determine by some VMCS fields), but not the affection to the "architectural state". So the NMI block state would remain the same.
Agree. It's confusing because the internal "nmi pending" flag is not set, while the "nmi blocking" flag is set.
(on svm both are set, but the NMI is not taken until the vmexit completes and the host unmasks NMIs).
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
PATCH 1/1 Psychovisually-optimized HZ setting (2.6.33.3)
In reply to Zhang, YanminThis is based on the research I did with optimizing my machine for graphics.
I also wrote the following article: http://www.paradoxuncreated.com/articles/Millennium/Millennium.html
It is a bit outdated now, but I will update it with current information.
The value might iterate.
Peace Be With You,
Uwaysi Bin Kareem.
Kconfig.hz renamed from Kconfig.hzorig +13 -0
@@ -45,6 +45,18 @@ 1000 Hz is the preferred choice for desktop systems and other systems requiring fast interactive responses to events. + config HZ_3956 + bool "3956 HZ" + help + 3956 Hz is nearly the highest timer interrupt rate supported in the kernel. + Graphics workstations, and OpenGL applications may benefit from this, + since it gives the lowest framerate-jitter. The exact value 3956 is + psychovisually-optimized, meaning that it aims for a level of jitter, + percieved to be natural, and therefore non-nosiy. It is tuned for a + profile of "where the human senses register the most information". + + + endchoice config HZ
@@ -53,6 +65,7 @@ default 250 if HZ_250 default 300 if HZ_300 default 1000 if HZ_1000 + default 3956 if HZ_3956 config SCHED_HRTICK def_bool HIGH_RES_TIMERS && (!SMP || USE_GENERIC_SMP_HELPERS)
Re: [PATCH] Psychovisually-optimized HZ setting (2.6.33.3)
Quoted 6 lines · On Tue, 27 Apr 2010 21:03:11 +0200 Uwaysi Bin Kareem wrote:
This is based on the research I did with optimizing my machine for graphics.
I also wrote the following article:
http://www.paradoxuncreated.com/articles/Millennium/Millennium.html
It is a bit outdated now, but I will update it with current information. The value might iterate.
Hi,
What CPU architectures or platforms did you test this on? Were any other kernel changes needed?
Quoted 15 lines
Peace Be With You,
Uwaysi Bin Kareem.Kconfig.hz renamed from Kconfig.hzorig +4
-0@@ -45,6 +45,18 @@ 1000 Hz is the preferred choice for desktop systems and other systems requiring fast interactive responses to events. + config HZ_3956 + bool "3956 HZ" + help + 3956 Hz is nearly the highest timer interrupt rate supported in thekernel.
Kconfig.hz line 52
Quoted 1 line
Kconfig.hz renamed from Kconfig.hzorig +1
-0+ Graphics workstations, and OpenGL applications may benefit from this,
drop first comma.
Kconfig.hz line 55
Quoted 3 lines
Kconfig.hz renamed from Kconfig.hzorig +3
-0+ since it gives the lowest framerate-jitter. The exact value 3956 is + psychovisually-optimized, meaning that it aims for a level of jitter, + percieved to be natural, and therefore non-nosiy. It is tuned for a
perceived non-noisy.
Quoted 8 lines
Kconfig.hz renamed from Kconfig.hzorig +4
-0+ profile of "where the human senses register the most information". + + + endchoice config HZ
Kconfig.hz
Quoted 9 lines
Kconfig.hz renamed from Kconfig.hzorig +1
-1@@ -53,6 +65,7 @@ default 250 if HZ_250 default 300 if HZ_300 default 1000 if HZ_1000 + default 3956 if HZ_3956 config SCHED_HRTICK def_bool HIGH_RES_TIMERS && (!SMP || USE_GENERIC_SMP_HELPERS) --
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
Re: [PATCH] Psychovisually-optimized HZ setting (2.6.33.3)
In reply to Uwaysi Bin KareemKconfig.hz line 54
Quoted 9 lines · Uwaysi Bin Kareem
http://www.paradoxuncreated.com/articles/Millennium/Millennium.html
Kconfig.hz renamed from Kconfig.hzorig +7
-0+ config HZ_3956 + bool "3956 HZ" + help + 3956 Hz is nearly the highest timer interrupt rate supported in the kernel. + Graphics workstations, and OpenGL applications may benefit from this, + since it gives the lowest framerate-jitter. The exact value 3956 is + psychovisually-optimized, meaning that it aims for a level of jitter,
Even after reading your link, it's unclear why 3956 and not 4000. All your link said was "A granularity below 0.5 milliseconds, seems to suit the human senses." - anything over 2000 meets that requirement. Also, if your screen refresh is sitting at 72hz or a bit under 14ms per refresh, any jitter under that won't really matter much - it doesn't matter if your next frame is ready 5ms early or 5.5ms early, you *still* have to wait for the next vertical blanking interval or suffer tearing.
There's also the case of programs where HZ=300 would *make* the time budget, but the added 3,356 timer interrupts and associated overhead would cause a missed screen refresh.
I think you need more technical justification of why 3956 is better than 1000.