From e5b83ac140634830b8f8d9ca8d40a1d9d16d2d5b Mon Sep 17 00:00:00 2001 From: hejingxian Date: Tue, 12 Nov 2019 15:29:16 +0800 Subject: [PATCH] feature: introduce affinity hint verify to detect user hint variation In order to make the user affinity hint becomes effective quickly, introduce the periodically affinity hint verify. --- Makefile.am | 2 +- activate.c | 14 ++++-- classify.c | 5 ++- cpumask.h | 7 +++ hint_verify.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ hint_verify.h | 21 ++++++++ irqbalance.c | 43 ++++++++++----- irqbalance.h | 5 ++ placement.c | 14 ++++++ types.h | 1 + 10 files changed, 228 insertions(+), 20 deletions(-) create mode 100644 hint_verify.c create mode 100644 hint_verify.h diff --git a/Makefile.am b/Makefile.am index 3086d67..aacb399 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,7 +38,7 @@ sbin_PROGRAMS += irqbalance-ui endif irqbalance_SOURCES = activate.c bitmap.c classify.c cputree.c irqbalance.c \ - irqlist.c numa.c placement.c procinterrupts.c rules_config.c + irqlist.c numa.c placement.c procinterrupts.c rules_config.c hint_verify.c irqbalance_LDADD = $(LIBCAP_NG_LIBS) $(GLIB2_LIBS) $(NUMA_LIBS) if IRQBALANCEUI irqbalance_ui_SOURCES = $(UI_DIR)/helpers.c $(UI_DIR)/irqbalance-ui.c \ diff --git a/activate.c b/activate.c index 93fde58..c5859bf 100644 --- a/activate.c +++ b/activate.c @@ -78,11 +78,6 @@ static void activate_mapping(struct irq_info *info, void *data __attribute__((un int ret = 0; cpumask_t applied_mask; - /* - * only activate mappings for irqs that have moved - */ - if (!info->moved) - return; if (!info->assigned_obj) return; @@ -90,6 +85,15 @@ static void activate_mapping(struct irq_info *info, void *data __attribute__((un /* activate only online cpus, otherwise writing to procfs returns EOVERFLOW */ cpus_and(applied_mask, cpu_online_map, info->assigned_obj->mask); + if (hint_enabled) { + if (!cpus_empty(info->affinity_hint)) { + cpus_and(applied_mask, applied_mask, info->affinity_hint); + if (!cpus_intersects(applied_mask, unbanned_cpus)) { + return; + } + } + } + /* * Don't activate anything for which we have an invalid mask */ diff --git a/classify.c b/classify.c index 254197e..e9987ee 100644 --- a/classify.c +++ b/classify.c @@ -263,7 +263,7 @@ static int get_irq_class(const char *devpath) return irq_class; } -static gint compare_ints(gconstpointer a, gconstpointer b) +gint compare_ints(gconstpointer a, gconstpointer b) { const struct irq_info *ai = a; const struct irq_info *bi = b; @@ -397,6 +397,9 @@ get_numa_node: process_one_line(path, get_mask_from_bitmap, &new->cpumask); } + sprintf(path, "/proc/irq/%d/affinity_hint", irq); + process_one_line(path, get_mask_from_bitmap, &new->affinity_hint); + log(TO_CONSOLE, LOG_INFO, "Adding IRQ %d to database\n", irq); return new; } diff --git a/cpumask.h b/cpumask.h index 5bebbeb..bc5f006 100644 --- a/cpumask.h +++ b/cpumask.h @@ -30,6 +30,7 @@ * void cpus_xor(dst, src1, src2) dst = src1 ^ src2 * void cpus_andnot(dst, src1, src2) dst = src1 & ~src2 * void cpus_complement(dst, src) dst = ~src + * void cpumask_copy(dst, src) dst = src * * int cpus_equal(mask1, mask2) Does mask1 == mask2? * int cpus_intersects(mask1, mask2) Do mask1 and mask2 intersect? @@ -142,6 +143,12 @@ static inline void __cpus_complement(cpumask_t *dstp, bitmap_complement(dstp->bits, srcp->bits, nbits); } +#define cpumask_copy(dst, src) __cpumask_copy(&(dst), &(src), NR_CPUS) +static inline void __cpumask_copy(cpumask_t *dstp, const cpumask_t *srcp, int nbits) +{ + bitmap_copy(dstp->bits, srcp->bits, nbits); +} + #define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS) static inline int __cpus_equal(const cpumask_t *src1p, const cpumask_t *src2p, int nbits) diff --git a/hint_verify.c b/hint_verify.c new file mode 100644 index 0000000..3492902 --- /dev/null +++ b/hint_verify.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved. + * + * This program file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include +#include +#include "irqbalance.h" + +extern int keep_going; +extern GMainLoop *main_loop; +extern gboolean scan(); +extern int last_interval; + +int real_sleep_interval; +int sleep_interval_count; +int poll_hint_interval_count; +int sleep_count = 0; +gboolean hint_has_changed = FALSE; + +int hint_changed(void) +{ + FILE *file; + char *line = NULL; + size_t size = 0; + gboolean changed = FALSE; + + file = fopen("/proc/irq/affinity_hint_notify", "r+"); + if (!file) + return changed; + + if (getline(&line, &size, file) > 0 && *line != '0') { + fprintf(file, "Done"); + changed = TRUE; + } + + fclose(file); + if (line) + free(line); + return changed; +} + +void update_affinity_hint(struct irq_info *info, void *data __attribute__((unused))) +{ + cpumask_t current_affinity_hint; + char path[PATH_MAX]; + + if (!hint_enabled) + return; + + cpus_clear(info->affinity_hint); + sprintf(path, "/proc/irq/%d/affinity_hint", info->irq); + process_one_line(path, get_mask_from_bitmap, ¤t_affinity_hint); + + if (!cpus_equal(current_affinity_hint, info->affinity_hint)) { + cpumask_copy(info->affinity_hint, current_affinity_hint); + force_rebalance_irq(info, data); + hint_has_changed = TRUE; + cpumask_scnprintf(path, PATH_MAX, current_affinity_hint); + log(TO_ALL, LOG_INFO, "IRQ(%d): affinity hint modified %s\n", info->irq, path); + } +} + +/* + * This function is the main loop of irqbalance, which include: + * 1. scan opration for irq balancing; + * 2. poll irq affinity hint changes for quickly applying them. + */ +gboolean poll_hint_affinity_and_scan(gpointer data __attribute__((unused))) +{ + gboolean need_verify_flag = FALSE; + gboolean need_scan_flag = FALSE; + + if (!sleep_interval_count) + sleep_interval_count = 1; + if (!poll_hint_interval_count) + poll_hint_interval_count = 1; + + if (sleep_count % sleep_interval_count == 0) { + need_scan_flag = TRUE; + } + if (sleep_count % poll_hint_interval_count == 0) { + need_verify_flag = TRUE; + } + sleep_count++; + + if (need_verify_flag && hint_changed()) { + for_each_irq(NULL, update_affinity_hint, NULL); + if (hint_has_changed) { + hint_has_changed = FALSE; + sleep_count = 1; + need_scan_flag = TRUE; + } + } + + if (need_scan_flag) { + if (!scan()) { + g_main_loop_quit(main_loop); + return FALSE; + } + } + + update_interval_and_count(); + if (last_interval != real_sleep_interval) { + last_interval = real_sleep_interval; + g_timeout_add_seconds(real_sleep_interval, poll_hint_affinity_and_scan, NULL); + return FALSE; + } + + if (keep_going) { + return TRUE; + } else { + g_main_loop_quit(main_loop); + return FALSE; + } +} + +void update_interval_and_count() +{ + real_sleep_interval = + sleep_interval > poll_hint_interval ? poll_hint_interval : sleep_interval; + if (!real_sleep_interval) { + sleep_interval_count = 1; + poll_hint_interval_count = 1; + return; + } + sleep_interval_count = sleep_interval / real_sleep_interval; + poll_hint_interval_count = poll_hint_interval / real_sleep_interval; +} diff --git a/hint_verify.h b/hint_verify.h new file mode 100644 index 0000000..7391b32 --- /dev/null +++ b/hint_verify.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved. + * + * This program file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef _INCLUDE_HINT_VERIFY_H +#define _INCLUDE_HINT_VERIFY_H + +extern int real_sleep_interval; +extern gboolean poll_hint_affinity_and_scan(); +extern void update_interval_and_count(); + +#endif diff --git a/irqbalance.c b/irqbalance.c index 450a1ff..5985d8d 100644 --- a/irqbalance.c +++ b/irqbalance.c @@ -64,6 +64,8 @@ char *polscript = NULL; long HZ; int sleep_interval = SLEEP_INTERVAL; int last_interval; +int hint_enabled = 0; +int poll_hint_interval = SLEEP_INTERVAL / 5; GMainLoop *main_loop; char *cpu_ban_string = NULL; @@ -100,6 +102,8 @@ struct option lopts[] = { {"version", 0, NULL, 'V'}, {"migrateval", 1, NULL, 'e'}, {"rulesconfig", 1, NULL, 'r'}, + {"hintpolicy", 1, NULL, 'h'}, + {"verifyhint", 1, NULL, 'v'}, {0, 0, 0, 0} }; @@ -108,7 +112,7 @@ static void usage(void) log(TO_CONSOLE, LOG_INFO, "irqbalance [--oneshot | -o] [--debug | -d] [--foreground | -f] [--journal | -j]\n"); log(TO_CONSOLE, LOG_INFO, " [--powerthresh= | -p | ] [--banirq= | -i ] [--banmod= | -m ] [--policyscript= | -l