From ad1cbb7623fbf408d99b5d612273024a134cfc2e Mon Sep 17 00:00:00 2001 From: Minggui Cao Date: Mon, 29 Oct 2018 14:24:54 +0800 Subject: [PATCH] DM: add interface to set intr storm monitor params modify and add interface to set interrupt monitor params; it can be set by acrn-dm input arguments like following: --intr_monitor 10000,10,1,100 the 4 params order is: interrupt storm theshold per second, probe period to get interrupt data, pass-through devices' interrupt injection delay time, delay duration, after it, stop injection & restore to normal Tracked-On: #1724 Signed-off-by: Minggui Cao Acked-by: Yin Fengwei --- devicemodel/core/main.c | 12 +++++- devicemodel/core/monitor.c | 81 +++++++++++++++++++++++++++-------- devicemodel/include/monitor.h | 1 + 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c index 96c46a657..83a3d6012 100644 --- a/devicemodel/core/main.c +++ b/devicemodel/core/main.c @@ -157,7 +157,9 @@ usage(int code) " --part_info: guest partition info file path\n" " --enable_trusty: enable trusty for guest\n" " --ptdev_no_reset: disable reset check for ptdev\n" - " --debugexit: enable debug exit function\n", + " --debugexit: enable debug exit function\n" + " --intr_monitor: enable interrupt storm monitor\n" + "............its params: threshold/s,probe-period(s),delay_time(ms),delay_duration(ms)\n", progname, (int)strlen(progname), "", (int)strlen(progname), "", (int)strlen(progname), ""); @@ -701,6 +703,7 @@ enum { CMD_OPT_DEBUGEXIT, CMD_OPT_VMCFG, CMD_OPT_DUMP, + CMD_OPT_INTR_MONITOR, }; static struct option long_options[] = { @@ -734,6 +737,7 @@ static struct option long_options[] = { {"ptdev_no_reset", no_argument, 0, CMD_OPT_PTDEV_NO_RESET}, {"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT}, + {"intr_monitor", required_argument, 0, CMD_OPT_INTR_MONITOR}, {0, 0, 0, 0 }, }; @@ -859,6 +863,12 @@ dm_run(int argc, char *argv[]) case CMD_OPT_DEBUGEXIT: debugexit_enabled = true; break; + case CMD_OPT_INTR_MONITOR: + if (acrn_parse_intr_monitor(optarg) != 0) { + errx(EX_USAGE, "invalid intr-monitor params %s", optarg); + exit(1); + } + break; case 'h': usage(0); default: diff --git a/devicemodel/core/monitor.c b/devicemodel/core/monitor.c index 26afb48b5..21a127543 100644 --- a/devicemodel/core/monitor.c +++ b/devicemodel/core/monitor.c @@ -18,6 +18,7 @@ #include #include #include "dm.h" +#include "dm_string.h" #include "monitor.h" #include "acrn_mngr.h" #include "pm.h" @@ -30,6 +31,14 @@ #define DELAY_DURATION 100000 /* 100ms of total duration for delay intr */ #define TIME_TO_CHECK_AGAIN 2 /* 2seconds */ +struct intr_monitor_setting_t { + bool enable; + uint32_t threshold; /* intr count in probe_period when intr storm happens */ + uint32_t probe_period; /* seconds: the period to probe intr data */ + uint32_t delay_time; /* ms: the time to delay each intr injection */ + uint32_t delay_duration; /* us: the delay duration, after it, intr injection restore to normal */ +}; + union intr_monitor_t { struct acrn_intr_monitor monitor; char reserved[4096]; @@ -39,6 +48,10 @@ static union intr_monitor_t intr_data; static uint64_t intr_cnt_buf[MAX_PTDEV_NUM * 2]; static pthread_t intr_storm_monitor_pid; +static struct intr_monitor_setting_t intr_monitor_setting = { + .enable = false, +}; + /* switch macro, just open in debug */ /* #define INTR_MONITOR_DBG */ @@ -59,8 +72,7 @@ static void write_intr_data_to_file(const struct acrn_intr_monitor *hdr) for (j = 0; j < hdr->buf_cnt; j += 2) { if (hdr->buffer[j + 1] != 0) { - fprintf(dbg_file, "%ld\t\t%ld\n", hdr->buffer[j], - hdr->buffer[j + 1]); + fprintf(dbg_file, "%ld\t\t%ld\n", hdr->buffer[j], hdr->buffer[j + 1]); } } @@ -80,7 +92,7 @@ static void *intr_storm_monitor_thread(void *arg) #ifdef INTR_MONITOR_DBG dbg_file = fopen("/tmp/intr_log", "w+"); #endif - sleep(INTR_STORM_MONITOR_PERIOD); + sleep(intr_monitor_setting.probe_period); /* first to get interrupt data */ hdr->cmd = INTR_CMD_GET_DATA; @@ -98,9 +110,8 @@ static void *intr_storm_monitor_thread(void *arg) #ifdef INTR_MONITOR_DBG write_intr_data_to_file(hdr); #endif - memcpy(intr_cnt_buf, hdr->buffer, - sizeof(uint64_t) * hdr->buf_cnt); - sleep(INTR_STORM_MONITOR_PERIOD); + memcpy(intr_cnt_buf, hdr->buffer, sizeof(uint64_t) * hdr->buf_cnt); + sleep(intr_monitor_setting.probe_period); /* next time to get interrupt data */ memset(hdr->buffer, 0, sizeof(uint64_t) * hdr->buf_cnt); @@ -126,7 +137,7 @@ static void *intr_storm_monitor_thread(void *arg) continue; delta = hdr->buffer[i + 1] - intr_cnt_buf[i + 1]; - if (delta > INTR_STORM_THRESHOLD) { + if (delta > intr_monitor_setting.threshold) { #ifdef INTR_MONITOR_DBG write_intr_data_to_file(hdr); #endif @@ -139,17 +150,16 @@ static void *intr_storm_monitor_thread(void *arg) DPRINTF("irq=%ld, delta=%ld\n", intr_cnt_buf[i], delta); hdr->cmd = INTR_CMD_DELAY_INT; - hdr->buffer[0] = DELAY_INTR_TIME; + hdr->buffer[0] = intr_monitor_setting.delay_time; vm_intr_monitor(ctx, hdr); - usleep(DELAY_DURATION); /* sleep-delay intr */ + usleep(intr_monitor_setting.delay_duration); /* sleep-delay intr */ hdr->buffer[0] = 0; /* cancel to delay intr */ vm_intr_monitor(ctx, hdr); sleep(TIME_TO_CHECK_AGAIN); /* time to get data again */ hdr->cmd = INTR_CMD_GET_DATA; hdr->buf_cnt = MAX_PTDEV_NUM * 2; - memset(hdr->buffer, 0, - sizeof(uint64_t) * hdr->buf_cnt); + memset(hdr->buffer, 0, sizeof(uint64_t) * hdr->buf_cnt); vm_intr_monitor(ctx, hdr); } } @@ -159,14 +169,15 @@ static void *intr_storm_monitor_thread(void *arg) static void start_intr_storm_monitor(struct vmctx *ctx) { - int ret = pthread_create(&intr_storm_monitor_pid, NULL, - intr_storm_monitor_thread, ctx); - if (ret) { - printf("failed %s %d\n", __func__, __LINE__); - intr_storm_monitor_pid = 0; - } + if (intr_monitor_setting.enable) { + int ret = pthread_create(&intr_storm_monitor_pid, NULL, intr_storm_monitor_thread, ctx); + if (ret) { + printf("failed %s %d\n", __func__, __LINE__); + intr_storm_monitor_pid = 0; + } - printf("start monitor interrupt data...\n"); + printf("start monitor interrupt data...\n"); + } } static void stop_intr_storm_monitor(void) @@ -177,6 +188,40 @@ static void stop_intr_storm_monitor(void) } } +/* +.* interrupt monitor setting params, current interrupt mitigation will delay UOS's +.* pass-through devices' interrupt injection, the settings input from acrn-dm: +.* params: +.* threshold: each intr count/second when intr storm happens; +.* probe_period: seconds -- the period to probe intr data; +.* delay_time: ms -- the time to delay each intr injection; + * delay_duration; us -- the delay duration, after it, intr injection restore to normal +.*/ +int acrn_parse_intr_monitor(const char *opt) +{ + uint32_t threshold, period, delay, duration; + char *cp; + + if((!dm_strtoui(opt, &cp, 10, &threshold) && *cp == ',') && + (!dm_strtoui(cp + 1, &cp, 10, &period) && *cp == ',') && + (!dm_strtoui(cp + 1, &cp, 10, &delay) && *cp == ',') && + (!dm_strtoui(cp + 1, &cp, 10, &duration))) { + printf("interrupt storm monitor params: %d, %d, %d, %d\n", threshold, period, delay, duration); + } else { + printf("%s: not correct, it should be like: --intr_monitor 10000,10,1,100, please check!\n", opt); + return -1; + } + + intr_monitor_setting.enable = true; + intr_monitor_setting.threshold = threshold * period; + intr_monitor_setting.probe_period = period; + intr_monitor_setting.delay_time = delay; + intr_monitor_setting.delay_duration = duration * 1000; + + return 0; +} + + /* helpers */ /* Check if @path is a directory, and create if not exist */ static int check_dir(const char *path) diff --git a/devicemodel/include/monitor.h b/devicemodel/include/monitor.h index 5397f4532..0ba78f888 100644 --- a/devicemodel/include/monitor.h +++ b/devicemodel/include/monitor.h @@ -33,4 +33,5 @@ int monitor_register_vm_ops(struct monitor_vm_ops *ops, void *arg, /* helper functions for vm_ops callback developer */ unsigned get_wakeup_reason(void); int set_wakeup_timer(time_t t); +int acrn_parse_intr_monitor(const char *opt); #endif