2
0

Initial support for POWER platforms

Tested on Talos II with Vega 64

POWER systems allocate NUMA nodes on multiples of 8 to allow CPU
onlining / offlining
Set the correct NUMA mask bits when requesting node-bound memory
allocations

This is a cleanup/squash/rebase of:
https://github.com/RadeonOpenCompute/ROCT-Thunk-Interface/pull/47

Change-Id: Id4af6dff7e66e9d464d6b17a1e99087eb3ac8e51
Signed-off-by: Jeremy Newton <Jeremy.Newton@amd.com>


[ROCm/ROCR-Runtime commit: 5fd3c868b2]
Este cometimento está contido em:
Timothy Pearson
2019-11-23 20:09:55 -05:00
cometido por Jeremy Newton
ascendente 3672168b7d
cometimento 7a601bb339
2 ficheiros modificados com 91 adições e 14 eliminações
+4
Ver ficheiro
@@ -1514,7 +1514,11 @@ static int bind_mem_to_numa(uint32_t node_id, void *mem,
if (!node_mask)
return -ENOMEM;
#ifdef __PPC64__
numa_bitmask_setbit(node_mask, node_id * 8);
#else
numa_bitmask_setbit(node_mask, node_id);
#endif
mode |= mflags.ui32.NoSubstitute ? MPOL_BIND : MPOL_PREFERRED;
r = mbind(mem, SizeInBytes, mode, node_mask->maskp, num_node + 1, 0);
numa_bitmask_free(node_mask);
+87 -14
Ver ficheiro
@@ -1,5 +1,6 @@
/*
* Copyright © 2014 Advanced Micro Devices, Inc.
* Copyright 2016-2018 Raptor Engineering, LLC. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -76,12 +77,14 @@ static int processor_vendor = -1;
/* Supported System Vendors */
enum SUPPORTED_PROCESSOR_VENDORS {
GENUINE_INTEL = 0,
AUTHENTIC_AMD
AUTHENTIC_AMD,
IBM_POWER
};
/* Adding newline to make the search easier */
static const char *supported_processor_vendor_name[] = {
"GenuineIntel\n",
"AuthenticAMD\n"
"AuthenticAMD\n",
"\n" // POWER requires a different search method
};
static HSAKMT_STATUS topology_take_snapshot(void);
@@ -497,6 +500,13 @@ static int get_cpu_cache_info(const char *prefix, struct proc_cpuinfo *cpuinfo,
int idx, num_idx, n;
HsaCacheProperties *this_cache;
char path[256], str[256];
bool is_power9 = false;
if (processor_vendor == IBM_POWER) {
if (strcmp(cpuinfo[0].model_name, "POWER9") == 0) {
is_power9 = true;
}
}
this_cache = cpu_ci->cache_prop;
num_idx = cpu_ci->num_caches;
@@ -504,19 +514,27 @@ static int get_cpu_cache_info(const char *prefix, struct proc_cpuinfo *cpuinfo,
/* If this cache is shared by multiple CPUs, we only need
* to list it in the first CPU.
*/
snprintf(path, 256, "%s/index%d/shared_cpu_list", prefix, idx);
/* shared_cpu_list is shown as n1,n2... or n1-n2,n3-n4...
* For both cases, this cache is listed to proc n1 only.
*/
fscanf_dec(path, (uint32_t *)&n);
if (cpu_ci->proc_num != n) {
/* proc is not n1. Skip and reduce the cache count. */
--cpu_ci->num_caches;
continue;
if (is_power9) {
// POWER9 has SMT4
if (cpu_ci->proc_num & 0x3) {
/* proc is not 0,4,8,etc. Skip and reduce the cache count. */
--cpu_ci->num_caches;
continue;
}
} else {
snprintf(path, 256, "%s/index%d/shared_cpu_list", prefix, idx);
/* shared_cpu_list is shown as n1,n2... or n1-n2,n3-n4...
* For both cases, this cache is listed to proc n1 only.
*/
fscanf_dec(path, (uint32_t *)&n);
if (cpu_ci->proc_num != n) {
/* proc is not n1. Skip and reduce the cache count. */
--cpu_ci->num_caches;
continue;
}
this_cache->ProcessorIdLow = cpuinfo[cpu_ci->proc_num].apicid;
}
this_cache->ProcessorIdLow = cpuinfo[cpu_ci->proc_num].apicid;
/* CacheLevel */
snprintf(path, 256, "%s/index%d/level", prefix, idx);
fscanf_dec(path, &this_cache->CacheLevel);
@@ -845,6 +863,8 @@ static int topology_search_processor_vendor(const char *processor_name)
for (i = 0; i < ARRAY_LEN(supported_processor_vendor_name); i++) {
if (!strcmp(processor_name, supported_processor_vendor_name[i]))
return i;
if (!strcmp(processor_name, "POWER9, altivec supported\n"))
return IBM_POWER;
}
return -1;
}
@@ -877,6 +897,52 @@ static HSAKMT_STATUS topology_parse_cpuinfo(struct proc_cpuinfo *cpuinfo,
return HSAKMT_STATUS_ERROR;
}
#ifdef __PPC64__
char *p2;
/* Each line in /proc/cpuinfo that read_buf is constructed, the format
* is like this:
* "token : value\n"
* where token is our target like vendor_id, model name, apicid ...
* and value is the answer
*/
while (fgets(read_buf, sizeof(read_buf), fd)) {
/* processor number */
if (!strncmp("processor ", read_buf, sizeof("processor ") - 1)) {
p = strchr(read_buf, ':');
p += 2; /* remove ": " */
proc = atoi(p);
if (proc >= num_procs) {
pr_warn("cpuinfo contains processor %d larger than %u\n",
proc, num_procs);
ret = HSAKMT_STATUS_NO_MEMORY;
goto exit;
}
continue;
}
/* vendor name / model name */
if (!strncmp("cpu ", read_buf, sizeof("cpu ") - 1) &&
(processor_vendor == -1)) {
p = strchr(read_buf, ':');
p += 2; /* remove ": " */
processor_vendor = topology_search_processor_vendor(p);
p2 = strchr(p, ',');
if (p2 != NULL) {
p2++;
*p2 = 0;
}
if (strlen(p) < HSA_PUBLIC_NAME_SIZE) {
/* -1 to remove \n from p */
strncpy(cpuinfo[proc].model_name, p, strlen(p) - 1);
cpuinfo[proc].model_name[strlen(p) - 1] = '\0';
} else
strncpy(cpuinfo[proc].model_name, p, HSA_PUBLIC_NAME_SIZE);
continue;
}
}
#else
/* Each line in /proc/cpuinfo that read_buf is constructed, the format
* is like this:
* "token : value\n"
@@ -926,6 +992,7 @@ static HSAKMT_STATUS topology_parse_cpuinfo(struct proc_cpuinfo *cpuinfo,
cpuinfo[proc].apicid = atoi(p);
}
}
#endif
if (processor_vendor < 0) {
pr_err("Failed to get Processor Vendor. Setting to %s",
@@ -1289,7 +1356,13 @@ static int topology_create_temp_cpu_cache_list(int node,
*temp_cpu_ci_list = NULL;
/* Get info from /sys/devices/system/node/nodeX/cpuY/cache */
snprintf(node_dir, MAXPATHSIZE, "/sys/devices/system/node/node%d", node);
int node_real = node;
if (processor_vendor == IBM_POWER) {
if (!strcmp(cpuinfo[0].model_name, "POWER9")) {
node_real = node * 8;
}
}
snprintf(node_dir, MAXPATHSIZE, "/sys/devices/system/node/node%d", node_real);
/* Other than cpuY folders, this dir also has cpulist and cpumap */
max_cpus = num_subdirs(node_dir, "cpu");
if (max_cpus <= 0) {