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 <minggui.cao@intel.com>
Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
Minggui Cao 2018-10-29 14:24:54 +08:00 committed by lijinxia
parent 1902d725a0
commit ad1cbb7623
3 changed files with 75 additions and 19 deletions

View File

@ -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:

View File

@ -18,6 +18,7 @@
#include <unistd.h>
#include <pthread.h>
#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)

View File

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