Browse Source

Add files

Serj Kalichev 10 years ago
parent
commit
fd13ba5963
6 changed files with 927 additions and 0 deletions
  1. 216 0
      cpu.c
  2. 332 0
      irq.c
  3. 134 0
      numa.c
  4. 23 0
      numa.h
  5. 205 0
      pxm.c
  6. 17 0
      pxm.h

+ 216 - 0
cpu.c

@@ -0,0 +1,216 @@
+/* cpu.c
+ * Parse CPU-related files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "lub/list.h"
+#include "cpumask.h"
+#include "cpu.h"
+#include "irq.h"
+
+int cpu_list_compare(const void *first, const void *second)
+{
+	const cpu_t *f = (const cpu_t *)first;
+	const cpu_t *s = (const cpu_t *)second;
+	return (f->id - s->id);
+}
+
+int cpu_list_compare_len(const void *first, const void *second)
+{
+	const cpu_t *f = (const cpu_t *)first;
+	const cpu_t *s = (const cpu_t *)second;
+	return (lub_list_len(f->irqs) - lub_list_len(s->irqs));
+}
+
+static cpu_t * cpu_new(unsigned int id)
+{
+	cpu_t *new;
+
+	if (!(new = malloc(sizeof(*new))))
+		return NULL;
+	new->id = id;
+	new->old_load_all = 0;
+	new->old_load_irq = 0;
+	new->old_load = 0;
+	new->load = 0;
+	new->irqs = lub_list_new(irq_list_compare);
+	cpus_clear(new->cpumask);
+	cpu_set(new->id, new->cpumask);
+
+	return new;
+}
+
+static void cpu_free(cpu_t *cpu)
+{
+	lub_list_node_t *node;
+
+	while ((node = lub_list__get_tail(cpu->irqs))) {
+		lub_list_del(cpu->irqs, node);
+		lub_list_node_free(node);
+	}
+	lub_list_free(cpu->irqs);
+	free(cpu);
+}
+
+/* Search for CPU with specified package and core IDs.
+   The second CPU with the same IDs is a thread of Hyper Threading.
+   We don't want to use HT for IRQ balancing. */
+static cpu_t * cpu_list_search_ht(lub_list_t *cpus,
+	unsigned int package_id, unsigned int core_id,
+	cpumask_t thread_siblings)
+{
+	lub_list_node_t *iter;
+
+	/* Check if current CPU has thread siblings */
+	/* The CPUs without thread siblings has no hyper
+	   threading. For example some AMD processors has
+	   two CPUs with the same package and core ids but
+	   has no thread siblings. Don't consider such CPUs as
+	   a hyper threading. */
+	if (cpus_weight(thread_siblings) < 2)
+		return NULL;
+
+	for (iter = lub_list_iterator_init(cpus); iter;
+		iter = lub_list_iterator_next(iter)) {
+		cpu_t *cpu;
+		cpu = (cpu_t *)lub_list_node__get_data(iter);
+		if (cpu->package_id != package_id)
+			continue;
+		if (cpu->core_id != core_id)
+			continue;
+		return cpu;
+	}
+
+	return NULL;
+}
+
+cpu_t * cpu_list_search(lub_list_t *cpus, unsigned int id)
+{
+	lub_list_node_t *node;
+	cpu_t search;
+
+	search.id = id;
+	node = lub_list_search(cpus, &search);
+	if (!node)
+		return NULL;
+	return (cpu_t *)lub_list_node__get_data(node);
+}
+
+static cpu_t * cpu_list_add(lub_list_t *cpus, cpu_t *cpu)
+{
+	cpu_t *old = cpu_list_search(cpus, cpu->id);
+
+	if (old) /* CPU already exists. May be renew some fields later */
+		return old;
+	lub_list_add(cpus, cpu);
+
+	return cpu;
+}
+
+int cpu_list_free(lub_list_t *cpus)
+{
+	lub_list_node_t *iter;
+	while ((iter = lub_list__get_head(cpus))) {
+		cpu_t *cpu;
+		cpu = (cpu_t *)lub_list_node__get_data(iter);
+		cpu_free(cpu);
+		lub_list_del(cpus, iter);
+		lub_list_node_free(iter);
+	}
+	lub_list_free(cpus);
+	return 0;
+}
+
+/* Show CPU information */
+static void show_cpu_info(cpu_t *cpu)
+{
+	char buf[NR_CPUS + 1];
+	cpumask_scnprintf(buf, sizeof(buf), cpu->cpumask);
+	printf("CPU %d package %d core %d mask %s\n", cpu->id, cpu->package_id, cpu->core_id, buf);
+}
+
+/* Show CPU list */
+int show_cpus(lub_list_t *cpus)
+{
+	lub_list_node_t *iter;
+	for (iter = lub_list_iterator_init(cpus); iter;
+		iter = lub_list_iterator_next(iter)) {
+		cpu_t *cpu;
+		cpu = (cpu_t *)lub_list_node__get_data(iter);
+		show_cpu_info(cpu);
+	}
+	return 0;
+}
+
+/* Search for CPUs */
+int scan_cpus(lub_list_t *cpus, int ht)
+{
+	FILE *fd;
+	char path[PATH_MAX];
+	unsigned int id;
+	unsigned int package_id;
+	unsigned int core_id;
+	cpu_t *new;
+	char *str = NULL;
+	size_t sz;
+	cpumask_t thread_siblings;
+
+	for (id = 0; id < NR_CPUS; id++) {
+		sprintf(path, "%s/cpu%d", SYSFS_CPU_PATH, id);
+		if (access(path, F_OK))
+			break;
+
+		/* Try to get package_id */
+		sprintf(path, "%s/cpu%d/topology/physical_package_id",
+			SYSFS_CPU_PATH, id);
+		if (!(fd = fopen(path, "r")))
+			continue;
+		if (fscanf(fd, "%u", &package_id) < 0) {
+			fclose(fd);
+			continue;
+		}
+		fclose(fd);
+
+		/* Try to get core_id */
+		sprintf(path, "%s/cpu%d/topology/core_id",
+			SYSFS_CPU_PATH, id);
+		if (!(fd = fopen(path, "r")))
+			continue;
+		if (fscanf(fd, "%u", &core_id) < 0) {
+			fclose(fd);
+			continue;
+		}
+		fclose(fd);
+
+		/* Get thread siblings */
+		cpus_clear(thread_siblings);
+		cpu_set(id, thread_siblings);
+		sprintf(path, "%s/cpu%d/topology/thread_siblings",
+			SYSFS_CPU_PATH, id);
+		if ((fd = fopen(path, "r"))) {
+			if (getline(&str, &sz, fd) >= 0)
+				cpumask_parse_user(str, strlen(str), thread_siblings);
+			fclose(fd);
+		}
+
+		/* Don't use second thread of Hyper Threading */
+		if (!ht && cpu_list_search_ht(cpus, package_id, core_id, thread_siblings))
+			continue;
+
+		new = cpu_new(id);
+		new->package_id = package_id;
+		new->core_id = core_id;
+		cpu_list_add(cpus, new);
+	}
+	free(str);
+
+	return 0;
+}

