diff --git a/utils/irqbalance/Makefile b/utils/irqbalance/Makefile new file mode 100644 index 0000000000..3777fde1ae --- /dev/null +++ b/utils/irqbalance/Makefile @@ -0,0 +1,52 @@ +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=irqbalance +PKG_VERSION:=1.2.0 +PKG_RELEASE:=2 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/Irqbalance/irqbalance.git +PKG_SOURCE_VERSION:=0e0dd4cfe5464de2f81eaef504eab7183f1fb030 +PKG_MIRROR_HASH:=c826e78babfc26f777a5791b2a6ea95b61453ba3e3c5803d4428cc803216bc5c +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_LICENSE:=GPLv2 + +PKG_MAINTAINER:=Hannu Nyman + +PKG_FIXUP:=autoreconf +PKG_REMOVE_FILES:=autogen.sh + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/irqbalance + SECTION:=utils + CATEGORY:=Utilities + TITLE:=IRQ usage balancing for multi-core systems + URL:=https://github.com/Irqbalance/irqbalance +endef + +define Package/irqbalance/description + The purpose of irqbalance is to distribute hardware interrupts across + processors/cores on a multiprocessor/multicore system in order to + increase performance. +endef + +CONFIGURE_ARGS+= \ + --disable-numa \ + --with-libcap_ng=no \ + --with-systemd=no \ + --without-glib2 + +define Package/irqbalance/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/irqbalance $(1)/usr/sbin/ +endef + +$(eval $(call BuildPackage,irqbalance)) diff --git a/utils/irqbalance/patches/100-disable-ui-compilation.patch b/utils/irqbalance/patches/100-disable-ui-compilation.patch new file mode 100644 index 0000000000..5793ec6914 --- /dev/null +++ b/utils/irqbalance/patches/100-disable-ui-compilation.patch @@ -0,0 +1,47 @@ +Revert upstream commit bf9297132d219539e07506c125c6801dd77202f4 +to prevent building the UI component. Also disable manpage. + +--- a/Makefile.am ++++ b/Makefile.am +@@ -24,19 +24,14 @@ AUTOMAKE_OPTIONS = no-dependencies + ACLOCAL_AMFLAGS = -I m4 + EXTRA_DIST = COPYING autogen.sh misc/irqbalance.service misc/irqbalance.env + +-UI_DIR = ui + AM_CFLAGS = $(LIBCAP_NG_CFLAGS) $(GLIB_CFLAGS) + AM_CPPFLAGS = -I${top_srcdir} -W -Wall -Wshadow -Wformat -Wundef -D_GNU_SOURCE + noinst_HEADERS = bitmap.h constants.h cpumask.h irqbalance.h non-atomic.h \ +- types.h $(UI_DIR)/helpers.h $(UI_DIR)/irqbalance-ui.h $(UI_DIR)/ui.h +-sbin_PROGRAMS = irqbalance irqbalance-ui ++ types.h ++sbin_PROGRAMS = irqbalance + irqbalance_SOURCES = activate.c bitmap.c classify.c cputree.c irqbalance.c \ + irqlist.c numa.c placement.c procinterrupts.c + irqbalance_LDADD = $(LIBCAP_NG_LIBS) $(GLIB_LIBS) +-irqbalance_ui_SOURCES = $(UI_DIR)/helpers.c $(UI_DIR)/irqbalance-ui.c \ +- $(UI_DIR)/ui.c +-irqbalance_ui_LDADD = $(GLIB_LIBS) $(CURSES_LIBS) +-dist_man_MANS = irqbalance.1 + + CONFIG_CLEAN_FILES = debug*.list config/* + clean-generic: +--- a/configure.ac ++++ b/configure.ac +@@ -3,7 +3,7 @@ AC_PREREQ(2.12)dnl + AM_CONFIG_HEADER(config.h) + + AC_CONFIG_MACRO_DIR([m4]) +-AM_INIT_AUTOMAKE([foreign] [subdir-objects]) ++AM_INIT_AUTOMAKE([foreign]) + AM_PROG_LIBTOOL + AC_SUBST(LIBTOOL_DEPS) + +@@ -26,8 +26,6 @@ AC_CHECK_FUNCS(getopt_long) + AC_CHECK_LIB(numa, numa_available) + AC_CHECK_LIB(m, floor) + +-AC_CHECK_LIB(curses, mvprintw) +- + AC_C_CONST + AC_C_INLINE + AM_PROG_CC_C_O diff --git a/utils/irqbalance/patches/200-avoid-glib.patch b/utils/irqbalance/patches/200-avoid-glib.patch new file mode 100644 index 0000000000..3c201966ef --- /dev/null +++ b/utils/irqbalance/patches/200-avoid-glib.patch @@ -0,0 +1,421 @@ +Revert upstream commit d1993bcde2a524346a9508754671f096ec129ad1 +to avoid glib dependency. That commit polluted the main code +with glib types. + +--- a/irqbalance.h ++++ b/irqbalance.h +@@ -8,7 +8,6 @@ + + #include + #include +-#include + #include + #include + +@@ -63,7 +62,6 @@ extern GList *packages; + extern GList *cache_domains; + extern GList *cpus; + extern int numa_avail; +-extern GList *cl_banned_irqs; + + extern int debug_mode; + extern int journal_logging; +@@ -171,7 +169,5 @@ extern unsigned int log_mask; + }while(0) + #endif /* HAVE_LIBSYSTEMD */ + +-#define SOCKET_PATH "irqbalance" +- + #endif /* __INCLUDE_GUARD_IRQBALANCE_H_ */ + +--- a/irqbalance.c ++++ b/irqbalance.c +@@ -31,8 +31,6 @@ + #include + #include + #include +-#include +-#include + #include + #ifdef HAVE_GETOPT_LONG + #include +@@ -44,7 +42,6 @@ + #include "irqbalance.h" + + volatile int keep_going = 1; +-int socket_fd; + int one_shot_mode; + int debug_mode; + int foreground_mode; +@@ -61,9 +58,6 @@ char *banscript = NULL; + char *polscript = NULL; + long HZ; + int sleep_interval = SLEEP_INTERVAL; +-GMainLoop *main_loop; +- +-char *banned_cpumask_from_ui = NULL; + + static void sleep_approx(int seconds) + { +@@ -236,224 +230,22 @@ static void force_rebalance_irq(struct i + info->assigned_obj = NULL; + } + +-gboolean handler(gpointer data __attribute__((unused))) ++static void handler(int signum) + { ++ (void)signum; + keep_going = 0; +- g_main_loop_quit(main_loop); +- return TRUE; + } + +-gboolean force_rescan(gpointer data __attribute__((unused))) ++static void force_rescan(int signum) + { ++ (void)signum; + if (cycle_count) + need_rescan = 1; +- return TRUE; +-} +- +-gboolean scan(gpointer data) +-{ +- log(TO_CONSOLE, LOG_INFO, "\n\n\n-----------------------------------------------------------------------------\n"); +- clear_work_stats(); +- parse_proc_interrupts(); +- parse_proc_stat(); +- +- +- /* cope with cpu hotplug -- detected during /proc/interrupts parsing */ +- if (need_rescan) { +- need_rescan = 0; +- cycle_count = 0; +- log(TO_CONSOLE, LOG_INFO, "Rescanning cpu topology \n"); +- clear_work_stats(); +- +- free_object_tree(); +- build_object_tree(); +- for_each_irq(NULL, force_rebalance_irq, NULL); +- parse_proc_interrupts(); +- parse_proc_stat(); +- sleep_approx(sleep_interval); +- clear_work_stats(); +- parse_proc_interrupts(); +- parse_proc_stat(); +- } +- +- if (cycle_count) +- update_migration_status(); +- +- calculate_placement(); +- activate_mappings(); +- +- if (debug_mode) +- dump_tree(); +- if (one_shot_mode) +- keep_going = 0; +- cycle_count++; +- +- if (data != &sleep_interval) { +- data = &sleep_interval; +- g_timeout_add_seconds(sleep_interval, scan, data); +- return FALSE; +- } +- +- if (keep_going) +- return TRUE; +- else +- return FALSE; +-} +- +-void get_irq_data(struct irq_info *irq, void *data) +-{ +- sprintf(data + strlen(data), +- "IRQ %d LOAD %lu DIFF %lu CLASS %d ", irq->irq, irq->load, +- (irq->irq_count - irq->last_irq_count), irq->class); +-} +- +-void get_object_stat(struct topo_obj *object, void *data) +-{ +- char irq_data[1024] = "\0"; +- +- if (g_list_length(object->interrupts) > 0) { +- for_each_irq(object->interrupts, get_irq_data, irq_data); +- } +- sprintf(data + strlen(data), "TYPE %d NUMBER %d LOAD %lu SAVE_MODE %d %s", +- object->obj_type, object->number, object->load, +- object->powersave_mode, irq_data); +- if (object->obj_type != OBJ_TYPE_CPU) { +- for_each_object(object->children, get_object_stat, data); +- } +-} +- +-gboolean sock_handle(gint fd, GIOCondition condition, gpointer user_data __attribute__((unused))) +-{ +- char buff[500]; +- int sock; +- int recv_size = 0; +- int valid_user = 0; +- +- struct iovec iov = { buff, 500 }; +- struct msghdr msg = { NULL, 0, &iov, 1, NULL, 0, 0 }; +- msg.msg_control = malloc(CMSG_SPACE(sizeof(struct ucred))); +- msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred)); +- +- struct cmsghdr *cmsg; +- +- if (condition == G_IO_IN) { +- sock = accept(fd, NULL, NULL); +- if (sock < 0) { +- log(TO_ALL, LOG_WARNING, "Connection couldn't be accepted.\n"); +- return TRUE; +- } +- if ((recv_size = recvmsg(sock, &msg, 0)) < 0) { +- log(TO_ALL, LOG_WARNING, "Error while receiving data.\n"); +- return TRUE; +- } +- cmsg = CMSG_FIRSTHDR(&msg); +- if ((cmsg->cmsg_level == SOL_SOCKET) && +- (cmsg->cmsg_type == SCM_CREDENTIALS)) { +- struct ucred *credentials = (struct ucred *) CMSG_DATA(cmsg); +- if (!credentials->uid) { +- valid_user = 1; +- } +- } +- if (!valid_user) { +- log(TO_ALL, LOG_INFO, "Permission denied for user to connect to socket.\n"); +- return TRUE; +- } +- +- if (!strncmp(buff, "stats", strlen("stats"))) { +- char stats[2048] = "\0"; +- for_each_object(numa_nodes, get_object_stat, stats); +- send(sock, stats, strlen(stats), 0); +- } +- if (!strncmp(buff, "settings ", strlen("settings "))) { +- if (!(strncmp(buff + strlen("settings "), "sleep ", +- strlen("sleep ")))) { +- char *sleep_string = malloc( +- sizeof(char) * (recv_size - strlen("settings sleep "))); +- strncpy(sleep_string, buff + strlen("settings sleep "), +- recv_size - strlen("settings sleep ")); +- int new_iterval = strtoul(sleep_string, NULL, 10); +- if (new_iterval >= 1) { +- sleep_interval = new_iterval; +- } +- } else if (!(strncmp(buff + strlen("settings "), "ban irqs ", +- strlen("ban irqs ")))) { +- char *end; +- char *irq_string = malloc( +- sizeof(char) * (recv_size - strlen("settings ban irqs "))); +- strncpy(irq_string, buff + strlen("settings ban irqs "), +- recv_size - strlen("settings ban irqs ")); +- g_list_free_full(cl_banned_irqs, free); +- cl_banned_irqs = NULL; +- need_rescan = 1; +- if (!strncmp(irq_string, "NONE", strlen("NONE"))) { +- return TRUE; +- } +- int irq = strtoul(irq_string, &end, 10); +- do { +- add_cl_banned_irq(irq); +- } while((irq = strtoul(end, &end, 10))); +- } else if (!(strncmp(buff + strlen("settings "), "cpus ", +- strlen("cpus")))) { +- char *cpu_ban_string = malloc( +- sizeof(char) * (recv_size - strlen("settings cpus "))); +- strncpy(cpu_ban_string, buff + strlen("settings cpus "), +- recv_size - strlen("settings cpus ")); +- banned_cpumask_from_ui = strtok(cpu_ban_string, " "); +- if (!strncmp(banned_cpumask_from_ui, "NULL", strlen("NULL"))) { +- banned_cpumask_from_ui = NULL; +- } +- need_rescan = 1; +- } +- } +- if (!strncmp(buff, "setup", strlen("setup"))) { +- char setup[2048] = "\0"; +- snprintf(setup, 2048, "SLEEP %d ", sleep_interval); +- if(g_list_length(cl_banned_irqs) > 0) { +- for_each_irq(cl_banned_irqs, get_irq_data, setup); +- } +- char banned[512]; +- cpumask_scnprintf(banned, 512, banned_cpus); +- snprintf(setup + strlen(setup), 2048 - strlen(setup), +- "BANNED %s", banned); +- send(sock, setup, strlen(setup), 0); +- } +- +- close(sock); +- } +- return TRUE; +-} +- +-int init_socket(char *socket_name) +-{ +- struct sockaddr_un addr; +- memset(&addr, 0, sizeof(struct sockaddr_un)); +- +- socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0); +- if (socket_fd < 0) { +- log(TO_ALL, LOG_WARNING, "Socket couldn't be created.\n"); +- return 1; +- } +- +- addr.sun_family = AF_UNIX; +- addr.sun_path[0] = '\0'; +- strncpy(addr.sun_path + 1, socket_name, strlen(socket_name)); +- if (bind(socket_fd, (struct sockaddr *)&addr, +- sizeof(sa_family_t) + strlen(socket_name) + 1) < 0) { +- log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the socket.\n"); +- return 1; +- } +- int optval = 1; +- if (setsockopt(socket_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) { +- log(TO_ALL, LOG_WARNING, "Unable to set socket options.\n"); +- return 1; +- } +- listen(socket_fd, 1); +- g_unix_fd_add(socket_fd, G_IO_IN, sock_handle, NULL); +- return 0; + } + + int main(int argc, char** argv) + { ++ struct sigaction action, hupaction; + sigset_t sigset, old_sigset; + + sigemptyset(&sigset); +@@ -553,11 +345,19 @@ int main(int argc, char** argv) + } + } + +- g_unix_signal_add(SIGINT, handler, NULL); +- g_unix_signal_add(SIGTERM, handler, NULL); +- g_unix_signal_add(SIGUSR1, handler, NULL); +- g_unix_signal_add(SIGUSR2, handler, NULL); +- g_unix_signal_add(SIGHUP, force_rescan, NULL); ++ action.sa_handler = handler; ++ sigemptyset(&action.sa_mask); ++ action.sa_flags = 0; ++ sigaction(SIGINT, &action, NULL); ++ sigaction(SIGTERM, &action, NULL); ++ sigaction(SIGUSR1, &action, NULL); ++ sigaction(SIGUSR2, &action, NULL); ++ ++ hupaction.sa_handler = force_rescan; ++ sigemptyset(&hupaction.sa_mask); ++ hupaction.sa_flags = 0; ++ sigaction(SIGHUP, &hupaction, NULL); ++ + sigprocmask(SIG_SETMASK, &old_sigset, NULL); + + #ifdef HAVE_LIBCAP_NG +@@ -566,32 +366,58 @@ int main(int argc, char** argv) + capng_lock(); + capng_apply(CAPNG_SELECT_BOTH); + #endif ++ + for_each_irq(NULL, force_rebalance_irq, NULL); + + parse_proc_interrupts(); + parse_proc_stat(); + +- char socket_name[64]; +- snprintf(socket_name, 64, "%s%d.sock", SOCKET_PATH, getpid()); ++ while (keep_going) { ++ sleep_approx(sleep_interval); ++ log(TO_CONSOLE, LOG_INFO, "\n\n\n-----------------------------------------------------------------------------\n"); + +- if (init_socket(socket_name)) { +- return EXIT_FAILURE; +- } +- main_loop = g_main_loop_new(NULL, FALSE); +- int *last_interval = &sleep_interval; +- g_timeout_add_seconds(sleep_interval, scan, last_interval); +- g_main_loop_run(main_loop); + +- g_main_loop_quit(main_loop); ++ clear_work_stats(); ++ parse_proc_interrupts(); ++ parse_proc_stat(); ++ ++ /* cope with cpu hotplug -- detected during /proc/interrupts parsing */ ++ if (need_rescan) { ++ need_rescan = 0; ++ cycle_count = 0; ++ log(TO_CONSOLE, LOG_INFO, "Rescanning cpu topology \n"); ++ clear_work_stats(); ++ ++ free_object_tree(); ++ build_object_tree(); ++ for_each_irq(NULL, force_rebalance_irq, NULL); ++ parse_proc_interrupts(); ++ parse_proc_stat(); ++ sleep_approx(sleep_interval); ++ clear_work_stats(); ++ parse_proc_interrupts(); ++ parse_proc_stat(); ++ } ++ ++ if (cycle_count) ++ update_migration_status(); ++ ++ calculate_placement(); ++ activate_mappings(); + ++ if (debug_mode) ++ dump_tree(); ++ if (one_shot_mode) ++ keep_going = 0; ++ cycle_count++; ++ ++ } + free_object_tree(); + free_cl_opts(); + + /* Remove pidfile */ + if (!foreground_mode && pidfile) + unlink(pidfile); +- /* Remove socket */ +- close(socket_fd); + + return EXIT_SUCCESS; + } +--- a/cputree.c ++++ b/cputree.c +@@ -38,7 +38,6 @@ + + #include "irqbalance.h" + +-extern char *banned_cpumask_from_ui; + + GList *cpus; + GList *cache_domains; +@@ -77,15 +76,11 @@ static void setup_banned_cpus(void) + cpus_clear(nohz_full); + + /* A manually specified cpumask overrides auto-detection. */ +- if (banned_cpumask_from_ui != NULL) { +- cpulist_parse(banned_cpumask_from_ui, +- strlen(banned_cpumask_from_ui), banned_cpus); +- goto out; +- } + if (getenv("IRQBALANCE_BANNED_CPUS")) { + cpumask_parse_user(getenv("IRQBALANCE_BANNED_CPUS"), strlen(getenv("IRQBALANCE_BANNED_CPUS")), banned_cpus); + goto out; + } ++ + file = fopen("/sys/devices/system/cpu/isolated", "r"); + if (file) { + if (getline(&line, &size, file) > 0) { +@@ -117,8 +112,6 @@ out: + log(TO_CONSOLE, LOG_INFO, "Isolated CPUs: %s\n", buffer); + cpumask_scnprintf(buffer, 4096, nohz_full); + log(TO_CONSOLE, LOG_INFO, "Adaptive-ticks CPUs: %s\n", buffer); +- cpumask_scnprintf(buffer, 4096, banned_cpus); +- log(TO_CONSOLE, LOG_INFO, "Banned CPUs: %s\n", buffer); + } + + static struct topo_obj* add_cache_domain_to_package(struct topo_obj *cache,