|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* Copyright (C) 2006, Intel Corporation
|
|
Packit |
9eaa09 |
* Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
|
|
Packit |
9eaa09 |
*
|
|
Packit |
9eaa09 |
* This file is part of irqbalance
|
|
Packit |
9eaa09 |
*
|
|
Packit |
9eaa09 |
* This program file is free software; you can redistribute it and/or modify it
|
|
Packit |
9eaa09 |
* under the terms of the GNU General Public License as published by the
|
|
Packit |
9eaa09 |
* Free Software Foundation; version 2 of the License.
|
|
Packit |
9eaa09 |
*
|
|
Packit |
9eaa09 |
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
Packit |
9eaa09 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
9eaa09 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
Packit |
9eaa09 |
* for more details.
|
|
Packit |
9eaa09 |
*
|
|
Packit |
9eaa09 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
9eaa09 |
* along with this program in a file named COPYING; if not, write to the
|
|
Packit |
9eaa09 |
* Free Software Foundation, Inc.,
|
|
Packit |
9eaa09 |
* 51 Franklin Street, Fifth Floor,
|
|
Packit |
9eaa09 |
* Boston, MA 02110-1301 USA
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* This file contains the code to construct and manipulate a hierarchy of processors,
|
|
Packit |
9eaa09 |
* cache domains and processor cores.
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
#include "config.h"
|
|
Packit |
9eaa09 |
#include <stdio.h>
|
|
Packit |
9eaa09 |
#include <stdlib.h>
|
|
Packit |
9eaa09 |
#include <string.h>
|
|
Packit |
9eaa09 |
#include <unistd.h>
|
|
Packit |
9eaa09 |
#include <sys/types.h>
|
|
Packit |
9eaa09 |
#include <sys/stat.h>
|
|
Packit |
9eaa09 |
#include <dirent.h>
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
#include <glib.h>
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
#include "irqbalance.h"
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
extern char *banned_cpumask_from_ui;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
GList *cpus;
|
|
Packit |
9eaa09 |
GList *cache_domains;
|
|
Packit |
9eaa09 |
GList *packages;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
int package_count;
|
|
Packit |
9eaa09 |
int cache_domain_count;
|
|
Packit |
9eaa09 |
int core_count;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* Users want to be able to keep interrupts away from some cpus; store these in a cpumask_t */
|
|
Packit |
9eaa09 |
cpumask_t banned_cpus;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpumask_t cpu_possible_map;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
it's convenient to have the complement of banned_cpus available so that
|
|
Packit |
9eaa09 |
the AND operator can be used to mask out unwanted cpus
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
cpumask_t unbanned_cpus;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* By default do not place IRQs on CPUs the kernel keeps isolated or
|
|
Packit |
9eaa09 |
* nohz_full, as specified through the boot commandline. Users can
|
|
Packit |
9eaa09 |
* override this with the IRQBALANCE_BANNED_CPUS environment variable.
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
static void setup_banned_cpus(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
FILE *file;
|
|
Packit |
9eaa09 |
char *line = NULL;
|
|
Packit |
9eaa09 |
size_t size = 0;
|
|
Packit |
9eaa09 |
char buffer[4096];
|
|
Packit |
9eaa09 |
cpumask_t nohz_full;
|
|
Packit |
9eaa09 |
cpumask_t isolated_cpus;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpus_clear(isolated_cpus);
|
|
Packit |
9eaa09 |
cpus_clear(nohz_full);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* A manually specified cpumask overrides auto-detection. */
|
|
Packit |
9eaa09 |
if (banned_cpumask_from_ui != NULL) {
|
|
Packit |
9eaa09 |
cpulist_parse(banned_cpumask_from_ui,
|
|
Packit |
9eaa09 |
strlen(banned_cpumask_from_ui), banned_cpus);
|
|
Packit |
9eaa09 |
goto out;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
if (getenv("IRQBALANCE_BANNED_CPUS")) {
|
|
Packit |
9eaa09 |
cpumask_parse_user(getenv("IRQBALANCE_BANNED_CPUS"), strlen(getenv("IRQBALANCE_BANNED_CPUS")), banned_cpus);
|
|
Packit |
9eaa09 |
goto out;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
file = fopen("/sys/devices/system/cpu/isolated", "r");
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file) > 0) {
|
|
Packit |
9eaa09 |
if (strlen(line) && line[0] != '\n')
|
|
Packit |
9eaa09 |
cpulist_parse(line, strlen(line), isolated_cpus);
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
line = NULL;
|
|
Packit |
9eaa09 |
size = 0;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
file = fopen("/sys/devices/system/cpu/nohz_full", "r");
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file) > 0) {
|
|
Packit |
9eaa09 |
if (strlen(line) && line[0] != '\n')
|
|
Packit |
9eaa09 |
cpulist_parse(line, strlen(line), nohz_full);
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
line = NULL;
|
|
Packit |
9eaa09 |
size = 0;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpus_or(banned_cpus, nohz_full, isolated_cpus);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
out:
|
|
Packit |
9eaa09 |
cpumask_scnprintf(buffer, 4096, isolated_cpus);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "Isolated CPUs: %s\n", buffer);
|
|
Packit |
9eaa09 |
cpumask_scnprintf(buffer, 4096, nohz_full);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "Adaptive-ticks CPUs: %s\n", buffer);
|
|
Packit |
9eaa09 |
cpumask_scnprintf(buffer, 4096, banned_cpus);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "Banned CPUs: %s\n", buffer);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void add_numa_node_to_topo_obj(struct topo_obj *obj, int nodeid)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
GList *entry;
|
|
Packit |
9eaa09 |
struct topo_obj *node;
|
|
Packit |
9eaa09 |
struct topo_obj *cand_node;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
node = get_numa_node(nodeid);
|
|
Packit |
9eaa09 |
if (!node || node->number == -1)
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
entry = g_list_first(obj->numa_nodes);
|
|
Packit |
9eaa09 |
while (entry) {
|
|
Packit |
9eaa09 |
cand_node = entry->data;
|
|
Packit |
9eaa09 |
if (cand_node == node)
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
entry = g_list_next(entry);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (!entry)
|
|
Packit |
9eaa09 |
obj->numa_nodes = g_list_append(obj->numa_nodes, node);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static struct topo_obj* add_cache_domain_to_package(struct topo_obj *cache,
|
|
Packit |
9eaa09 |
int packageid,
|
|
Packit |
9eaa09 |
cpumask_t package_mask,
|
|
Packit |
9eaa09 |
int nodeid)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
GList *entry;
|
|
Packit |
9eaa09 |
struct topo_obj *package;
|
|
Packit |
9eaa09 |
struct topo_obj *lcache;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
entry = g_list_first(packages);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
while (entry) {
|
|
Packit |
9eaa09 |
package = entry->data;
|
|
Packit |
9eaa09 |
if (cpus_equal(package_mask, package->mask)) {
|
|
Packit |
9eaa09 |
if (packageid != package->number)
|
|
Packit |
9eaa09 |
log(TO_ALL, LOG_WARNING, "package_mask with different physical_package_id found!\n");
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
entry = g_list_next(entry);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (!entry) {
|
|
Packit |
9eaa09 |
package = calloc(sizeof(struct topo_obj), 1);
|
|
Packit |
9eaa09 |
if (!package)
|
|
Packit |
9eaa09 |
return NULL;
|
|
Packit |
9eaa09 |
package->mask = package_mask;
|
|
Packit |
9eaa09 |
package->obj_type = OBJ_TYPE_PACKAGE;
|
|
Packit |
9eaa09 |
package->obj_type_list = &packages;
|
|
Packit |
9eaa09 |
package->number = packageid;
|
|
Packit |
9eaa09 |
packages = g_list_append(packages, package);
|
|
Packit |
9eaa09 |
package_count++;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
entry = g_list_first(package->children);
|
|
Packit |
9eaa09 |
while (entry) {
|
|
Packit |
9eaa09 |
lcache = entry->data;
|
|
Packit |
9eaa09 |
if (lcache == cache)
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
entry = g_list_next(entry);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (!entry) {
|
|
Packit |
9eaa09 |
package->children = g_list_append(package->children, cache);
|
|
Packit |
9eaa09 |
cache->parent = package;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (nodeid > -1)
|
|
Packit |
9eaa09 |
add_numa_node_to_topo_obj(package, nodeid);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
return package;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
static struct topo_obj* add_cpu_to_cache_domain(struct topo_obj *cpu,
|
|
Packit |
9eaa09 |
cpumask_t cache_mask,
|
|
Packit |
9eaa09 |
int nodeid)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
GList *entry;
|
|
Packit |
9eaa09 |
struct topo_obj *cache;
|
|
Packit |
9eaa09 |
struct topo_obj *lcpu;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
entry = g_list_first(cache_domains);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
while (entry) {
|
|
Packit |
9eaa09 |
cache = entry->data;
|
|
Packit |
9eaa09 |
if (cpus_equal(cache_mask, cache->mask))
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
entry = g_list_next(entry);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (!entry) {
|
|
Packit |
9eaa09 |
cache = calloc(sizeof(struct topo_obj), 1);
|
|
Packit |
9eaa09 |
if (!cache)
|
|
Packit |
9eaa09 |
return NULL;
|
|
Packit |
9eaa09 |
cache->obj_type = OBJ_TYPE_CACHE;
|
|
Packit |
9eaa09 |
cache->mask = cache_mask;
|
|
Packit |
9eaa09 |
cache->number = cache_domain_count;
|
|
Packit |
9eaa09 |
cache->obj_type_list = &cache_domains;
|
|
Packit |
9eaa09 |
cache_domains = g_list_append(cache_domains, cache);
|
|
Packit |
9eaa09 |
cache_domain_count++;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
entry = g_list_first(cache->children);
|
|
Packit |
9eaa09 |
while (entry) {
|
|
Packit |
9eaa09 |
lcpu = entry->data;
|
|
Packit |
9eaa09 |
if (lcpu == cpu)
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
entry = g_list_next(entry);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (!entry) {
|
|
Packit |
9eaa09 |
cache->children = g_list_append(cache->children, cpu);
|
|
Packit |
9eaa09 |
cpu->parent = (struct topo_obj *)cache;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (nodeid > -1)
|
|
Packit |
9eaa09 |
add_numa_node_to_topo_obj(cache, nodeid);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
return cache;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void do_one_cpu(char *path)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
struct topo_obj *cpu;
|
|
Packit |
9eaa09 |
FILE *file;
|
|
Packit |
9eaa09 |
char new_path[PATH_MAX];
|
|
Packit |
9eaa09 |
cpumask_t cache_mask, package_mask;
|
|
Packit |
9eaa09 |
struct topo_obj *cache;
|
|
Packit |
9eaa09 |
DIR *dir;
|
|
Packit |
9eaa09 |
struct dirent *entry;
|
|
Packit |
9eaa09 |
int nodeid;
|
|
Packit |
9eaa09 |
int packageid = 0;
|
|
Packit |
9eaa09 |
unsigned int max_cache_index, cache_index, cache_stat;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* skip offline cpus */
|
|
Packit |
9eaa09 |
snprintf(new_path, PATH_MAX, "%s/online", path);
|
|
Packit |
9eaa09 |
file = fopen(new_path, "r");
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
char *line = NULL;
|
|
Packit |
9eaa09 |
size_t size = 0;
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file)==0)
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
if (line && line[0]=='0') {
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu = calloc(sizeof(struct topo_obj), 1);
|
|
Packit |
9eaa09 |
if (!cpu)
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu->obj_type = OBJ_TYPE_CPU;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu->number = strtoul(&path[27], NULL, 10);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu_set(cpu->number, cpu_possible_map);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu_set(cpu->number, cpu->mask);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* Default the cache_domain mask to be equal to the cpu
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
cpus_clear(cache_mask);
|
|
Packit |
9eaa09 |
cpu_set(cpu->number, cache_mask);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* if the cpu is on the banned list, just don't add it */
|
|
Packit |
9eaa09 |
if (cpus_intersects(cpu->mask, banned_cpus)) {
|
|
Packit |
9eaa09 |
free(cpu);
|
|
Packit |
9eaa09 |
/* even though we don't use the cpu we do need to count it */
|
|
Packit |
9eaa09 |
core_count++;
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* try to read the package mask; if it doesn't exist assume solitary */
|
|
Packit |
9eaa09 |
snprintf(new_path, PATH_MAX, "%s/topology/core_siblings", path);
|
|
Packit |
9eaa09 |
file = fopen(new_path, "r");
|
|
Packit |
9eaa09 |
cpu_set(cpu->number, package_mask);
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
char *line = NULL;
|
|
Packit |
9eaa09 |
size_t size = 0;
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file))
|
|
Packit |
9eaa09 |
cpumask_parse_user(line, strlen(line), package_mask);
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
/* try to read the package id */
|
|
Packit |
9eaa09 |
snprintf(new_path, PATH_MAX, "%s/topology/physical_package_id", path);
|
|
Packit |
9eaa09 |
file = fopen(new_path, "r");
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
char *line = NULL;
|
|
Packit |
9eaa09 |
size_t size = 0;
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file))
|
|
Packit |
9eaa09 |
packageid = strtoul(line, NULL, 10);
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/* try to read the cache mask; if it doesn't exist assume solitary */
|
|
Packit |
9eaa09 |
/* We want the deepest cache level available */
|
|
Packit |
9eaa09 |
cpu_set(cpu->number, cache_mask);
|
|
Packit |
9eaa09 |
max_cache_index = 0;
|
|
Packit |
9eaa09 |
cache_index = 1;
|
|
Packit |
9eaa09 |
do {
|
|
Packit |
9eaa09 |
struct stat sb;
|
|
Packit |
9eaa09 |
snprintf(new_path, PATH_MAX, "%s/cache/index%d/shared_cpu_map", path, cache_index);
|
|
Packit |
9eaa09 |
cache_stat = stat(new_path, &sb);
|
|
Packit |
9eaa09 |
if (!cache_stat) {
|
|
Packit |
9eaa09 |
max_cache_index = cache_index;
|
|
Packit |
9eaa09 |
if (max_cache_index == deepest_cache)
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
cache_index ++;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
} while(!cache_stat);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (max_cache_index > 0) {
|
|
Packit |
9eaa09 |
snprintf(new_path, PATH_MAX, "%s/cache/index%d/shared_cpu_map", path, max_cache_index);
|
|
Packit |
9eaa09 |
file = fopen(new_path, "r");
|
|
Packit |
9eaa09 |
if (file) {
|
|
Packit |
9eaa09 |
char *line = NULL;
|
|
Packit |
9eaa09 |
size_t size = 0;
|
|
Packit |
9eaa09 |
if (getline(&line, &size, file))
|
|
Packit |
9eaa09 |
cpumask_parse_user(line, strlen(line), cache_mask);
|
|
Packit |
9eaa09 |
fclose(file);
|
|
Packit |
9eaa09 |
free(line);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
nodeid=-1;
|
|
Packit |
9eaa09 |
if (numa_avail) {
|
|
Packit |
9eaa09 |
struct topo_obj *node;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
dir = opendir(path);
|
|
Packit |
9eaa09 |
do {
|
|
Packit |
9eaa09 |
entry = readdir(dir);
|
|
Packit |
9eaa09 |
if (!entry)
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
if (strstr(entry->d_name, "node")) {
|
|
Packit |
9eaa09 |
nodeid = strtoul(&entry->d_name[4], NULL, 10);
|
|
Packit |
9eaa09 |
break;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
} while (entry);
|
|
Packit |
9eaa09 |
closedir(dir);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* In case of multiple NUMA nodes within a CPU package,
|
|
Packit |
9eaa09 |
* we override package_mask with node mask.
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
node = get_numa_node(nodeid);
|
|
Packit |
9eaa09 |
if (node && (cpus_weight(package_mask) > cpus_weight(node->mask)))
|
|
Packit |
9eaa09 |
cpus_and(package_mask, package_mask, node->mask);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
blank out the banned cpus from the various masks so that interrupts
|
|
Packit |
9eaa09 |
will never be told to go there
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
cpus_and(cache_mask, cache_mask, unbanned_cpus);
|
|
Packit |
9eaa09 |
cpus_and(package_mask, package_mask, unbanned_cpus);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cache = add_cpu_to_cache_domain(cpu, cache_mask, nodeid);
|
|
Packit |
9eaa09 |
add_cache_domain_to_package(cache, packageid, package_mask,
|
|
Packit |
9eaa09 |
nodeid);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpu->obj_type_list = &cpus;
|
|
Packit |
9eaa09 |
cpus = g_list_append(cpus, cpu);
|
|
Packit |
9eaa09 |
core_count++;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void dump_irq(struct irq_info *info, void *data)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
int spaces = (long int)data;
|
|
Packit |
9eaa09 |
int i;
|
|
Packit |
9eaa09 |
char * indent = malloc (sizeof(char) * (spaces + 1));
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
for ( i = 0; i < spaces; i++ )
|
|
Packit |
9eaa09 |
indent[i] = log_indent[0];
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
indent[i] = '\0';
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "%sInterrupt %i node_num is %d (%s/%lu:%lu) \n", indent,
|
|
Packit |
9eaa09 |
info->irq, irq_numa_node(info)->number, classes[info->class], info->load, (info->irq_count - info->last_irq_count));
|
|
Packit |
9eaa09 |
free(indent);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void dump_numa_node_num(struct topo_obj *p, void *data __attribute__((unused)))
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "%d ", p->number);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void dump_balance_obj(struct topo_obj *d, void *data __attribute__((unused)))
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
struct topo_obj *c = (struct topo_obj *)d;
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "%s%s%s%sCPU number %i numa_node is ",
|
|
Packit |
9eaa09 |
log_indent, log_indent, log_indent, log_indent, c->number);
|
|
Packit |
9eaa09 |
for_each_object(cpu_numa_node(c), dump_numa_node_num, NULL);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "(load %lu)\n", (unsigned long)c->load);
|
|
Packit |
9eaa09 |
if (c->interrupts)
|
|
Packit |
9eaa09 |
for_each_irq(c->interrupts, dump_irq, (void *)18);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void dump_cache_domain(struct topo_obj *d, void *data)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
char *buffer = data;
|
|
Packit |
9eaa09 |
cpumask_scnprintf(buffer, 4095, d->mask);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "%s%sCache domain %i: numa_node is ",
|
|
Packit |
9eaa09 |
log_indent, log_indent, d->number);
|
|
Packit |
9eaa09 |
for_each_object(d->numa_nodes, dump_numa_node_num, NULL);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "cpu mask is %s (load %lu) \n", buffer,
|
|
Packit |
9eaa09 |
(unsigned long)d->load);
|
|
Packit |
9eaa09 |
if (d->children)
|
|
Packit |
9eaa09 |
for_each_object(d->children, dump_balance_obj, NULL);
|
|
Packit |
9eaa09 |
if (g_list_length(d->interrupts) > 0)
|
|
Packit |
9eaa09 |
for_each_irq(d->interrupts, dump_irq, (void *)10);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void dump_package(struct topo_obj *d, void *data)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
char *buffer = data;
|
|
Packit |
9eaa09 |
cpumask_scnprintf(buffer, 4096, d->mask);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "Package %i: numa_node ", d->number);
|
|
Packit |
9eaa09 |
for_each_object(d->numa_nodes, dump_numa_node_num, NULL);
|
|
Packit |
9eaa09 |
log(TO_CONSOLE, LOG_INFO, "cpu mask is %s (load %lu)\n",
|
|
Packit |
9eaa09 |
buffer, (unsigned long)d->load);
|
|
Packit |
9eaa09 |
if (d->children)
|
|
Packit |
9eaa09 |
for_each_object(d->children, dump_cache_domain, buffer);
|
|
Packit |
9eaa09 |
if (g_list_length(d->interrupts) > 0)
|
|
Packit |
9eaa09 |
for_each_irq(d->interrupts, dump_irq, (void *)2);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
void dump_tree(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
char buffer[4096];
|
|
Packit |
9eaa09 |
for_each_object(packages, dump_package, buffer);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void clear_irq_stats(struct irq_info *info, void *data __attribute__((unused)))
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
info->load = 0;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static void clear_obj_stats(struct topo_obj *d, void *data __attribute__((unused)))
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
for_each_object(d->children, clear_obj_stats, NULL);
|
|
Packit |
9eaa09 |
for_each_irq(d->interrupts, clear_irq_stats, NULL);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* this function removes previous state from the cpu tree, such as
|
|
Packit |
9eaa09 |
* which level does how much work and the actual lists of interrupts
|
|
Packit |
9eaa09 |
* assigned to each component
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
void clear_work_stats(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
for_each_object(numa_nodes, clear_obj_stats, NULL);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
void parse_cpu_tree(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
DIR *dir;
|
|
Packit |
9eaa09 |
struct dirent *entry;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
setup_banned_cpus();
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
cpus_complement(unbanned_cpus, banned_cpus);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
dir = opendir("/sys/devices/system/cpu");
|
|
Packit |
9eaa09 |
if (!dir)
|
|
Packit |
9eaa09 |
return;
|
|
Packit |
9eaa09 |
do {
|
|
Packit |
9eaa09 |
int num;
|
|
Packit |
9eaa09 |
char pad;
|
|
Packit |
9eaa09 |
entry = readdir(dir);
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* We only want to count real cpus, not cpufreq and
|
|
Packit |
9eaa09 |
* cpuidle
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
if (entry &&
|
|
Packit |
9eaa09 |
sscanf(entry->d_name, "cpu%d%c", &num, &pad) == 1 &&
|
|
Packit |
9eaa09 |
!strchr(entry->d_name, ' ')) {
|
|
Packit |
9eaa09 |
char new_path[PATH_MAX];
|
|
Packit |
9eaa09 |
sprintf(new_path, "/sys/devices/system/cpu/%s", entry->d_name);
|
|
Packit |
9eaa09 |
do_one_cpu(new_path);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
} while (entry);
|
|
Packit |
9eaa09 |
closedir(dir);
|
|
Packit |
9eaa09 |
for_each_object(packages, connect_cpu_mem_topo, NULL);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
if (debug_mode)
|
|
Packit |
9eaa09 |
dump_tree();
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
/*
|
|
Packit |
9eaa09 |
* This function frees all memory related to a cpu tree so that a new tree
|
|
Packit |
9eaa09 |
* can be read
|
|
Packit |
9eaa09 |
*/
|
|
Packit |
9eaa09 |
void clear_cpu_tree(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
GList *item;
|
|
Packit |
9eaa09 |
struct topo_obj *cpu;
|
|
Packit |
9eaa09 |
struct topo_obj *cache_domain;
|
|
Packit |
9eaa09 |
struct topo_obj *package;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
while (packages) {
|
|
Packit |
9eaa09 |
item = g_list_first(packages);
|
|
Packit |
9eaa09 |
package = item->data;
|
|
Packit |
9eaa09 |
g_list_free(package->children);
|
|
Packit |
9eaa09 |
g_list_free(package->interrupts);
|
|
Packit |
9eaa09 |
g_list_free(package->numa_nodes);
|
|
Packit |
9eaa09 |
free(package);
|
|
Packit |
9eaa09 |
packages = g_list_delete_link(packages, item);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
package_count = 0;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
while (cache_domains) {
|
|
Packit |
9eaa09 |
item = g_list_first(cache_domains);
|
|
Packit |
9eaa09 |
cache_domain = item->data;
|
|
Packit |
9eaa09 |
g_list_free(cache_domain->children);
|
|
Packit |
9eaa09 |
g_list_free(cache_domain->interrupts);
|
|
Packit |
9eaa09 |
g_list_free(cache_domain->numa_nodes);
|
|
Packit |
9eaa09 |
free(cache_domain);
|
|
Packit |
9eaa09 |
cache_domains = g_list_delete_link(cache_domains, item);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
cache_domain_count = 0;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
while (cpus) {
|
|
Packit |
9eaa09 |
item = g_list_first(cpus);
|
|
Packit |
9eaa09 |
cpu = item->data;
|
|
Packit |
9eaa09 |
g_list_free(cpu->interrupts);
|
|
Packit |
9eaa09 |
free(cpu);
|
|
Packit |
9eaa09 |
cpus = g_list_delete_link(cpus, item);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
core_count = 0;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
static gint compare_cpus(gconstpointer a, gconstpointer b)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
const struct topo_obj *ai = a;
|
|
Packit |
9eaa09 |
const struct topo_obj *bi = b;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
return ai->number - bi->number;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
struct topo_obj *find_cpu_core(int cpunr)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
GList *entry;
|
|
Packit |
9eaa09 |
struct topo_obj find;
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
find.number = cpunr;
|
|
Packit |
9eaa09 |
entry = g_list_find_custom(cpus, &find, compare_cpus);
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
return entry ? entry->data : NULL;
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|
|
Packit |
9eaa09 |
int get_cpu_count(void)
|
|
Packit |
9eaa09 |
{
|
|
Packit |
9eaa09 |
return g_list_length(cpus);
|
|
Packit |
9eaa09 |
}
|
|
Packit |
9eaa09 |
|