+ 332 - 0
irq.c

@@ -0,0 +1,332 @@
+/* irq.c
+ * Parse IRQ-related files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "lub/list.h"
+#include "irq.h"
+#include "pxm.h"
+
+#define STR(str) ( str ? str : "" )
+
+int irq_list_compare(const void *first, const void *second)
+{
+	const irq_t *f = (const irq_t *)first;
+	const irq_t *s = (const irq_t *)second;
+	return (f->irq - s->irq);
+}
+
+static irq_t * irq_new(int num)
+{
+	irq_t *new;
+
+	if (!(new = malloc(sizeof(*new))))
+		return NULL;
+	new->irq = num;
+	new->type = NULL;
+	new->desc = NULL;
+	new->refresh = 1;
+	new->old_intr = 0;
+	new->intr = 0;
+	new->cpu = NULL;
+	new->weight = 0;
+	cpus_setall(new->local_cpus);
+	cpus_clear(new->affinity);
+	new->blacklisted = 0;
+
+	return new;
+}
+
+static void irq_free(irq_t *irq)
+{
+	free(irq->type);
+	free(irq->desc);
+	free(irq);
+}
+
+irq_t * irq_list_search(lub_list_t *irqs, unsigned int num)
+{
+	lub_list_node_t *node;
+	irq_t search;
+
+	search.irq = num;
+	node = lub_list_search(irqs, &search);
+	if (!node)
+		return NULL;
+	return (irq_t *)lub_list_node__get_data(node);
+}
+
+static irq_t * irq_list_add(lub_list_t *irqs, unsigned int num)
+{
+	lub_list_node_t *node;
+	irq_t *new;
+	irq_t search;
+
+	search.irq = num;
+	node = lub_list_search(irqs, &search);
+	if (node) /* IRQ already exists. May be renew some fields later */
+		return (irq_t *)lub_list_node__get_data(node);
+	if (!(new = irq_new(num)))
+		return NULL;
+	lub_list_add(irqs, new);
+
+	return new;
+}
+
+int irq_list_free(lub_list_t *irqs)
+{
+	lub_list_node_t *iter;
+	while ((iter = lub_list__get_head(irqs))) {
+		irq_t *irq;
+		irq = (irq_t *)lub_list_node__get_data(iter);
+		irq_free(irq);
+		lub_list_del(irqs, iter);
+		lub_list_node_free(iter);
+	}
+	lub_list_free(irqs);
+	return 0;
+}
+
+/* Show IRQ information */
+static void irq_show(irq_t *irq)
+{
+	char buf[NR_CPUS + 1];
+	if (cpus_full(irq->local_cpus))
+		snprintf(buf, sizeof(buf), "*");
+	else
+		cpumask_scnprintf(buf, sizeof(buf), irq->local_cpus);
+	printf("IRQ %3d %s [%s] %s\n", irq->irq, buf, STR(irq->type), STR(irq->desc));
+}
+
+/* Show IRQ list */
+int irq_list_show(lub_list_t *irqs)
+{
+	lub_list_node_t *iter;
+	for (iter = lub_list_iterator_init(irqs); iter;
+		iter = lub_list_iterator_next(iter)) {
+		irq_t *irq;
+		irq = (irq_t *)lub_list_node__get_data(iter);
+		irq_show(irq);
+	}
+	return 0;
+}
+
+static int parse_local_cpus(lub_list_t *irqs, const char *sysfs_path,
+	unsigned int num, lub_list_t *pxms)
+{
+	char path[PATH_MAX];
+	FILE *fd;
+	char *str = NULL;
+	size_t sz;
+	cpumask_t local_cpus;
+	irq_t *irq = NULL;
+	cpumask_t cpumask;
+
+	irq = irq_list_search(irqs, num);
+	if (!irq)
+		return -1;
+
+	/* Find proximity in config file. */
+	if (!pxm_search(pxms, sysfs_path, cpumask)) {
+char buf[NR_CPUS + 1];
+cpumask_scnprintf(buf, sizeof(buf), cpumask);
+printf("!!!!!! %s %s\n", sysfs_path, buf);
+/*		cpus_clear(irq->local_cpus);
+		cpus_or(irq->local_cpus, irq->local_cpus, cpumask);
+*/		cpus_setall(irq->local_cpus);
+		cpus_and(irq->local_cpus, irq->local_cpus, cpumask);
+		return 0;
+	}
+
+	sprintf(path, "%s/%s/local_cpus", SYSFS_PCI_PATH, sysfs_path);
+	if (!(fd = fopen(path, "r")))
+		return -1;
+	if (getline(&str, &sz, fd) < 0) {
+		fclose(fd);
+		return -1;
+	}
+	fclose(fd);
+	cpumask_parse_user(str, strlen(str), local_cpus);
+	cpus_and(irq->local_cpus, irq->local_cpus, local_cpus);
+	free(str);
+
+	return 0;
+}
+
+static int parse_sysfs(lub_list_t *irqs, lub_list_t *pxms)
+{
+	DIR *dir;
+	DIR *msi;
+	struct dirent *dent;
+	struct dirent *ment;
+	FILE *fd;
+	char path[PATH_MAX];
+	int num;
+
+	/* Now we can parse PCI devices only */
+	/* Get info from /sys/bus/pci/devices */
+	dir = opendir(SYSFS_PCI_PATH);
+	if (!dir)
+		return -1;
+	while((dent = readdir(dir))) {
+		if (!strcmp(dent->d_name, ".") ||
+			!strcmp(dent->d_name, ".."))
+			continue;
+
+		/* Search for MSI IRQs. Since linux-3.2 */
+		sprintf(path, "%s/%s/msi_irqs", SYSFS_PCI_PATH, dent->d_name);
+		if ((msi = opendir(path))) {
+			while((ment = readdir(msi))) {
+				if (!strcmp(ment->d_name, ".") ||
+					!strcmp(ment->d_name, ".."))
+					continue;
+				num = strtol(ment->d_name, NULL, 10);
+				if (!num)
+					continue;
+				parse_local_cpus(irqs, dent->d_name, num, pxms);
+			}
+			closedir(msi);
+			continue;
+		}
+
+		/* Try to get IRQ number from irq file */
+		sprintf(path, "%s/%s/irq", SYSFS_PCI_PATH, dent->d_name);
+		if (!(fd = fopen(path, "r")))
+			continue;
+		if (fscanf(fd, "%d", &num) < 0) {
+			fclose(fd);
+			continue;
+		}
+		fclose(fd);
+		if (!num)
+			continue;
+
+		parse_local_cpus(irqs, dent->d_name, num, pxms);
+	}
+	closedir(dir);
+
+	return 0;
+}
+
+int irq_get_affinity(irq_t *irq)
+{
+	char path[PATH_MAX];
+	FILE *fd;
+	char *str = NULL;
+	size_t sz;
+
+	if (!irq)
+		return -1;
+
+	sprintf(path, "%s/%u/smp_affinity", PROC_IRQ, irq->irq);
+	if (!(fd = fopen(path, "r")))
+		return -1;
+	if (getline(&str, &sz, fd) < 0) {
+		fclose(fd);
+		return -1;
+	}
+	fclose(fd);
+	cpumask_parse_user(str, strlen(str), irq->affinity);
+	free(str);
+
+	return 0;
+}
+
+
+/* Parse /proc/interrupts to get actual IRQ list */
+int scan_irqs(lub_list_t *irqs, lub_list_t *balance_irqs, lub_list_t *pxms)
+{
+	FILE *fd;
+	unsigned int num;
+	char *str = NULL;
+	size_t sz;
+	irq_t *irq;
+	lub_list_node_t *iter;
+
+	if (!(fd = fopen(PROC_INTERRUPTS, "r")))
+		return -1;
+	while(getline(&str, &sz, fd) >= 0) {
+		char *endptr, *tok;
+		int new = 0;
+		num = strtoul(str, &endptr, 10);
+		if (endptr == str)
+			continue;
+		
+		if (!(irq = irq_list_search(irqs, num))) {
+			new = 1;
+			irq = irq_list_add(irqs, num);
+		}
+
+		/* Set refresh flag because IRQ was found */
+		irq->refresh = 1;
+
+		/* Doesn't refresh info for blacklisted IRQs */
+		if (irq->blacklisted)
+			continue;
+
+		/* Find IRQ type - first non-digital and non-space */
+		while (*endptr && !isalpha(*endptr))
+			endptr++;
+		tok = endptr; /* It will be IRQ type */
+		while (*endptr && !isblank(*endptr))
+			endptr++;
+		free(irq->type);
+		irq->type = strndup(tok, endptr - tok);
+
+		/* Find IRQ devices list */
+		while (*endptr && !isalpha(*endptr))
+			endptr++;
+		tok = endptr; /* It will be device list */
+		while (*endptr && !iscntrl(*endptr))
+			endptr++;
+		free(irq->desc);
+		irq->desc = strndup(tok, endptr - tok);
+
+		if (new) {
+			/* By default all CPUs are local for IRQ. Real local
+			   CPUs will be find while sysfs scan. */
+			cpus_setall(irq->local_cpus);
+
+			irq_get_affinity(irq);
+
+			lub_list_add(balance_irqs, irq);
+			printf("Add IRQ %3d %s\n", irq->irq, STR(irq->desc));
+		}
+	}
+	free(str);
+	fclose(fd);
+
+	/* Remove disapeared IRQs */
+	iter = lub_list_iterator_init(irqs);
+	while(iter) {
+		irq_t *irq;
+		lub_list_node_t *old_iter;
+		irq = (irq_t *)lub_list_node__get_data(iter);
+		old_iter = iter;
+		iter = lub_list_iterator_next(iter);
+		if (!irq->refresh) {
+			lub_list_del(irqs, old_iter);
+			irq_free(irq);
+			printf("Remove IRQ %3d %s\n", irq->irq, STR(irq->desc));
+		} else {
+			/* Drop refresh flag for next iteration */
+			irq->refresh = 0;
+		}
+	}
+
+	/* No new IRQs were found. It doesn't need to scan sysfs. */
+	if (lub_list_len(balance_irqs) == 0)
+		return 0;
+	/* Add IRQ info from sysfs */
+	parse_sysfs(irqs, pxms);
+
+	return 0;
+}
+

