[PATCH 1/5] Add ability for socket communication

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This will be used with user interface and also can be used as API for
users to create their own scripts on top of. The socket communication
can be used for receiving data about IRQs-to-CPUs assignments and setup,
as well as setting some options during runtime.

Socket address: /var/run/irqbalance.sock

Data to send to socket:
stats: get the assignment tree of CPUs and IRQs
setup: get values of sleep interval, banned IRQs and banned CPUs
settings sleep <int>: set new sleep interval value
settings cpus <cpu_number1> <cpu_number2> ... : ban listed CPUs from
                                                IRQ handling (old values
                                                are forgotten, not added to)
settings ban irqs <irq1> <irq2> ... : ban listed IRQs from balancing (old
                                      values are forgotten, not added to)

Signed-off-by: Veronika Kabatova <vkabatov at redhat.com>
---
 cputree.c    |   9 ++-
 irqbalance.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 irqbalance.h |   4 +
 3 files changed, 212 insertions(+), 58 deletions(-)

diff --git a/cputree.c b/cputree.c
index 8762b64..b74ae76 100644
--- a/cputree.c
+++ b/cputree.c
@@ -38,6 +38,7 @@
 
 #include "irqbalance.h"
 
+extern char *banned_cpumask_from_ui;
 
 GList *cpus;
 GList *cache_domains;
@@ -76,11 +77,15 @@ 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) {
@@ -112,6 +117,8 @@ 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, 
diff --git a/irqbalance.c b/irqbalance.c
index 2eeee24..c2f3dcd 100644
--- a/irqbalance.c
+++ b/irqbalance.c
@@ -31,6 +31,8 @@
 #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>
@@ -42,6 +44,7 @@
 #include "irqbalance.h"
 
 volatile int keep_going = 1;
+int socket_fd;
 int one_shot_mode;
 int debug_mode;
 int foreground_mode;
@@ -58,6 +61,9 @@ 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)
 {
@@ -230,22 +236,197 @@ static void force_rebalance_irq(struct irq_info *info, void *data __attribute__(
 	info->assigned_obj = NULL;
 }
 
-static void handler(int signum)
+gboolean handler(gpointer data __attribute__((unused)))
 {
-	(void)signum;
 	keep_going = 0;
+	g_main_loop_quit(main_loop);
+	return TRUE;
 }
 
-static void force_rescan(int signum)
+gboolean force_rescan(gpointer data __attribute__((unused)))
 {
-	(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;
+
+	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 = recv(sock, buff, 500, 0)) < 0) {
+			log(TO_ALL, LOG_WARNING, "Error while receiving data.\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()
+{
+	struct sockaddr_un addr;
+
+	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;
+	strcpy(addr.sun_path, SOCKET_PATH);
+	addr.sun_path[strlen(addr.sun_path)] = '\0';
+	if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
+		log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the socket.\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);
@@ -345,19 +526,11 @@ int main(int argc, char** argv)
 		}
 	}
 
-	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);
-
+	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);
 	sigprocmask(SIG_SETMASK, &old_sigset, NULL);
 
 #ifdef HAVE_LIBCAP_NG
@@ -366,58 +539,28 @@ 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();
 
-	while (keep_going) {
-		sleep_approx(sleep_interval);
-		log(TO_CONSOLE, LOG_INFO, "\n\n\n-----------------------------------------------------------------------------\n");
-
-
-		clear_work_stats();
-		parse_proc_interrupts();
-		parse_proc_stat();
+	init_socket();
+	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);
 
-		/* 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();
+	g_main_loop_quit(main_loop);
 	
-		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);
+	unlink(SOCKET_PATH);
 
 	return EXIT_SUCCESS;
 }
diff --git a/irqbalance.h b/irqbalance.h
index d2d0f07..2ca0061 100644
--- a/irqbalance.h
+++ b/irqbalance.h
@@ -8,6 +8,7 @@
 
 #include <stdint.h>
 #include <glib.h>
+#include <glib-unix.h>
 #include <syslog.h>
 #include <limits.h>
 
@@ -62,6 +63,7 @@ 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;
@@ -169,5 +171,7 @@ extern unsigned int log_mask;
 }while(0)
 #endif /* HAVE_LIBSYSTEMD */
 
+#define SOCKET_PATH "/var/run/irqbalance.sock"
+
 #endif /* __INCLUDE_GUARD_IRQBALANCE_H_ */
 
-- 
2.7.4




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux