-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhwloc_wrap.h
114 lines (93 loc) · 3.2 KB
/
hwloc_wrap.h
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
/**
* This file is part of mpi-cache-bench.
*
* mpi-cache-bench is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* mpi-cache-bench is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with mpi-cache-bench. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
/**
* When the benchmark is compiled with HWLOC support then we use the library to detect
* information of the underlying CPU, like the amount of cache for each level of
* available caches and the number of sockets and cores available on the machine
*/
#ifdef USE_HWLOC
#include <hwloc.h>
#endif
#include <cstring>
void usage(char* argv[]) {
std::cerr << "Argument error, usage: " << argv[0] <<
" SOCKETS_PER_NODE CPU_CORES_PER_NODE LAST_LEVEL_CACHE" << std::endl
<< "\tLAST_LEVEL_CACHE format: XX, XXK, XXM, XXG (where X is a digit)"
<< std::endl;
exit(1);
}
#define MAX_CACHE_LEVELS 10
// Stores the number of cores / sockets and the cache size exclusive to each process
struct Info {
unsigned num_cores;
unsigned num_sockets;
unsigned levels;
// For each level contains the size of the cache at that level
size_t* cache_sizes;
Info(int argc, char* argv[]) : levels(0) {
#ifndef USE_HWLOC
if (argc != 4) { usage(argv); }
num_sockets = atoi(argv[1]);
num_cores = atoi(argv[2]);
levels=1;
cache_sizes = new size_t[1];
char* size_str = argv[3];
unsigned multiplier = 1;
char* last = &size_str[strlen(size_str)-1];
if (!(*last >=0 && *last <= 9)) {
switch (*last) {
case 'G': multiplier *= 1024;
case 'M': multiplier *= 1024;
case 'K': multiplier *= 1024;
break;
default:
std::cerr << "Wrong quantifer, allowed quantifiers are: 'K' (1024), 'M' (1024K), 'G' (1024M)";
usage(argv);
}
}
*last = '\0';
cache_sizes[0] = atoi(size_str) * multiplier;
#endif
#ifdef USE_HWLOC
hwloc_topology_t topology;
// Allocate and initialize topology object.
hwloc_topology_init(&topology);
hwloc_topology_load(topology);
int depth = hwloc_get_type_or_below_depth(topology, HWLOC_OBJ_SOCKET);
num_sockets = hwloc_get_nbobjs_by_depth(topology, depth);
depth = hwloc_get_type_or_below_depth(topology, HWLOC_OBJ_PU); // logical CPU
num_cores = hwloc_get_nbobjs_by_depth(topology, depth);
size_t size[MAX_CACHE_LEVELS];
for (hwloc_obj_t obj = hwloc_get_obj_by_type(topology, HWLOC_OBJ_PU, 0);
obj;
obj = obj->parent)
if (obj->type == HWLOC_OBJ_CACHE) {
assert( levels < MAX_CACHE_LEVELS && "This architecture has more than 3 cache levels");
size[levels++] = obj->attr->cache.size;
}
hwloc_topology_destroy(topology);
cache_sizes = new size_t[levels];
memcpy(cache_sizes, size, levels*sizeof(size_t));
#endif
}
~Info() {
delete[] cache_sizes;
}
private:
Info(const Info& other) { } // make it not copyable
};