+ 134 - 0
numa.c

@@ -0,0 +1,134 @@
+/* numa.c
+ * Parse NUMA-related files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "lub/list.h"
+#include "cpumask.h"
+#include "numa.h"
+
+int numa_list_compare(const void *first, const void *second)
+{
+	const numa_t *f = (const numa_t *)first;
+	const numa_t *s = (const numa_t *)second;
+	return (f->id - s->id);
+}
+
+static numa_t * numa_new(unsigned int id)
+{
+	numa_t *new;
+
+	if (!(new = malloc(sizeof(*new))))
+		return NULL;
+	new->id = id;
+	cpus_setall(new->cpumap);
+
+	return new;
+}
+
+static void numa_free(numa_t *numa)
+{
+	free(numa);
+}
+
+numa_t * numa_list_search(lub_list_t *numas, unsigned int id)
+{
+	lub_list_node_t *node;
+	numa_t search;
+
+	search.id = id;
+	node = lub_list_search(numas, &search);
+	if (!node)
+		return NULL;
+	return (numa_t *)lub_list_node__get_data(node);
+}
+
+static numa_t * numa_list_add(lub_list_t *numas, numa_t *numa)
+{
+	numa_t *old = numa_list_search(numas, numa->id);
+
+	if (old) /* NUMA already exists. May be renew some fields later */
+		return old;
+	lub_list_add(numas, numa);
+
+	return numa;
+}
+
+int numa_list_free(lub_list_t *numas)
+{
+	lub_list_node_t *iter;
+	while ((iter = lub_list__get_head(numas))) {
+		numa_t *numa;
+		numa = (numa_t *)lub_list_node__get_data(iter);
+		numa_free(numa);
+		lub_list_del(numas, iter);
+		lub_list_node_free(iter);
+	}
+	lub_list_free(numas);
+	return 0;
+}
+
+/* Show NUMA information */
+static void show_numa_info(numa_t *numa)
+{
+	char buf[NR_CPUS + 1];
+	cpumask_scnprintf(buf, sizeof(buf), numa->cpumap);
+	printf("NUMA node %d cpumap %s\n", numa->id, buf);
+}
+
+/* Show NUMA list */
+int show_numas(lub_list_t *numas)
+{
+	lub_list_node_t *iter;
+	for (iter = lub_list_iterator_init(numas); iter;
+		iter = lub_list_iterator_next(iter)) {
+		numa_t *numa;
+		numa = (numa_t *)lub_list_node__get_data(iter);
+		show_numa_info(numa);
+	}
+	return 0;
+}
+
+/* Search for NUMA nodes */
+int scan_numas(lub_list_t *numas)
+{
+	FILE *fd;
+	char path[PATH_MAX];
+	unsigned int id;
+	numa_t *numa;
+	char *str = NULL;
+	size_t sz;
+	cpumask_t cpumap;
+
+	for (id = 0; id < NR_NUMA_NODES; id++) {
+		sprintf(path, "%s/node%d", SYSFS_NUMA_PATH, id);
+		if (access(path, F_OK))
+			break;
+
+		if (!(numa = numa_list_search(numas, id))) {
+			numa = numa_new(id);
+			numa_list_add(numas, numa);
+		}
+
+		/* Get NUMA node cpumap */
+		sprintf(path, "%s/node%d/cpumap",
+			SYSFS_NUMA_PATH, id);
+		if ((fd = fopen(path, "r"))) {
+			if (getline(&str, &sz, fd) >= 0)
+				cpumask_parse_user(str, strlen(str), cpumap);
+			fclose(fd);
+			cpus_and(numa->cpumap, numa->cpumap, cpumap);
+		}
+	}
+	free(str);
+
+	return 0;
+}

