1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
/*
* Copyright © 2018-2020 Inria. All rights reserved.
* See COPYING in top-level directory.
*/
#include <private/autogen/config.h>
#include <private/private.h>
#include <hwloc.h>
#include <hwloc/shmem.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "lstopo.h"
struct lstopo_shmem_header {
#define LSTOPO_SHMEM_HEADER_VERSION 1U
uint32_t header_version;
uint32_t header_length;
uint64_t mmap_address;
uint64_t mmap_length;
uint64_t file_offset;
};
extern uint64_t shmem_output_addr;
#ifndef MAP_ANONYMOUS /* for Mac OS X 9 */
#define MAP_ANONYMOUS MAP_ANON
#endif
static unsigned long
find_mmap_addr(unsigned long length)
{
unsigned long addr;
void *tmp_mmap;
int err;
/* try to find a good address starting from something in the middle of the entire/full address space */
#if SIZEOF_VOID_P == 8
addr = 0x8000000000000000UL;
#else
addr = 0x80000000UL;
#endif
printf("Testing mmaps to find room for length %lu\n", length);
again:
tmp_mmap = mmap((void*)(uintptr_t)addr, length, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
if (tmp_mmap != MAP_FAILED) {
err = munmap((void*)(uintptr_t)tmp_mmap, length);
assert(!err);
if (tmp_mmap == (void*)(uintptr_t) addr) {
/* worked! */
printf(" test mmap at 0x%lx succeeded, let's use that!\n", addr);
return addr;
}
printf(" test mmap at 0x%lx returned another address\n", addr);
} else
printf(" test mmap at 0x%lx failed (errno %d)\n", addr, errno);
/* couldn't map there, try again with a smaller address */
addr >>= 1;
if (addr)
goto again;
return 0;
}
int
output_shmem(struct lstopo_output *loutput, const char *filename)
{
struct lstopo_shmem_header header;
size_t shmem_length;
struct stat st;
int fd, err;
if (!filename || !strcasecmp(filename, "-.shmem")) {
fprintf(stderr, "Cannot export shmem topology to stdout.\n");
return -1;
}
if (!stat(filename, &st) && !loutput->overwrite) {
fprintf(stderr, "Failed to export shmem topology to %s (%s)\n", filename, strerror(EEXIST));
return -1;
}
err = hwloc_shmem_topology_get_length(loutput->topology, &shmem_length, 0);
if (err < 0) {
if (errno == ENOSYS)
fprintf(stderr, "shmem topology not supported\n"); /* this line must match the grep line in test-lstopo-shmem */
else
fprintf(stderr, "Failed to compute shmem topology export length\n");
return -1;
}
fd = open(filename, O_RDWR|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR);
if (fd < 0) {
fprintf(stderr, "Failed to open shmem topology file %s (%s)\n", filename, strerror(errno));
return -1;
}
if (!loutput->shmem_output_addr)
loutput->shmem_output_addr = find_mmap_addr(shmem_length);
if (!loutput->shmem_output_addr) {
fprintf(stderr, "Failed to find a shmem topology mmap address\n"); /* this line must match the grep line in test-lstopo-shmem */
close(fd);
unlink(filename);
return -1;
}
header.header_version = LSTOPO_SHMEM_HEADER_VERSION;
header.header_length = sizeof(header);
header.mmap_address = loutput->shmem_output_addr;
header.mmap_length = shmem_length;
header.file_offset = hwloc_getpagesize();
err = write(fd, &header, sizeof(header));
if (err != sizeof(header)) {
fprintf(stderr, "Failed to write shmem topology header\n");
close(fd);
unlink(filename);
return -1;
}
if (hwloc_shmem_topology_write(loutput->topology, fd, header.file_offset, (void*)(uintptr_t)loutput->shmem_output_addr, shmem_length, 0) < 0) {
if (errno == EBUSY)
fprintf(stderr, "Failed to export shmem topology, memory range is busy\n"); /* this line must match the grep line in test-lstopo-shmem */
else
fprintf(stderr, "Failed to export shmem topology to %s (%s)\n", filename, strerror(errno));
close(fd);
unlink(filename);
return -1;
}
close(fd);
printf("Exported shmem topology to %s for mmap address 0x%llx length %lu\n", filename, (unsigned long long) loutput->shmem_output_addr, (unsigned long) shmem_length);
return 0;
}
int lstopo_shmem_adopt(const char *input, hwloc_topology_t *topologyp)
{
hwloc_topology_t adopted;
struct lstopo_shmem_header header;
int fd, err;
fd = open(input, O_RDONLY);
if (fd < 0)
return -1;
err = read(fd, &header, sizeof(header));
if (err < (int) sizeof(header)) {
fprintf(stderr, "Failed to read shmem topology header\n");
close(fd);
return -1;
}
if (header.header_version != LSTOPO_SHMEM_HEADER_VERSION
|| header.header_length != sizeof(header)) {
fprintf(stderr, "Unexpected shmem topology header version %u length %u (instead of %u %u)\n",
header.header_version, header.header_length,
LSTOPO_SHMEM_HEADER_VERSION, (unsigned) sizeof(header));
close(fd);
return -1;
}
err = hwloc_shmem_topology_adopt(&adopted, fd, header.file_offset, (void*)(uintptr_t)header.mmap_address, header.mmap_length, 0);
close(fd);
if (err < 0) {
if (errno == EBUSY)
fprintf(stderr, "Failed to adopt shmem topology, memory range is busy\n"); /* this line must match the grep line in test-lstopo-shmem */
else
fprintf(stderr, "Failed to adopt shmem topology (%s)\n", strerror(errno));
return -1;
}
err = hwloc_topology_dup(topologyp, adopted);
hwloc_topology_destroy(adopted);
if (err < 0) {
fprintf(stderr, "Failed to duplicate adopted shmem topology (%s)\n", strerror(errno));
return -1;
}
return 0;
}
|