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; + struct irq_info *new_irq = NULL; + + devdir = opendir(SYSPCI_DIR); + if (devdir) { + do { + entry = readdir(devdir); + if (!entry) + break; + /* 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(); - - devdir = opendir(SYSPCI_DIR); - - if (devdir) { - do { - entry = readdir(devdir); - - if (!entry) - break; - - build_one_dev_entry(entry->d_name, tmp_irqs); - - } while (entry != NULL); - - closedir(devdir); - } + + 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? */