+ 23 - 0
numa.h

@@ -0,0 +1,23 @@
+#ifndef _numa_h
+#define _numa_h
+
+#include "lub/list.h"
+#include "cpumask.h"
+
+struct numa_s {
+	unsigned int id; /* NUMA ID */
+	cpumask_t cpumap;
+};
+typedef struct numa_s numa_t;
+
+#define NR_NUMA_NODES 256
+/* System NUMA info */
+#define SYSFS_NUMA_PATH "/sys/devices/system/node"
+
+int numa_list_compare(const void *first, const void *second);
+int numa_list_free(lub_list_t *numas);
+int scan_numas(lub_list_t *numas);
+int show_numas(lub_list_t *numas);
+numa_t * numa_list_search(lub_list_t *numas, unsigned int id);
+
+#endif

+ 205 - 0
pxm.c

@@ -0,0 +1,205 @@
+/* pxm.c
+ * Parse manual proximity config.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "lub/list.h"
+#include "numa.h"
+#include "pxm.h"
+
+static pxm_t * pxm_new(const char *addr)
+{
+	pxm_t *new;
+
+	if (!(new = malloc(sizeof(*new))))
+		return NULL;
+	new->addr = strdup(addr);
+	cpus_clear(new->cpumask);
+
+	return new;
+}
+
+static void pxm_free(pxm_t *pxm)
+{
+	if (!pxm)
+		return;
+	if (pxm->addr)
+		free(pxm->addr);
+	free(pxm);
+}
+
+static pxm_t * pxm_list_add(lub_list_t *pxms, pxm_t *pxm)
+{
+	lub_list_add(pxms, pxm);
+	return pxm;
+}
+
+int pxm_list_free(lub_list_t *pxms)
+{
+	lub_list_node_t *iter;
+	while ((iter = lub_list__get_head(pxms))) {
+		pxm_t *pxm;
+		pxm = (pxm_t *)lub_list_node__get_data(iter);
+		pxm_free(pxm);
+		lub_list_del(pxms, iter);
+		lub_list_node_free(iter);
+	}
+	lub_list_free(pxms);
+	return 0;
+}
+
+/* Show proximity information */
+static void show_pxm_info(pxm_t *pxm)
+{
+	char buf[NR_CPUS + 1];
+	if (cpus_full(pxm->cpumask))
+		snprintf(buf, sizeof(buf), "*");
+	else
+		cpumask_scnprintf(buf, sizeof(buf), pxm->cpumask);
+	printf("PXM: %s cpumask %s\n", pxm->addr, buf);
+}
+
+/* Show PXM list */
+int show_pxms(lub_list_t *pxms)
+{
+	lub_list_node_t *iter;
+	for (iter = lub_list_iterator_init(pxms); iter;
+		iter = lub_list_iterator_next(iter)) {
+		pxm_t *pxm;
+		pxm = (pxm_t *)lub_list_node__get_data(iter);
+		show_pxm_info(pxm);
+	}
+	return 0;
+}
+
+int pxm_search(lub_list_t *pxms, const char *addr, cpumask_t cpumask)
+{
+	lub_list_node_t *iter;
+	int maxaddr = 0;
+
+	for (iter = lub_list_iterator_init(pxms); iter;
+		iter = lub_list_iterator_next(iter)) {
+		pxm_t *pxm;
+		char *tmp = NULL;
+		size_t len;
+
+		pxm = (pxm_t *)lub_list_node__get_data(iter);
+		tmp = strstr(addr, pxm->addr);
+		if (!tmp)
+			continue;
+		len = strlen(pxm->addr);
+		if (maxaddr >= len)
+			continue;
+		maxaddr = len;
+		cpus_clear(cpumask);
+		cpus_or(cpumask, cpumask, pxm->cpumask);
+	}
+
+	if (!maxaddr)
+		return -1;
+	return 0;
+}
+
+int parse_pxm_config(const char *fname, lub_list_t *pxms, lub_list_t *numas)
+{
+	FILE *file;
+	char *line = NULL;
+	size_t size = 0;
+	char *saveptr;
+	unsigned int ln = 0; /* Line number */
+	pxm_t *pxm;
+
+	if (!fname)
+		return -1;
+	file = fopen(fname, "r");
+	if (!file)
+		return -1;
+
+	while (!feof(file)) {
+		char *str = NULL;
+		char *pci_addr = NULL;
+		char *pxm_cmd = NULL;
+		char *pxm_pxm = NULL;
+		cpumask_t cpumask;
+
+		ln++; /* Next line */
+		if (getline(&line, &size, file) == 0)
+			break;
+		/* Find comments */
+		str = strchr(line, '#');
+		if (str)
+			*str = '\0';
+		/* Find \n */
+		str = strchr(line, '\n');
+		if (str)
+			*str = '\0';
+		/* Get PCI address */
+		pci_addr = strtok_r(line, " ", &saveptr);
+		if (!pci_addr)
+			continue;
+		/* Get PXM command */
+		pxm_cmd = strtok_r(NULL, " ", &saveptr);
+		if (!pxm_cmd) {
+			fprintf(stderr, "Warning: Illegal line %u in %s\n",
+				ln, fname);
+			continue;
+		}
+		/* Get PXM string (mask or node) */
+		pxm_pxm = strtok_r(NULL, " ", &saveptr);
+		if (!pxm_pxm) {
+			fprintf(stderr, "Warning: Illegal line %u in %s\n",
+				ln, fname);
+			continue;
+		}
+
+		if (!strcasecmp(pxm_cmd, "cpumask")) {
+			cpumask_parse_user(pxm_pxm, strlen(pxm_pxm),
+				cpumask);
+		} else if (!strcasecmp(pxm_cmd, "node")) {
+			char *endptr;
+			int noden = -1;
+			noden = strtol(pxm_pxm, &endptr, 10);
+			if (endptr == pxm_pxm) {
+				fprintf(stderr, "Warning: Wrong NUMA node in "
+					"line %u in %s\n", ln, fname);
+				continue;
+			}
+			if (noden == -1) /* Non-NUMA = all CPUs */
+				cpus_setall(cpumask);
+			else {
+				numa_t *numa;
+				numa = numa_list_search(numas, noden);
+				if (!numa) {
+					fprintf(stderr, "Warning: Wrong NUMA node. Line %u in %s\n",
+						ln, fname);
+					continue;
+				}
+				cpus_clear(cpumask);
+				cpus_or(cpumask, cpumask, numa->cpumap);
+			}
+		} else {
+			fprintf(stderr, "Warning: Illegal command %u in %s\n",
+				ln, fname);
+			continue;
+		}
+
+		/* Add new entry to PXM list */
+		pxm = pxm_new(pci_addr);
+		cpus_clear(pxm->cpumask);
+		cpus_or(pxm->cpumask, pxm->cpumask, cpumask);
+		pxm_list_add(pxms, pxm);
+	}
+
+	fclose(file);
+	free(line);
+
+	return 0;
+}

+ 17 - 0
pxm.h

@@ -0,0 +1,17 @@
+#ifndef _pxm_h
+#define _pxm_h
+
+#include "cpumask.h"
+
+struct pxm_s {
+	char *addr;
+	cpumask_t cpumask;
+};
+typedef struct pxm_s pxm_t;
+
+int pxm_list_free(lub_list_t *pxms);
+int show_pxms(lub_list_t *pxms);
+int pxm_search(lub_list_t *pxms, const char *addr, cpumask_t cpumask);
+int parse_pxm_config(const char *fname, lub_list_t *pxms, lub_list_t *numas);
+
+#endif