[PATCH v2 4/5] Add main user interface files

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

 



Signed-off-by: Veronika Kabatova <vkabatov at redhat.com>
---
 ui/irqbalance-ui.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 ui/irqbalance-ui.h |  86 ++++++++++++
 2 files changed, 486 insertions(+)
 create mode 100644 ui/irqbalance-ui.c
 create mode 100644 ui/irqbalance-ui.h

diff --git a/ui/irqbalance-ui.c b/ui/irqbalance-ui.c
new file mode 100644
index 0000000..74ba93c
--- /dev/null
+++ b/ui/irqbalance-ui.c
@@ -0,0 +1,400 @@
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <curses.h>
+#include <ncurses.h>
+#include "irqbalance-ui.h"
+#include "ui.h"
+#include "helpers.h"
+
+
+int irqbalance_pid = -1;
+GList *tree = NULL;
+setup_t setup;
+GMainLoop *main_loop;
+int is_tree = 1;
+
+struct msghdr * create_credentials_msg()
+{
+	struct ucred *credentials = malloc(sizeof(struct ucred));
+	credentials->pid = getpid();
+	credentials->uid = geteuid();
+	credentials->gid = getegid();
+
+	struct msghdr *msg = malloc(sizeof(struct msghdr));
+	memset(msg, 0, sizeof(struct msghdr));
+	msg->msg_iovlen = 1;
+	msg->msg_control = malloc(CMSG_SPACE(sizeof(struct ucred)));
+	msg->msg_controllen = CMSG_SPACE(sizeof(struct ucred));
+
+	struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_CREDENTIALS;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+	memcpy(CMSG_DATA(cmsg), credentials, sizeof(struct ucred));
+
+	return msg;
+}
+
+int init_connection()
+{
+	struct sockaddr_un addr;
+	memset(&addr, 0, sizeof(struct sockaddr_un));
+
+	int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if(socket_fd < 0) {
+		perror("Error opening socket");
+		return 0;
+	}
+	addr.sun_family = AF_UNIX;
+	char socket_name[64];
+	snprintf(socket_name, 64, "%s%d.sock", SOCKET_PATH, irqbalance_pid);
+	strncpy(addr.sun_path + 1, socket_name, strlen(socket_name));
+
+	if(connect(socket_fd, (struct sockaddr *)&addr,
+				sizeof(sa_family_t) + strlen(socket_name) + 1) < 0) {
+		return 0;
+	}
+
+	return socket_fd;
+}
+
+void send_settings(char *data)
+{
+	/* Send "settings sleep X" to set sleep interval, "settings ban
+	 * irqs X Y..." to ban IRQs from balancing,
+	 * "settings cpus <banned_list>" to setup which CPUs are forbidden
+	 * to handle IRQs
+	 */
+	int socket_fd = init_connection();
+	if(!socket_fd) {
+		return;
+	}
+
+	struct msghdr *msg = create_credentials_msg();
+	struct iovec iov;
+	iov.iov_base = (void *) data;
+	iov.iov_len = strlen(data);
+	msg->msg_iov = &iov;
+	sendmsg(socket_fd, msg, 0);
+
+	close(socket_fd);
+}
+
+char * get_data(char *string)
+{
+	/* Send "setup" to get sleep interval, banned IRQs and banned CPUs,
+	 * "stats" to get CPU tree statistics
+	 */
+	int socket_fd = init_connection();
+	if(!socket_fd) {
+		return NULL;
+	}
+
+	struct msghdr *msg = create_credentials_msg();
+	struct iovec iov;
+	iov.iov_base = (void *) string;
+	iov.iov_len = strlen(string);
+	msg->msg_iov = &iov;
+	sendmsg(socket_fd, msg, 0);
+
+	char *data = malloc(2048 * sizeof(char));
+	int len = recv(socket_fd, data, 2048, 0);
+	close(socket_fd);
+	data[len] = '\0';
+	return data;
+}
+
+void parse_setup(char *setup_data)
+{
+	char *token, *ptr;
+	if((setup_data == NULL) || (strlen(setup_data) == 0)) return;
+	char copy[strlen(setup_data) + 1];
+	strncpy(copy, setup_data, strlen(setup_data) + 1);
+	setup.banned_irqs = NULL;
+	setup.banned_cpus = NULL;
+	token = strtok_r(copy, " ", &ptr);
+	if(strncmp(token, "SLEEP", strlen("SLEEP"))) goto out;
+	setup.sleep = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+	token = strtok_r(ptr, " ", &ptr);
+	/* Parse banned IRQ data */
+	while(!strncmp(token, "IRQ", strlen("IRQ"))) {
+		irq_t *new_irq = malloc(sizeof(irq_t));
+		new_irq->vector = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "LOAD", strlen("LOAD"))) goto out;
+		new_irq->load = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "DIFF", strlen("DIFF"))) goto out;
+		new_irq->diff = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "CLASS", strlen("CLASS"))) goto out;
+		new_irq->class = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		new_irq->is_banned = 1;
+		new_irq->assigned_to = NULL;
+		setup.banned_irqs = g_list_append(setup.banned_irqs, new_irq);
+		token = strtok_r(ptr, " ", &ptr);
+	}
+
+	if(strncmp(token, "BANNED", strlen("BANNED"))) goto out;
+	token = strtok_r(ptr, " ", &ptr);
+	for(int i = strlen(token) - 1; i >= 0; i--) {
+		char *map = hex_to_bitmap(token[i]);
+		for(int j = 3; j >= 0; j--) {
+			if(map[j] == '1') {
+				uint64_t *banned_cpu = malloc(sizeof(uint64_t));
+				*banned_cpu = (4 * (strlen(token) - (i + 1)) + (4 - (j + 1)));
+				setup.banned_cpus = g_list_append(setup.banned_cpus,
+								banned_cpu);
+			}
+		}
+	}
+	return;
+
+out: {
+	/* Invalid data presented */
+	char invalid_data[128];
+	snprintf(invalid_data, 128, "Invalid data sent. Unexpected token: %s\n",
+				token);
+	printf("%s\n", invalid_data);
+	g_list_free(tree);
+	exit(1);
+}
+}
+
+GList * concat_child_lists(cpu_node_t *node)
+{
+	GList *new = NULL;
+	GList *child_entry = g_list_first(node->children);
+	do {
+		cpu_node_t *child = (cpu_node_t *)child_entry->data;
+		GList *cpu_entry = g_list_first(child->cpu_list);
+		do {
+			uint64_t *cpu = (uint64_t *)cpu_entry->data;
+			new = g_list_append(new, cpu);
+			cpu_entry = g_list_next(cpu_entry);
+		} while(cpu_entry != NULL);
+		child_entry = g_list_next(child_entry);
+	} while(child_entry != NULL);
+
+	return new;
+}
+
+void copy_cpu_list_to_irq(irq_t *irq, void *data)
+{
+	irq->assigned_to = g_list_copy((GList *)data);
+	irq->assigned_to = g_list_sort(irq->assigned_to, sort_ints);
+}
+
+void assign_cpu_lists(cpu_node_t *node, void *data __attribute__((unused)))
+{
+	if(g_list_length(node->children) > 0) {
+		for_each_node(node->children, assign_cpu_lists, NULL);
+		node->cpu_list = concat_child_lists(node);
+	} else {
+		node->cpu_list = g_list_append(node->cpu_list, &(node->number));
+	}
+
+	for_each_irq(node->irqs, copy_cpu_list_to_irq, node->cpu_list);
+}
+
+void assign_cpu_mask(cpu_node_t *node, void *data __attribute__((unused)))
+{
+	char *mask = malloc(16 * sizeof(char));
+	mask[0] = '\0';
+	unsigned int sum = 0;
+	GList *list_entry = g_list_first(node->cpu_list);
+	do {
+		int *cpu = list_entry->data;
+		sum += 1 << (*cpu);
+		list_entry = g_list_next(list_entry);
+	} while(list_entry != NULL);
+	snprintf(mask, 15, "0x%x", sum);
+	node->cpu_mask = mask;
+
+	if(g_list_length(node->children) > 0) {
+		for_each_node(node->children, assign_cpu_mask, NULL);
+	}
+}
+
+void parse_into_tree(char *data)
+{
+	if((data == NULL) || (strlen(data) == 0)) return;
+	char *token, *ptr;
+	cpu_node_t *parent = NULL;
+	char copy[strlen(data) + 1];
+	strncpy(copy, data, strlen(data) + 1);
+	tree = NULL;
+
+	token = strtok_r(copy, " ", &ptr);
+	while(token != NULL) {
+		/* Parse node data */
+		if(strncmp(token, "TYPE", strlen("TYPE"))) goto out;
+		cpu_node_t *new = malloc(sizeof(cpu_node_t));
+		new->irqs = NULL;
+		new->children = NULL;
+		new->cpu_list = NULL;
+		new->cpu_mask = NULL;
+		new->type = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		if(new->type == OBJ_TYPE_NODE) {
+			parent = NULL;
+		} else if(new->type >= parent->type) {
+			parent = parent->parent;
+		}
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "NUMBER", strlen("NUMBER"))) goto out;
+		new->number = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "LOAD", strlen("LOAD"))) goto out;
+		new->load = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+		if(strncmp(token, "SAVE_MODE", strlen("SAVE_MODE"))) goto out;
+		new->is_powersave = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+		token = strtok_r(ptr, " ", &ptr);
+
+		/* Parse assigned IRQ data */
+		while((token != NULL) && (!strncmp(token, "IRQ", strlen("IRQ")))) {
+			irq_t *new_irq = malloc(sizeof(irq_t));
+			new_irq->vector = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+			token = strtok_r(ptr, " ", &ptr);
+			if(strncmp(token, "LOAD", strlen("LOAD"))) goto out;
+			new_irq->load = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+			token = strtok_r(ptr, " ", &ptr);
+			if(strncmp(token, "DIFF", strlen("DIFF"))) goto out;
+			new_irq->diff = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+			token = strtok_r(ptr, " ", &ptr);
+			if(strncmp(token, "CLASS", strlen("CLASS"))) goto out;
+			new_irq->class = strtol(strtok_r(ptr, " ", &ptr), NULL, 10);
+			new_irq->is_banned = 0;
+			new->irqs = g_list_append(new->irqs, new_irq);
+			token = strtok_r(ptr, " ", &ptr);
+		}
+
+		if((token == NULL) || (strncmp(token, "IRQ", strlen("IRQ")))) {
+			new->parent = parent;
+			if(parent == NULL) {
+				tree = g_list_append(tree, new);
+			} else {
+				parent->children = g_list_append(parent->children, new);
+			}
+			if(new->type != OBJ_TYPE_CPU) {
+				parent = new;
+			}
+		}
+	}
+
+	for_each_node(tree, assign_cpu_lists, NULL);
+	for_each_node(tree, assign_cpu_mask, NULL);
+	return;
+
+out: {
+	/* Invalid data presented */
+	char invalid_data[128];
+	snprintf(invalid_data, 128, "Invalid data sent. Unexpected token: %s\n",
+				token);
+	printf("%s\n", invalid_data);
+	g_list_free(tree);
+	exit(1);
+}
+}
+
+gboolean rescan_tree(gpointer data __attribute__((unused)))
+{
+	char *setup_data = get_data(SETUP);
+	parse_setup(setup_data);
+	char *irqbalance_data = get_data(STATS);
+	parse_into_tree(irqbalance_data);
+	if(is_tree) {
+		display_tree();
+	}
+
+	return TRUE;
+}
+
+gboolean key_loop(gpointer data __attribute__((unused)))
+{
+	int c = getch();
+	switch(c) {
+	case 'q':
+		close_window(0);
+		break;
+	case KEY_F(3):
+		is_tree = 1;
+		display_tree();
+		break;
+	case KEY_F(4):
+		is_tree = 0;
+		settings();
+		break;
+	case KEY_F(5):
+		is_tree = 0;
+		setup_irqs();
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+int main(int argc, char **argv)
+{
+	if(getuid() != 0) {
+		printf("This program needs to be executed with root priviledges\n");
+		return EACCES;
+	}
+	if(argc > 1) {
+		/* PID of irqbalance specified */
+		irqbalance_pid = strtol(argv[1], NULL, 10);
+		if(!irqbalance_pid) {
+			printf("PID must be a number\n");
+			return EINVAL;
+		}
+	} else {
+		/* We need to find irqbalance's PID */
+		DIR *dir = opendir("/proc");
+		if(dir) {
+			struct dirent *entry;
+			char cmdfile[64];
+			char cmdstring[256];
+			cmdstring[255] = '\0';
+			do {
+				entry = readdir(dir);
+				if(entry) {
+					snprintf(cmdfile, 64, "/proc/%s/cmdline", entry->d_name);
+					FILE *f = fopen(cmdfile, "r");
+					if(f == NULL) {
+						continue;
+					}
+					fgets(cmdstring, 255, f);
+					if((strstr(cmdstring, "irqbalance") != NULL) &&
+							(strstr(cmdstring, "irqbalance-ui") == NULL)) {
+						irqbalance_pid = strtol(entry->d_name, NULL, 10);
+					}
+					fclose(f);
+				}
+			} while((entry) && (irqbalance_pid == -1));
+		}
+		if(irqbalance_pid == -1) {
+			printf("Unable to determine irqbalance PID\n");
+			return EINVAL;
+		}
+	}
+
+	init();
+
+	main_loop = g_main_loop_new(NULL, FALSE);
+	g_timeout_add_seconds(5, rescan_tree, NULL);
+	g_timeout_add_seconds(1, key_loop, NULL);
+	g_main_loop_run(main_loop);
+
+
+	g_main_loop_quit(main_loop);
+	close_window(0);
+}
diff --git a/ui/irqbalance-ui.h b/ui/irqbalance-ui.h
new file mode 100644
index 0000000..f97fcb1
--- /dev/null
+++ b/ui/irqbalance-ui.h
@@ -0,0 +1,86 @@
+
+#ifndef IRQBALANCE_UI_H
+#define IRQBALANCE_UI_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <glib.h>
+#include <glib-unix.h>
+
+#define SOCKET_PATH "irqbalance"
+
+#define STATS "stats"
+#define SET_SLEEP "settings sleep "
+#define BAN_IRQS "settings ban irqs "
+#define SETUP "setup"
+
+/* IRQ CLASSES (same as irqbalance uses) */
+#define IRQ_NODEF      -1
+#define IRQ_OTHER       0
+#define IRQ_LEGACY      1
+#define IRQ_SCSI        2
+#define IRQ_VIDEO       3
+#define IRQ_ETH         4
+#define IRQ_GBETH       5
+#define IRQ_10GBETH     6
+#define IRQ_VIRT_EVENT  7
+
+
+/* Typedefs */
+
+typedef enum node_type {
+	OBJ_TYPE_CPU,
+	OBJ_TYPE_CACHE,
+	OBJ_TYPE_PACKAGE,
+	OBJ_TYPE_NODE
+} node_type_e;
+
+typedef struct irq {
+	int vector;
+	uint64_t load;
+	uint64_t diff;
+	char is_banned;
+	GList *assigned_to;
+	int class;
+} irq_t;
+
+typedef struct cpu_node {
+	node_type_e type;
+	int number;
+	uint64_t load;
+	int is_powersave;
+	struct cpu_node *parent;
+	GList *children;
+	GList *irqs;
+	GList *cpu_list;
+	char *cpu_mask;
+} cpu_node_t;
+
+typedef struct cpu_ban {
+	int number;
+	char is_banned;
+} cpu_ban_t;
+
+typedef struct setup {
+	uint64_t sleep;
+	GList *banned_irqs;
+	GList *banned_cpus;
+} setup_t;
+
+/* Function prototypes */
+
+struct msghdr * create_credentials_msg();
+int init_connection();
+void send_settings(char *data);
+char * get_data(char *string);
+void parse_setup(char *setup_data);
+GList * concat_child_lists(cpu_node_t *node);
+void copy_cpu_list_to_irq(irq_t *irq, void *data);
+void assign_cpu_lists(cpu_node_t *node, void *data);
+void assign_cpu_mask(cpu_node_t *node, void *data);
+void parse_into_tree(char *data);
+gboolean rescan_tree(gpointer data);
+int main();
+
+
+#endif /* IRQBALANCE_UI_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