mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-07 04:19:10 +00:00
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:
parent
1902d725a0
commit
ad1cbb7623
@ -157,7 +157,9 @@ usage(int code)
|
|||||||
" --part_info: guest partition info file path\n"
|
" --part_info: guest partition info file path\n"
|
||||||
" --enable_trusty: enable trusty for guest\n"
|
" --enable_trusty: enable trusty for guest\n"
|
||||||
" --ptdev_no_reset: disable reset check for ptdev\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), "",
|
progname, (int)strlen(progname), "", (int)strlen(progname), "",
|
||||||
(int)strlen(progname), "");
|
(int)strlen(progname), "");
|
||||||
|
|
||||||
@ -701,6 +703,7 @@ enum {
|
|||||||
CMD_OPT_DEBUGEXIT,
|
CMD_OPT_DEBUGEXIT,
|
||||||
CMD_OPT_VMCFG,
|
CMD_OPT_VMCFG,
|
||||||
CMD_OPT_DUMP,
|
CMD_OPT_DUMP,
|
||||||
|
CMD_OPT_INTR_MONITOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
@ -734,6 +737,7 @@ static struct option long_options[] = {
|
|||||||
{"ptdev_no_reset", no_argument, 0,
|
{"ptdev_no_reset", no_argument, 0,
|
||||||
CMD_OPT_PTDEV_NO_RESET},
|
CMD_OPT_PTDEV_NO_RESET},
|
||||||
{"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT},
|
{"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT},
|
||||||
|
{"intr_monitor", required_argument, 0, CMD_OPT_INTR_MONITOR},
|
||||||
{0, 0, 0, 0 },
|
{0, 0, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -859,6 +863,12 @@ dm_run(int argc, char *argv[])
|
|||||||
case CMD_OPT_DEBUGEXIT:
|
case CMD_OPT_DEBUGEXIT:
|
||||||
debugexit_enabled = true;
|
debugexit_enabled = true;
|
||||||
break;
|
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':
|
case 'h':
|
||||||
usage(0);
|
usage(0);
|
||||||
default:
|
default:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "dm.h"
|
#include "dm.h"
|
||||||
|
#include "dm_string.h"
|
||||||
#include "monitor.h"
|
#include "monitor.h"
|
||||||
#include "acrn_mngr.h"
|
#include "acrn_mngr.h"
|
||||||
#include "pm.h"
|
#include "pm.h"
|
||||||
@ -30,6 +31,14 @@
|
|||||||
#define DELAY_DURATION 100000 /* 100ms of total duration for delay intr */
|
#define DELAY_DURATION 100000 /* 100ms of total duration for delay intr */
|
||||||
#define TIME_TO_CHECK_AGAIN 2 /* 2seconds */
|
#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 {
|
union intr_monitor_t {
|
||||||
struct acrn_intr_monitor monitor;
|
struct acrn_intr_monitor monitor;
|
||||||
char reserved[4096];
|
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 uint64_t intr_cnt_buf[MAX_PTDEV_NUM * 2];
|
||||||
static pthread_t intr_storm_monitor_pid;
|
static pthread_t intr_storm_monitor_pid;
|
||||||
|
|
||||||
|
static struct intr_monitor_setting_t intr_monitor_setting = {
|
||||||
|
.enable = false,
|
||||||
|
};
|
||||||
|
|
||||||
/* switch macro, just open in debug */
|
/* switch macro, just open in debug */
|
||||||
/* #define INTR_MONITOR_DBG */
|
/* #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) {
|
for (j = 0; j < hdr->buf_cnt; j += 2) {
|
||||||
if (hdr->buffer[j + 1] != 0) {
|
if (hdr->buffer[j + 1] != 0) {
|
||||||
fprintf(dbg_file, "%ld\t\t%ld\n", hdr->buffer[j],
|
fprintf(dbg_file, "%ld\t\t%ld\n", hdr->buffer[j], hdr->buffer[j + 1]);
|
||||||
hdr->buffer[j + 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +92,7 @@ static void *intr_storm_monitor_thread(void *arg)
|
|||||||
#ifdef INTR_MONITOR_DBG
|
#ifdef INTR_MONITOR_DBG
|
||||||
dbg_file = fopen("/tmp/intr_log", "w+");
|
dbg_file = fopen("/tmp/intr_log", "w+");
|
||||||
#endif
|
#endif
|
||||||
sleep(INTR_STORM_MONITOR_PERIOD);
|
sleep(intr_monitor_setting.probe_period);
|
||||||
|
|
||||||
/* first to get interrupt data */
|
/* first to get interrupt data */
|
||||||
hdr->cmd = INTR_CMD_GET_DATA;
|
hdr->cmd = INTR_CMD_GET_DATA;
|
||||||
@ -98,9 +110,8 @@ static void *intr_storm_monitor_thread(void *arg)
|
|||||||
#ifdef INTR_MONITOR_DBG
|
#ifdef INTR_MONITOR_DBG
|
||||||
write_intr_data_to_file(hdr);
|
write_intr_data_to_file(hdr);
|
||||||
#endif
|
#endif
|
||||||
memcpy(intr_cnt_buf, hdr->buffer,
|
memcpy(intr_cnt_buf, hdr->buffer, sizeof(uint64_t) * hdr->buf_cnt);
|
||||||
sizeof(uint64_t) * hdr->buf_cnt);
|
sleep(intr_monitor_setting.probe_period);
|
||||||
sleep(INTR_STORM_MONITOR_PERIOD);
|
|
||||||
|
|
||||||
/* next time to get interrupt data */
|
/* next time to get interrupt data */
|
||||||
memset(hdr->buffer, 0, sizeof(uint64_t) * hdr->buf_cnt);
|
memset(hdr->buffer, 0, sizeof(uint64_t) * hdr->buf_cnt);
|
||||||
@ -126,7 +137,7 @@ static void *intr_storm_monitor_thread(void *arg)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
delta = hdr->buffer[i + 1] - intr_cnt_buf[i + 1];
|
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
|
#ifdef INTR_MONITOR_DBG
|
||||||
write_intr_data_to_file(hdr);
|
write_intr_data_to_file(hdr);
|
||||||
#endif
|
#endif
|
||||||
@ -139,17 +150,16 @@ static void *intr_storm_monitor_thread(void *arg)
|
|||||||
DPRINTF("irq=%ld, delta=%ld\n", intr_cnt_buf[i], delta);
|
DPRINTF("irq=%ld, delta=%ld\n", intr_cnt_buf[i], delta);
|
||||||
|
|
||||||
hdr->cmd = INTR_CMD_DELAY_INT;
|
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);
|
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 */
|
hdr->buffer[0] = 0; /* cancel to delay intr */
|
||||||
vm_intr_monitor(ctx, hdr);
|
vm_intr_monitor(ctx, hdr);
|
||||||
|
|
||||||
sleep(TIME_TO_CHECK_AGAIN); /* time to get data again */
|
sleep(TIME_TO_CHECK_AGAIN); /* time to get data again */
|
||||||
hdr->cmd = INTR_CMD_GET_DATA;
|
hdr->cmd = INTR_CMD_GET_DATA;
|
||||||
hdr->buf_cnt = MAX_PTDEV_NUM * 2;
|
hdr->buf_cnt = MAX_PTDEV_NUM * 2;
|
||||||
memset(hdr->buffer, 0,
|
memset(hdr->buffer, 0, sizeof(uint64_t) * hdr->buf_cnt);
|
||||||
sizeof(uint64_t) * hdr->buf_cnt);
|
|
||||||
vm_intr_monitor(ctx, hdr);
|
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)
|
static void start_intr_storm_monitor(struct vmctx *ctx)
|
||||||
{
|
{
|
||||||
int ret = pthread_create(&intr_storm_monitor_pid, NULL,
|
if (intr_monitor_setting.enable) {
|
||||||
intr_storm_monitor_thread, ctx);
|
int ret = pthread_create(&intr_storm_monitor_pid, NULL, intr_storm_monitor_thread, ctx);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("failed %s %d\n", __func__, __LINE__);
|
printf("failed %s %d\n", __func__, __LINE__);
|
||||||
intr_storm_monitor_pid = 0;
|
intr_storm_monitor_pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("start monitor interrupt data...\n");
|
printf("start monitor interrupt data...\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_intr_storm_monitor(void)
|
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 */
|
/* helpers */
|
||||||
/* Check if @path is a directory, and create if not exist */
|
/* Check if @path is a directory, and create if not exist */
|
||||||
static int check_dir(const char *path)
|
static int check_dir(const char *path)
|
||||||
|
@ -33,4 +33,5 @@ int monitor_register_vm_ops(struct monitor_vm_ops *ops, void *arg,
|
|||||||
/* helper functions for vm_ops callback developer */
|
/* helper functions for vm_ops callback developer */
|
||||||
unsigned get_wakeup_reason(void);
|
unsigned get_wakeup_reason(void);
|
||||||
int set_wakeup_timer(time_t t);
|
int set_wakeup_timer(time_t t);
|
||||||
|
int acrn_parse_intr_monitor(const char *opt);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user