irqbalance: backport package from master
authorHannu Nyman <hannu.nyman@iki.fi>
Thu, 27 Apr 2017 20:44:32 +0000 (23:44 +0300)
committerHannu Nyman <hannu.nyman@iki.fi>
Thu, 27 Apr 2017 20:57:56 +0000 (23:57 +0300)
The purpose of irqbalance is to distribute hardware interrupts across
processors/cores on a multiprocessor/-core system in order to increase
performance.

Only the cmd-line tool is compiled and installed.

Run-tested with ipq806x / R7800.

Signed-off-by: Hannu Nyman <hannu.nyman@iki.fi>
(cherry picked from commit c5913bd12d73c4c781b79c16246a8e9c8d236b8f)
(cherry picked from commit c42ecd05a1c91070bc86b4d8254972562b6e0c67)
(cherry picked from commit a1a96fc9fa8312c87ee997d613e9e9de3f3a82d9)

utils/irqbalance/Makefile [new file with mode: 0644]
utils/irqbalance/patches/100-disable-ui-compilation.patch [new file with mode: 0644]
utils/irqbalance/patches/200-avoid-glib.patch [new file with mode: 0644]

diff --git a/utils/irqbalance/Makefile b/utils/irqbalance/Makefile
new file mode 100644 (file)
index 0000000..3777fde
--- /dev/null
@@ -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 <hannu.nyman@iki.fi>
+
+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 (file)
index 0000000..5793ec6
--- /dev/null
@@ -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 (file)
index 0000000..3c20196
--- /dev/null
@@ -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 <stdint.h>
+ #include <glib.h>
+-#include <glib-unix.h>
+ #include <syslog.h>
+ #include <limits.h>
+@@ -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 <time.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+-#include <sys/socket.h>
+-#include <sys/un.h>
+ #include <fcntl.h>
+ #ifdef HAVE_GETOPT_LONG 
+ #include <getopt.h>
+@@ -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,