From: Jan Kiszka <jan.kis...@siemens.com> The hypervisor already provides us the counter CPU-specific, we just need to expose them separated, in addition to the existing accumulated representation. This helps to identify hypervisor interferences in multicore cells that use core-specific workload.
The CPU-specific statistics are created for all CPUs during root cell setup as separate kobjects. When a non-root cell is create the kobjects associated with those CPUs that this cell is assigned are simply moved from the root cell to the new one. On non-root cell destruction, the kobjects are moved back. They are truly destroyed on root cell tear-down. Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- Documentation/sysfs-entries.txt | 17 +++--- driver/cell.h | 1 + driver/sysfs.c | 131 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 7 deletions(-) diff --git a/Documentation/sysfs-entries.txt b/Documentation/sysfs-entries.txt index 58d1f5a2..45db280a 100644 --- a/Documentation/sysfs-entries.txt +++ b/Documentation/sysfs-entries.txt @@ -22,14 +22,17 @@ can be used for monitoring the state of the hypervisor and its cells. | |- cpus_failed_list - human readable list of logical CPUs that | | caused a failure | `- statistics - | |- vmexits_total - Total number of VM exits - | `- vmexits_<reason> - VM exits due to <reason> + | |- cpu<n> + | | |- vmexits_total - Total number of VM exits on CPU <n> + | | `- vmexits_<reason> - VM exits due to <reason> on CPU <n> + | |- vmexits_total - Total number of VM exits on all cell CPUs + | `- vmexits_<reason> - VM exits due to <reason> on all cell CPUs `- ... -Note that statistics are accumulated non-atomically over all CPUs of a cell and -may not reflect a fully consistent state. The existence and semantics of VM -exit reason values are architecture-dependent and may change in future -versions. In general statistics shall only be considered as a first hint when -analyzing cell behavior. +Note that accumulated statistics over all CPUs of a cell are not collected +atomically and may not reflect a fully consistent state. The existence and +semantics of VM exit reason values are architecture-dependent and may change in +future versions. In general statistics shall only be considered as a first hint +when analyzing cell behavior. [1] Documentation/debug-output.md diff --git a/driver/cell.h b/driver/cell.h index c463dd32..92afbff8 100644 --- a/driver/cell.h +++ b/driver/cell.h @@ -25,6 +25,7 @@ struct cell { struct kobject kobj; struct kobject stats_kobj; + struct list_head cell_cpus; struct list_head entry; unsigned int id; char name[JAILHOUSE_CELL_ID_NAMELEN+1]; diff --git a/driver/sysfs.c b/driver/sysfs.c index 40f57ddb..8648cfeb 100644 --- a/driver/sysfs.c +++ b/driver/sysfs.c @@ -21,6 +21,7 @@ #include <linux/version.h> #include <linux/gfp.h> #include <linux/stat.h> +#include <linux/slab.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) #define DEVICE_ATTR_RO(_name) \ @@ -62,6 +63,12 @@ static const struct sysfs_ops cell_sysfs_ops = { static struct kobject *cells_dir; +struct cell_cpu { + struct kobject kobj; + struct list_head entry; + unsigned int cpu; +}; + struct jailhouse_cpu_stats_attr { struct kobj_attribute kattr; unsigned int code; @@ -89,10 +96,31 @@ static ssize_t cell_stats_show(struct kobject *kobj, return sprintf(buffer, "%lu\n", sum); } +static ssize_t cpu_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buffer) +{ + struct jailhouse_cpu_stats_attr *stats_attr = + container_of(attr, struct jailhouse_cpu_stats_attr, kattr); + unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code; + struct cell_cpu *cell_cpu = container_of(kobj, struct cell_cpu, kobj); + int value; + + value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cell_cpu->cpu, + code); + if (value < 0) + value = 0; + + return sprintf(buffer, "%d\n", value); +} + #define JAILHOUSE_CPU_STATS_ATTR(_name, _code) \ static struct jailhouse_cpu_stats_attr _name##_cell_attr = { \ .kattr = __ATTR(_name, S_IRUGO, cell_stats_show, NULL), \ .code = _code, \ + }; \ + static struct jailhouse_cpu_stats_attr _name##_cpu_attr = { \ + .kattr = __ATTR(_name, S_IRUGO, cpu_stats_show, NULL), \ .code = _code, \ } @@ -156,6 +184,37 @@ static struct kobj_type cell_stats_type = { .default_attrs = cell_stats_attrs, }; +static struct attribute *cpu_stats_attrs[] = { + &vmexits_total_cpu_attr.kattr.attr, + &vmexits_mmio_cpu_attr.kattr.attr, + &vmexits_management_cpu_attr.kattr.attr, + &vmexits_hypercall_cpu_attr.kattr.attr, +#ifdef CONFIG_X86 + &vmexits_pio_cpu_attr.kattr.attr, + &vmexits_xapic_cpu_attr.kattr.attr, + &vmexits_cr_cpu_attr.kattr.attr, + &vmexits_cpuid_cpu_attr.kattr.attr, + &vmexits_xsetbv_cpu_attr.kattr.attr, + &vmexits_exception_cpu_attr.kattr.attr, + &vmexits_msr_other_cpu_attr.kattr.attr, + &vmexits_msr_x2apic_icr_cpu_attr.kattr.attr, +#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) + &vmexits_maintenance_cpu_attr.kattr.attr, + &vmexits_virt_irq_cpu_attr.kattr.attr, + &vmexits_virt_sgi_cpu_attr.kattr.attr, + &vmexits_psci_cpu_attr.kattr.attr, +#ifdef CONFIG_ARM + &vmexits_cp15_cpu_attr.kattr.attr, +#endif +#endif + NULL +}; + +static struct kobj_type cell_cpu_type = { + .sysfs_ops = &kobj_sysfs_ops, + .default_attrs = cpu_stats_attrs, +}; + static int print_cpumask(char *buf, size_t size, cpumask_t *mask, bool as_list) { int written; @@ -287,8 +346,21 @@ static struct kobj_type cell_type = { .default_attrs = cell_attrs, }; +static struct cell_cpu *find_cell_cpu(struct cell *cell, unsigned int cpu) +{ + struct cell_cpu *cell_cpu; + + list_for_each_entry(cell_cpu, &root_cell->cell_cpus, entry) + if (cell_cpu->cpu == cpu) + return cell_cpu; + + return NULL; +} + int jailhouse_sysfs_cell_create(struct cell *cell) { + struct cell_cpu *cell_cpu; + unsigned int cpu; int err; err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%d", @@ -306,6 +378,43 @@ int jailhouse_sysfs_cell_create(struct cell *cell) return err; } + INIT_LIST_HEAD(&cell->cell_cpus); + + for_each_cpu(cpu, &cell->cpus_assigned) { + if (root_cell == NULL) { + cell_cpu = kzalloc(sizeof(struct cell_cpu), GFP_KERNEL); + if (cell_cpu == NULL) { + jailhouse_sysfs_cell_delete(cell); + return -ENOMEM; + } + + cell_cpu->cpu = cpu; + + err = kobject_init_and_add(&cell_cpu->kobj, + &cell_cpu_type, + &cell->stats_kobj, + "cpu%u", cpu); + if (err) { + jailhouse_cell_kobj_release(&cell_cpu->kobj); + kfree(cell_cpu); + jailhouse_sysfs_cell_delete(cell); + return err; + } + list_add_tail(&cell_cpu->entry, &cell->cell_cpus); + } else { + cell_cpu = find_cell_cpu(root_cell, cpu); + if (WARN_ON(cell_cpu == NULL)) + continue; + + err = kobject_move(&cell_cpu->kobj, &cell->stats_kobj); + if (WARN_ON(err)) + continue; + + list_del(&cell_cpu->entry); + list_add_tail(&cell_cpu->entry, &cell->cell_cpus); + } + } + return 0; } @@ -316,6 +425,28 @@ void jailhouse_sysfs_cell_register(struct cell *cell) void jailhouse_sysfs_cell_delete(struct cell *cell) { + struct cell_cpu *cell_cpu, *tmp; + int err; + + if (cell == root_cell) { + list_for_each_entry_safe(cell_cpu, tmp, &cell->cell_cpus, + entry) { + list_del(&cell_cpu->entry); + kobject_put(&cell_cpu->kobj); + kfree(cell_cpu); + } + } else { + list_for_each_entry_safe(cell_cpu, tmp, &cell->cell_cpus, + entry) { + err = kobject_move(&cell_cpu->kobj, + &root_cell->stats_kobj); + if (WARN_ON(err)) + continue; + + list_del(&cell_cpu->entry); + list_add_tail(&cell_cpu->entry, &root_cell->cell_cpus); + } + } kobject_put(&cell->stats_kobj); kobject_put(&cell->kobj); } -- 2.16.4 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to jailhouse-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.