353 lines
9.0 KiB
Diff
353 lines
9.0 KiB
Diff
|
|
From 0ba4a60a2a732150e5016389e32b2e81906a72c2 Mon Sep 17 00:00:00 2001
|
||
|
|
From: hejingxian 00273181 <hejingxian@huawei.com>
|
||
|
|
Date: Fri, 4 Dec 2020 10:52:57 +0800
|
||
|
|
Subject: [PATCH] add irq hotplug feature for irqbalance
|
||
|
|
|
||
|
|
Conflict:NA
|
||
|
|
Reference:https://github.com/Irqbalance/irqbalance/commit/0ba4a60a2a732150e5016389e32b2e81906a72c2
|
||
|
|
---
|
||
|
|
classify.c | 70 +++++++++++++++++++++++--------
|
||
|
|
irqbalance.c | 2 +-
|
||
|
|
irqbalance.h | 4 +-
|
||
|
|
procinterrupts.c | 104 ++++++++++++++++++++++++++++-------------------
|
||
|
|
4 files changed, 120 insertions(+), 60 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/classify.c b/classify.c
|
||
|
|
index 9f588bc..0d556e9 100644
|
||
|
|
--- a/classify.c
|
||
|
|
+++ b/classify.c
|
||
|
|
@@ -619,7 +619,7 @@ static void add_new_irq(char *path, struct irq_info *hint, GList *proc_interrupt
|
||
|
|
/*
|
||
|
|
* Figures out which interrupt(s) relate to the device we"re looking at in dirname
|
||
|
|
*/
|
||
|
|
-static void build_one_dev_entry(const char *dirname, GList *tmp_irqs)
|
||
|
|
+static void build_one_dev_entry(const char *dirname, GList *tmp_irqs, int build_irq)
|
||
|
|
{
|
||
|
|
struct dirent *entry;
|
||
|
|
DIR *msidir;
|
||
|
|
@@ -642,10 +642,14 @@ static void build_one_dev_entry(const char *dirname, GList *tmp_irqs)
|
||
|
|
if (!entry)
|
||
|
|
break;
|
||
|
|
irqnum = strtol(entry->d_name, NULL, 10);
|
||
|
|
- if (irqnum) {
|
||
|
|
+ /* If build_irq is valid, only add irq when it's number equals to build_irq */
|
||
|
|
+ if (irqnum && ((build_irq < 0) || (irqnum == build_irq))) {
|
||
|
|
+ printf("add irq:%d %d for %s\n", irqnum, build_irq, path);
|
||
|
|
hint.irq = irqnum;
|
||
|
|
hint.type = IRQ_TYPE_MSIX;
|
||
|
|
add_new_irq(devpath, &hint, tmp_irqs);
|
||
|
|
+ if (build_irq >= 0)
|
||
|
|
+ break;
|
||
|
|
}
|
||
|
|
} while (entry != NULL);
|
||
|
|
closedir(msidir);
|
||
|
|
@@ -665,9 +669,12 @@ static void build_one_dev_entry(const char *dirname, GList *tmp_irqs)
|
||
|
|
#else
|
||
|
|
if (irqnum) {
|
||
|
|
#endif
|
||
|
|
- hint.irq = irqnum;
|
||
|
|
- hint.type = IRQ_TYPE_LEGACY;
|
||
|
|
- add_new_irq(devpath, &hint, tmp_irqs);
|
||
|
|
+ /* If build_irq is valid, only add irq when it's number equals to build_irq */
|
||
|
|
+ if ((build_irq < 0) || (irqnum == build_irq)) {
|
||
|
|
+ hint.irq = irqnum;
|
||
|
|
+ hint.type = IRQ_TYPE_LEGACY;
|
||
|
|
+ add_new_irq(devpath, &hint, tmp_irqs);
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
done:
|
||
|
|
@@ -712,31 +719,60 @@ static void free_tmp_irqs(gpointer data)
|
||
|
|
free(info);
|
||
|
|
}
|
||
|
|
|
||
|
|
-void rebuild_irq_db(void)
|
||
|
|
+static struct irq_info * build_dev_irqs(GList *tmp_irqs, int build_irq)
|
||
|
|
{
|
||
|
|
DIR *devdir;
|
||
|
|
struct dirent *entry;
|
||
|
|
- GList *tmp_irqs = NULL;
|
||
|
|
-
|
||
|
|
- free_irq_db();
|
||
|
|
-
|
||
|
|
- tmp_irqs = collect_full_irq_list();
|
||
|
|
+ struct irq_info *new_irq = NULL;
|
||
|
|
|
||
|
|
devdir = opendir(SYSPCI_DIR);
|
||
|
|
-
|
||
|
|
if (devdir) {
|
||
|
|
do {
|
||
|
|
entry = readdir(devdir);
|
||
|
|
-
|
||
|
|
if (!entry)
|
||
|
|
break;
|
||
|
|
-
|
||
|
|
- build_one_dev_entry(entry->d_name, tmp_irqs);
|
||
|
|
-
|
||
|
|
+ /* when hotplug irqs, we add one irq at one time */
|
||
|
|
+ build_one_dev_entry(entry->d_name, tmp_irqs, build_irq);
|
||
|
|
+ if (build_irq >= 0) {
|
||
|
|
+ new_irq = get_irq_info(build_irq);
|
||
|
|
+ if (new_irq)
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
} while (entry != NULL);
|
||
|
|
-
|
||
|
|
closedir(devdir);
|
||
|
|
}
|
||
|
|
+ return new_irq;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int proc_irq_hotplug(char *savedline, int irq, struct irq_info **pinfo)
|
||
|
|
+{
|
||
|
|
+ struct irq_info tmp_info = {0};
|
||
|
|
+
|
||
|
|
+ /* firstly, init irq info by read device info */
|
||
|
|
+ *pinfo = build_dev_irqs(interrupts_db, irq);
|
||
|
|
+ if (*pinfo == NULL) {
|
||
|
|
+ /* secondly, init irq info by parse savedline */
|
||
|
|
+ init_irq_class_and_type(savedline, &tmp_info, irq);
|
||
|
|
+ add_new_irq(NULL, &tmp_info, interrupts_db);
|
||
|
|
+ *pinfo = get_irq_info(irq);
|
||
|
|
+ }
|
||
|
|
+ if (*pinfo == NULL) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ force_rebalance_irq(*pinfo, NULL);
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void rebuild_irq_db(void)
|
||
|
|
+{
|
||
|
|
+ GList *tmp_irqs = NULL;
|
||
|
|
+
|
||
|
|
+ free_irq_db();
|
||
|
|
+
|
||
|
|
+ tmp_irqs = collect_full_irq_list();
|
||
|
|
+
|
||
|
|
+ build_dev_irqs(tmp_irqs, -1);
|
||
|
|
|
||
|
|
for_each_irq(tmp_irqs, add_missing_irq, interrupts_db);
|
||
|
|
|
||
|
|
diff --git a/irqbalance.c b/irqbalance.c
|
||
|
|
index eaa0ce1..9baa955 100644
|
||
|
|
--- a/irqbalance.c
|
||
|
|
+++ b/irqbalance.c
|
||
|
|
@@ -249,7 +249,7 @@ static void dump_object_tree(void)
|
||
|
|
for_each_object(numa_nodes, dump_numa_node_info, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
-static void force_rebalance_irq(struct irq_info *info, void *data __attribute__((unused)))
|
||
|
|
+void force_rebalance_irq(struct irq_info *info, void *data __attribute__((unused)))
|
||
|
|
{
|
||
|
|
if (info->level == BALANCE_NONE)
|
||
|
|
return;
|
||
|
|
diff --git a/irqbalance.h b/irqbalance.h
|
||
|
|
index acf0ed5..d8e80a9 100644
|
||
|
|
--- a/irqbalance.h
|
||
|
|
+++ b/irqbalance.h
|
||
|
|
@@ -40,8 +40,11 @@ extern GList* collect_full_irq_list();
|
||
|
|
extern void parse_proc_stat(void);
|
||
|
|
extern void set_interrupt_count(int number, uint64_t count);
|
||
|
|
extern void set_msi_interrupt_numa(int number);
|
||
|
|
+extern void init_irq_class_and_type(char *savedline, struct irq_info *info, int irq);
|
||
|
|
+extern int proc_irq_hotplug(char *line, int irq, struct irq_info **pinfo);
|
||
|
|
|
||
|
|
extern GList *rebalance_irq_list;
|
||
|
|
+extern void force_rebalance_irq(struct irq_info *info, void *data __attribute__((unused)));
|
||
|
|
|
||
|
|
void update_migration_status(void);
|
||
|
|
void dump_workloads(void);
|
||
|
|
@@ -52,7 +55,6 @@ void dump_tree(void);
|
||
|
|
void activate_mappings(void);
|
||
|
|
void clear_cpu_tree(void);
|
||
|
|
void free_cpu_topo(gpointer data);
|
||
|
|
-
|
||
|
|
/*===================NEW BALANCER FUNCTIONS============================*/
|
||
|
|
|
||
|
|
/*
|
||
|
|
diff --git a/procinterrupts.c b/procinterrupts.c
|
||
|
|
index 858b66b..0671be0 100644
|
||
|
|
--- a/procinterrupts.c
|
||
|
|
+++ b/procinterrupts.c
|
||
|
|
@@ -145,16 +145,59 @@ static void guess_arm_irq_hints(char *name, struct irq_info *info)
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
+void init_irq_class_and_type(char *savedline, struct irq_info *info, int irq)
|
||
|
|
+{
|
||
|
|
+ char *irq_name = NULL;
|
||
|
|
+ char *irq_mod = NULL;
|
||
|
|
+ char *savedptr = NULL;
|
||
|
|
+ char *last_token = NULL;
|
||
|
|
+ char *p = NULL;
|
||
|
|
+ int is_xen_dyn = 0;
|
||
|
|
+#ifdef AARCH64
|
||
|
|
+ char *tmp = NULL;
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+ irq_name = strtok_r(savedline, " ", &savedptr);
|
||
|
|
+ if (strstr(irq_name, "xen-dyn") != NULL)
|
||
|
|
+ is_xen_dyn = 1;
|
||
|
|
+ last_token = strtok_r(NULL, " ", &savedptr);
|
||
|
|
+ while ((p = strtok_r(NULL, " ", &savedptr))) {
|
||
|
|
+ irq_name = last_token;
|
||
|
|
+ if (strstr(irq_name, "xen-dyn") != NULL)
|
||
|
|
+ is_xen_dyn = 1;
|
||
|
|
+ last_token = p;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+#ifdef AARCH64
|
||
|
|
+ irq_name = last_token;
|
||
|
|
+ tmp = strchr(irq_name, '\n');
|
||
|
|
+ if (tmp)
|
||
|
|
+ *tmp = 0;
|
||
|
|
+#endif
|
||
|
|
+ irq_mod = last_token;
|
||
|
|
+ info->irq = irq;
|
||
|
|
+
|
||
|
|
+ if (strstr(irq_name, "-event") != NULL && is_xen_dyn == 1) {
|
||
|
|
+ info->type = IRQ_TYPE_VIRT_EVENT;
|
||
|
|
+ info->class = IRQ_VIRT_EVENT;
|
||
|
|
+ } else {
|
||
|
|
+#ifdef AARCH64
|
||
|
|
+ guess_arm_irq_hints(irq_name, info);
|
||
|
|
+#else
|
||
|
|
+ info->type = IRQ_TYPE_LEGACY;
|
||
|
|
+ info->class = IRQ_OTHER;
|
||
|
|
+#endif
|
||
|
|
+ }
|
||
|
|
+ info->numa_node = get_numa_node(0);
|
||
|
|
+ info->name = strdup(irq_mod);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
GList* collect_full_irq_list()
|
||
|
|
{
|
||
|
|
GList *tmp_list = NULL;
|
||
|
|
FILE *file;
|
||
|
|
char *line = NULL;
|
||
|
|
size_t size = 0;
|
||
|
|
- char *irq_name, *irq_mod, *savedptr, *last_token, *p;
|
||
|
|
-#ifdef AARCH64
|
||
|
|
- char *tmp;
|
||
|
|
-#endif
|
||
|
|
|
||
|
|
file = fopen("/proc/interrupts", "r");
|
||
|
|
if (!file)
|
||
|
|
@@ -169,7 +212,6 @@ GList* collect_full_irq_list()
|
||
|
|
|
||
|
|
while (!feof(file)) {
|
||
|
|
int number;
|
||
|
|
- int is_xen_dyn = 0;
|
||
|
|
struct irq_info *info;
|
||
|
|
char *c;
|
||
|
|
char *savedline = NULL;
|
||
|
|
@@ -191,44 +233,12 @@ GList* collect_full_irq_list()
|
||
|
|
savedline = strdup(line);
|
||
|
|
if (!savedline)
|
||
|
|
break;
|
||
|
|
- irq_name = strtok_r(savedline, " ", &savedptr);
|
||
|
|
- if (strstr(irq_name, "xen-dyn") != NULL)
|
||
|
|
- is_xen_dyn = 1;
|
||
|
|
- last_token = strtok_r(NULL, " ", &savedptr);
|
||
|
|
- while ((p = strtok_r(NULL, " ", &savedptr))) {
|
||
|
|
- irq_name = last_token;
|
||
|
|
- if (strstr(irq_name, "xen-dyn") != NULL)
|
||
|
|
- is_xen_dyn = 1;
|
||
|
|
- last_token = p;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
-#ifdef AARCH64
|
||
|
|
- /* Of course the formatting for /proc/interrupts is different on different arches */
|
||
|
|
- irq_name = last_token;
|
||
|
|
- tmp = strchr(irq_name, '\n');
|
||
|
|
- if (tmp)
|
||
|
|
- *tmp = 0;
|
||
|
|
-#endif
|
||
|
|
- irq_mod = last_token;
|
||
|
|
-
|
||
|
|
*c = 0;
|
||
|
|
number = strtoul(line, NULL, 10);
|
||
|
|
|
||
|
|
info = calloc(1, sizeof(struct irq_info));
|
||
|
|
if (info) {
|
||
|
|
- info->irq = number;
|
||
|
|
- if (strstr(irq_name, "-event") != NULL && is_xen_dyn == 1) {
|
||
|
|
- info->type = IRQ_TYPE_VIRT_EVENT;
|
||
|
|
- info->class = IRQ_VIRT_EVENT;
|
||
|
|
- } else {
|
||
|
|
-#ifdef AARCH64
|
||
|
|
- guess_arm_irq_hints(irq_name, info);
|
||
|
|
-#else
|
||
|
|
- info->type = IRQ_TYPE_LEGACY;
|
||
|
|
- info->class = IRQ_OTHER;
|
||
|
|
-#endif
|
||
|
|
- }
|
||
|
|
- info->name = strdup(irq_mod);
|
||
|
|
+ init_irq_class_and_type(savedline, info, number);
|
||
|
|
tmp_list = g_list_append(tmp_list, info);
|
||
|
|
}
|
||
|
|
free(savedline);
|
||
|
|
@@ -238,11 +248,13 @@ GList* collect_full_irq_list()
|
||
|
|
return tmp_list;
|
||
|
|
}
|
||
|
|
|
||
|
|
+
|
||
|
|
void parse_proc_interrupts(void)
|
||
|
|
{
|
||
|
|
FILE *file;
|
||
|
|
char *line = NULL;
|
||
|
|
size_t size = 0;
|
||
|
|
+ int ret;
|
||
|
|
|
||
|
|
file = fopen("/proc/interrupts", "r");
|
||
|
|
if (!file)
|
||
|
|
@@ -261,6 +273,7 @@ void parse_proc_interrupts(void)
|
||
|
|
uint64_t count;
|
||
|
|
char *c, *c2;
|
||
|
|
struct irq_info *info;
|
||
|
|
+ char *savedline = NULL;
|
||
|
|
|
||
|
|
if (getline(&line, &size, file)<=0)
|
||
|
|
break;
|
||
|
|
@@ -280,15 +293,24 @@ void parse_proc_interrupts(void)
|
||
|
|
if (!c)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
+ savedline = strdup(line);
|
||
|
|
+ if (!savedline)
|
||
|
|
+ break;
|
||
|
|
*c = 0;
|
||
|
|
c++;
|
||
|
|
number = strtoul(line, NULL, 10);
|
||
|
|
|
||
|
|
info = get_irq_info(number);
|
||
|
|
if (!info) {
|
||
|
|
- need_rescan = 1;
|
||
|
|
- break;
|
||
|
|
+ ret = proc_irq_hotplug(savedline, number, &info);
|
||
|
|
+ if (ret < 0) {
|
||
|
|
+ /* hotplug fail, need to rescan */
|
||
|
|
+ need_rescan = 1;
|
||
|
|
+ free(savedline);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
+ free(savedline);
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
cpunr = 0;
|
||
|
|
@@ -316,7 +338,7 @@ void parse_proc_interrupts(void)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
- info->last_irq_count = info->irq_count;
|
||
|
|
+ info->last_irq_count = info->irq_count;
|
||
|
|
info->irq_count = count;
|
||
|
|
|
||
|
|
/* is interrupt MSI based? */
|
||
|
|
--
|
||
|
|
2.23.0
|
||
|
|
|