From 1541b26086464f99607d3080386446c7a67d7b88 Mon Sep 17 00:00:00 2001 From: Ken Sato Date: Thu, 27 Apr 2017 17:13:49 +0900 Subject: [PATCH] ihklib: add pa_info functions. --- executer/include/uprotocol.h | 30 ++++ executer/kernel/mcctrl/control.c | 255 ++++++++++++++++++++++++++++++- executer/kernel/mcctrl/driver.c | 7 + executer/kernel/mcctrl/ikc.c | 4 + executer/kernel/mcctrl/mcctrl.h | 14 ++ kernel/host.c | 47 ++++++ kernel/include/syscall.h | 33 ++++ 7 files changed, 389 insertions(+), 1 deletion(-) diff --git a/executer/include/uprotocol.h b/executer/include/uprotocol.h index 9cf3eb45..765aace0 100644 --- a/executer/include/uprotocol.h +++ b/executer/include/uprotocol.h @@ -220,4 +220,34 @@ struct sys_unshare_desc { unsigned long unshare_flags; }; +enum perf_ctrl_type { + PERF_CTRL_SET, + PERF_CTRL_GET, + PERF_CTRL_ENABLE, + PERF_CTRL_DISABLE, +}; + +struct perf_ctrl_desc { + enum perf_ctrl_type ctrl_type; + int status; + union { + /* for SET, GET */ + struct { + unsigned int target_cntr; + unsigned long config; + unsigned long read_value; + unsigned disabled :1, + pinned :1, + exclude_user :1, + exclude_kernel :1, + exclude_hv :1, + exclude_idle :1; + }; + + /* for START, STOP*/ + struct { + unsigned long target_cntr_mask; + }; + }; +}; #endif diff --git a/executer/kernel/mcctrl/control.c b/executer/kernel/mcctrl/control.c index 98e40dbe..e3bbe693 100644 --- a/executer/kernel/mcctrl/control.c +++ b/executer/kernel/mcctrl/control.c @@ -40,6 +40,7 @@ #include #include "../../config.h" #include "mcctrl.h" +#include //#define DEBUG @@ -360,7 +361,7 @@ static long mcexec_newprocess(ihk_os_t os, struct newprocess_desc desc; struct release_handler_info *info; - if (copy_from_user(&desc, udesc, sizeof(struct newprocess_desc))) { + if (copy_from_user(&desc, udesc, sizeof(struct newprocess_desc))) { return -EFAULT; } info = kmalloc(sizeof(struct release_handler_info), GFP_KERNEL); @@ -1588,6 +1589,240 @@ long mcexec_sys_unshare(struct sys_unshare_desc *__user arg) return ret; } +static DECLARE_WAIT_QUEUE_HEAD(perfctrlq); + +long mcctrl_perf_num(ihk_os_t os, unsigned long arg) +{ + struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + + usrdata->perf_event_num = arg; + + return 0; +} + +long mcctrl_perf_set(ihk_os_t os, struct ihk_perf_event_attr *__user arg) +{ + struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + struct ikc_scd_packet isp; + struct perf_ctrl_desc *perf_desc = NULL; + struct ihk_perf_event_attr attr; + struct ihk_cpu_info *info = ihk_os_get_cpu_info(os); + int ret = 0; + int i = 0, j = 0; + + for (i = 0; i < usrdata->perf_event_num; i++) { + if (copy_from_user(&attr, &arg[i], sizeof(struct ihk_perf_event_attr))) { + printk("%s: error: copying ihk_perf_event_attr from user\n", + __FUNCTION__); + return -EINVAL; + } + + for (j = 0; j < info->n_cpus; j++) { + perf_desc = kmalloc(sizeof(struct perf_ctrl_desc), GFP_KERNEL); + if (!perf_desc) { + printk("%s: error: allocating perf_ctrl_desc\n", + __FUNCTION__); + return -ENOMEM; + } + memset(perf_desc, '\0', sizeof(struct perf_ctrl_desc)); + + perf_desc->ctrl_type = PERF_CTRL_SET; + perf_desc->status = 0; + perf_desc->target_cntr = i; + perf_desc->config = attr.config; + perf_desc->exclude_kernel = attr.exclude_kernel; + perf_desc->exclude_user = attr.exclude_user; + + memset(&isp, '\0', sizeof(struct ikc_scd_packet)); + isp.msg = SCD_MSG_PERF_CTRL; + isp.arg = virt_to_phys(perf_desc); + + if ((ret = mcctrl_ikc_send(os, j, &isp)) < 0) { + printk("%s: mcctrl_ikc_send ret=%d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + + ret = wait_event_interruptible(perfctrlq, perf_desc->status); + if (ret < 0) { + printk("%s: ERROR after wait: %d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + + kfree(perf_desc); + } + } + + return usrdata->perf_event_num; +} + +long mcctrl_perf_get(ihk_os_t os, unsigned long *__user arg) +{ + struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + struct ikc_scd_packet isp; + struct perf_ctrl_desc *perf_desc = NULL; + struct ihk_cpu_info *info = ihk_os_get_cpu_info(os); + unsigned long value_sum = 0; + int ret = 0; + int i = 0, j = 0; + + for (i = 0; i < usrdata->perf_event_num; i++) { + for (j = 0; j < info->n_cpus; j++) { + perf_desc = kmalloc(sizeof(struct perf_ctrl_desc), GFP_KERNEL); + if (!perf_desc) { + printk("%s: error: allocating perf_ctrl_desc\n", + __FUNCTION__); + return -ENOMEM; + } + memset(perf_desc, '\0', sizeof(struct perf_ctrl_desc)); + + perf_desc->ctrl_type = PERF_CTRL_GET; + perf_desc->status = 0; + perf_desc->target_cntr = i; + + memset(&isp, '\0', sizeof(struct ikc_scd_packet)); + isp.msg = SCD_MSG_PERF_CTRL; + isp.arg = virt_to_phys(perf_desc); + + if ((ret = mcctrl_ikc_send(os, j, &isp)) < 0) { + printk("%s: mcctrl_ikc_send ret=%d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + + ret = wait_event_interruptible(perfctrlq, perf_desc->status); + if (ret < 0) { + printk("%s: ERROR after wait: %d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + value_sum += perf_desc->read_value; + kfree(perf_desc); + } + if (copy_to_user(&arg[i], &value_sum, sizeof(unsigned long))) { + printk("%s: error: copying read_value to user\n", + __FUNCTION__); + return -EINVAL; + } + value_sum = 0; + } + + return 0; +} + +long mcctrl_perf_enable(ihk_os_t os) +{ + struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + struct ikc_scd_packet isp; + struct perf_ctrl_desc *perf_desc = NULL; + struct ihk_cpu_info *info = ihk_os_get_cpu_info(os); + unsigned int cntr_mask = 0; + int ret = 0; + int i = 0, j = 0; + + for (i = 0; i < usrdata->perf_event_num; i++) { + cntr_mask |= 1 << i; + } + for (j = 0; j < info->n_cpus; j++) { + perf_desc = kmalloc(sizeof(struct perf_ctrl_desc), GFP_KERNEL); + if (!perf_desc) { + printk("%s: error: allocating perf_ctrl_desc\n", + __FUNCTION__); + return -ENOMEM; + } + memset(perf_desc, '\0', sizeof(struct perf_ctrl_desc)); + + perf_desc->ctrl_type = PERF_CTRL_ENABLE; + perf_desc->status = 0; + perf_desc->target_cntr_mask = cntr_mask; + + memset(&isp, '\0', sizeof(struct ikc_scd_packet)); + isp.msg = SCD_MSG_PERF_CTRL; + isp.arg = virt_to_phys(perf_desc); + + if ((ret = mcctrl_ikc_send(os, j, &isp)) < 0) { + printk("%s: mcctrl_ikc_send ret=%d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + + ret = wait_event_interruptible(perfctrlq, perf_desc->status); + if (ret < 0) { + printk("%s: ERROR after wait: %d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + kfree(perf_desc); + } + + return 0; +} + +long mcctrl_perf_disable(ihk_os_t os) +{ + struct mcctrl_usrdata *usrdata = ihk_host_os_get_usrdata(os); + struct ikc_scd_packet isp; + struct perf_ctrl_desc *perf_desc = NULL; + struct ihk_cpu_info *info = ihk_os_get_cpu_info(os); + unsigned int cntr_mask = 0; + int ret = 0; + int i = 0, j = 0; + + for (i = 0; i < usrdata->perf_event_num; i++) { + cntr_mask |= 1 << i; + } + for (j = 0; j < info->n_cpus; j++) { + perf_desc = kmalloc(sizeof(struct perf_ctrl_desc), GFP_KERNEL); + if (!perf_desc) { + printk("%s: error: allocating perf_ctrl_desc\n", + __FUNCTION__); + return -ENOMEM; + } + memset(perf_desc, '\0', sizeof(struct perf_ctrl_desc)); + + perf_desc->ctrl_type = PERF_CTRL_DISABLE; + perf_desc->status = 0; + perf_desc->target_cntr_mask = cntr_mask; + + memset(&isp, '\0', sizeof(struct ikc_scd_packet)); + isp.msg = SCD_MSG_PERF_CTRL; + isp.arg = virt_to_phys(perf_desc); + + if ((ret = mcctrl_ikc_send(os, j, &isp)) < 0) { + printk("%s: mcctrl_ikc_send ret=%d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + + ret = wait_event_interruptible(perfctrlq, perf_desc->status); + if (ret < 0) { + printk("%s: ERROR after wait: %d\n", __FUNCTION__, ret); + kfree(perf_desc); + return -EINVAL; + } + kfree(perf_desc); + } + + return 0; +} + +long mcctrl_perf_destroy(ihk_os_t os) +{ + mcctrl_perf_disable(os); + mcctrl_perf_num(os, 0); + return 0; +} + +void mcctrl_perf_ack(ihk_os_t os, struct ikc_scd_packet *packet) +{ + struct perf_ctrl_desc *perf_desc = phys_to_virt(packet->arg); + + perf_desc->status = 1; + wake_up_interruptible(&perfctrlq); + +} + long __mcctrl_control(ihk_os_t os, unsigned int req, unsigned long arg, struct file *file) { @@ -1659,6 +1894,24 @@ long __mcctrl_control(ihk_os_t os, unsigned int req, unsigned long arg, case MCEXEC_UP_DEBUG_LOG: return mcexec_debug_log(os, arg); + + case IHK_OS_AUX_PERF_NUM: + return mcctrl_perf_num(os, arg); + + case IHK_OS_AUX_PERF_SET: + return mcctrl_perf_set(os, (struct ihk_perf_event_attr *)arg); + + case IHK_OS_AUX_PERF_GET: + return mcctrl_perf_get(os, (unsigned long *)arg); + + case IHK_OS_AUX_PERF_ENABLE: + return mcctrl_perf_enable(os); + + case IHK_OS_AUX_PERF_DISABLE: + return mcctrl_perf_disable(os); + + case IHK_OS_AUX_PERF_DESTROY: + return mcctrl_perf_destroy(os); } return -EINVAL; } diff --git a/executer/kernel/mcctrl/driver.c b/executer/kernel/mcctrl/driver.c index a532b43d..c3d15420 100644 --- a/executer/kernel/mcctrl/driver.c +++ b/executer/kernel/mcctrl/driver.c @@ -27,6 +27,7 @@ #include #include #include "mcctrl.h" +#include #define OS_MAX_MINOR 64 @@ -74,6 +75,12 @@ static struct ihk_os_user_call_handler mcctrl_uchs[] = { { .request = MCEXEC_UP_SYS_UMOUNT, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_SYS_UNSHARE, .func = mcctrl_ioctl }, { .request = MCEXEC_UP_DEBUG_LOG, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_NUM, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_SET, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_GET, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_ENABLE, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_DISABLE, .func = mcctrl_ioctl }, + { .request = IHK_OS_AUX_PERF_DESTROY, .func = mcctrl_ioctl }, }; static struct ihk_os_user_call mcctrl_uc_proto = { diff --git a/executer/kernel/mcctrl/ikc.c b/executer/kernel/mcctrl/ikc.c index 780fe031..89263c02 100644 --- a/executer/kernel/mcctrl/ikc.c +++ b/executer/kernel/mcctrl/ikc.c @@ -53,6 +53,7 @@ void mcexec_prepare_ack(ihk_os_t os, unsigned long arg, int err); static void mcctrl_ikc_init(ihk_os_t os, int cpu, unsigned long rphys, struct ihk_ikc_channel_desc *c); int mcexec_syscall(struct mcctrl_usrdata *ud, struct ikc_scd_packet *packet); void sig_done(unsigned long arg, int err); +void mcctrl_perf_ack(ihk_os_t os, struct ikc_scd_packet *packet); /* XXX: this runs in atomic context! */ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, @@ -109,6 +110,9 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, get_vdso_info(__os, pisp->arg); break; + case SCD_MSG_PERF_ACK: + mcctrl_perf_ack(__os, pisp); + break; default: printk(KERN_ERR "mcctrl:syscall_packet_handler:" "unknown message (%d.%d.%d.%d.%d.%#lx)\n", diff --git a/executer/kernel/mcctrl/mcctrl.h b/executer/kernel/mcctrl/mcctrl.h index c9b8804a..155f9937 100644 --- a/executer/kernel/mcctrl/mcctrl.h +++ b/executer/kernel/mcctrl/mcctrl.h @@ -92,6 +92,9 @@ #define SCD_MSG_PROCFS_TID_CREATE 0x44 #define SCD_MSG_PROCFS_TID_DELETE 0x45 +#define SCD_MSG_PERF_CTRL 0x50 +#define SCD_MSG_PERF_ACK 0x51 + #define DMA_PIN_SHIFT 21 #define DO_USER_MODE @@ -299,6 +302,7 @@ struct mcctrl_usrdata { struct list_head cpu_topology_list; struct list_head node_topology_list; struct mcctrl_part_exec part_exec; + int perf_event_num; }; struct mcctrl_signal { @@ -402,4 +406,14 @@ struct get_cpu_mapping_req { wait_queue_head_t wq; }; +struct ihk_perf_event_attr{ + unsigned long config; + unsigned disabled:1; + unsigned pinned:1; + unsigned exclude_user:1; + unsigned exclude_kernel:1; + unsigned exclude_hv:1; + unsigned exclude_idle:1; +}; + #endif diff --git a/kernel/host.c b/kernel/host.c index 081280c1..d4896d75 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -31,6 +31,7 @@ #include #include #include +#include //#define DEBUG_PRINT_HOST @@ -488,6 +489,8 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, unsigned long pp; int cpuid; int ret = 0; + struct perf_ctrl_desc *pcd; + unsigned int mode = 0; switch (packet->msg) { case SCD_MSG_INIT_CHANNEL_ACKED: @@ -597,6 +600,50 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, ret = 0; break; + case SCD_MSG_PERF_CTRL: + pp = ihk_mc_map_memory(NULL, packet->arg, sizeof(struct perf_ctrl_desc)); + pcd = (struct perf_ctrl_desc *)ihk_mc_map_virtual(pp, 1, PTATTR_WRITABLE | PTATTR_ACTIVE); + + switch (pcd->ctrl_type) { + case PERF_CTRL_SET: + if (!pcd->exclude_kernel) { + mode |= PERFCTR_KERNEL_MODE; + } + if (!pcd->exclude_user) { + mode |= PERFCTR_USER_MODE; + } + ihk_mc_perfctr_init_raw(pcd->target_cntr, pcd->config, mode); + ihk_mc_perfctr_stop(1 << pcd->target_cntr); + ihk_mc_perfctr_reset(pcd->target_cntr); + break; + + case PERF_CTRL_ENABLE: + ihk_mc_perfctr_start(pcd->target_cntr_mask); + break; + + case PERF_CTRL_DISABLE: + ihk_mc_perfctr_stop(pcd->target_cntr_mask); + break; + + case PERF_CTRL_GET: + pcd->read_value = ihk_mc_perfctr_read(pcd->target_cntr); + break; + + default: + kprintf("%s: SCD_MSG_PERF_CTRL unexpected ctrl_type\n", __FUNCTION__); + } + + ihk_mc_unmap_virtual(pcd, 1, 0); + ihk_mc_unmap_memory(NULL, pp, sizeof(struct perf_ctrl_desc)); + + pckt.msg = SCD_MSG_PERF_ACK; + pckt.err = 0; + pckt.arg = packet->arg; + ihk_ikc_send(c, &pckt, 0); + + ret = 0; + break; + default: kprintf("syscall_pakcet_handler:unknown message " "(%d.%d.%d.%d.%d.%#lx)\n", diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 49a7b409..182542c1 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -75,6 +75,9 @@ #define SCD_MSG_PROCFS_TID_DELETE 0x45 #define SCD_MSG_EVENT_SIGNAL 0x46 +#define SCD_MSG_PERF_CTRL 0x50 +#define SCD_MSG_PERF_ACK 0x51 + /* Cloning flags. */ # define CSIGNAL 0x000000ff /* Signal mask to be sent at exit. */ # define CLONE_VM 0x00000100 /* Set if VM shared between processes. */ @@ -445,4 +448,34 @@ struct get_cpu_mapping_req { #endif }; +enum perf_ctrl_type { + PERF_CTRL_SET, + PERF_CTRL_GET, + PERF_CTRL_ENABLE, + PERF_CTRL_DISABLE, +}; + +struct perf_ctrl_desc { + enum perf_ctrl_type ctrl_type; + int status; + union { + /* for SET, GET */ + struct { + unsigned int target_cntr; + unsigned long config; + unsigned long read_value; + unsigned disabled :1, + pinned :1, + exclude_user :1, + exclude_kernel :1, + exclude_hv :1, + exclude_idle :1; + }; + + /* for START, STOP*/ + struct { + unsigned long target_cntr_mask; + }; + }; +}; #endif