Hardware detection clean-up and pre/post-processing
[gromacs.git] / src / gromacs / hardware / hardwaretopology.h
blobf766a4d695d9eeb4266a5a1eac1ff069d6276f20
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2016, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \libinternal \file
36 * \brief
37 * Declares gmx::HardwareTopology
39 * \author Erik Lindahl <erik.lindahl@gmail.com>
40 * \inlibraryapi
41 * \ingroup module_hardware
43 #ifndef GMX_HARDWARE_HARDWARETOPOLOGY_H
44 #define GMX_HARDWARE_HARDWARETOPOLOGY_H
46 #include <cstdint>
48 #include <vector>
50 namespace gmx
53 /*! \libinternal \brief Information about sockets, cores, threads, numa, caches
55 * This class is the main GROMACS interface to provide information about the
56 * hardware of the system we are running on. Internally, it uses either
57 * hwloc for full or almost-full information, or a fallback implementation
58 * that relies on CpuInfo on x86.
60 * You should always use this class (rather than CpuInfo directly) to query
61 * the hardware layout in user code. Note that you cannot rely on any
62 * information being present, but you must check with the supportLevel()
63 * method before trying to access any information.
65 class HardwareTopology
67 public:
69 /*! \brief Amount of topology information present (incremental) */
70 enum class SupportLevel
72 None, //!< No hardware information whatsoever. Sorry.
73 LogicalProcessorCount, //!< Only machine().logicalProcessorCount is valid
74 Basic, //!< Socket, core and hardware thread info
75 Full, //!< Cache, memory and numa node info
76 FullWithDevices //!< Information about devices on the PCI bus
79 /*! \libinternal \brief Information about a single cache level */
80 struct Cache
82 int level; //!< Level relative to core (starts at 1)
83 std::size_t size; //!< size in bytes, 0 if unknown
84 int linesize; //!< size of each cache line in bytes, 0 if unknown
85 int associativity; //!< associativity, -1 means fully associative
86 int shared; //!< Number of logical processors sharing this cache
89 /*! \libinternal \brief Information about a single hardware thread in a core
91 * The id of the thread typically increases continuously as you walk
92 * through sockets and cores in order of their ids. In general, this can
93 * be different from the logical processor id provided by the operating
94 * system. To achieve better load balancing when using SMT, Linux
95 * typically assigns logical processors in a round-robin fashion
96 * over all cores.
98 struct HWThread
100 int id; //!< Absolute id of this thread in hardware topology
101 int logicalProcessorId; //!< Id of the operating system logical processor
104 /*! \libinternal \brief Information about a single core in a socket */
105 struct Core
107 int id; //!< Absolute id of this core in hardware topology
108 int numaNodeId; //!< id of the numa node of this core
109 std::vector<HWThread> hwThreads; //!< All the hardware threads in this core
112 /*! \libinternal \brief Information about a single socket in the system */
113 struct Socket
115 int id; //!< Absolute id of this socket in hardware topology
116 std::vector<Core> cores; //!< All the cores in this socket
119 /*! \libinternal \brief Information about each numa node in system */
120 struct NumaNode
122 int id; //!< Absolute id of numa node in hardware topology
123 std::size_t memory; //!< Total detected memory in bytes
124 std::vector<int> logicalProcessorId; //!< Vector of all the logical processors in this node
127 /*! \libinternal \brief Information about a single numa node */
128 struct Numa
130 std::vector<NumaNode> nodes; //!< Information about each numa node
131 float baseLatency; //!< Scale factor for relative latencies
132 std::vector< std::vector<float> > relativeLatency; //!< 2D matrix of relative latencies between nodes
133 float maxRelativeLatency; //!< Largest relative latency
136 /*! \libinternal \brief Information about a single PCI device.
138 * \note On many systems the PCI bus is not directly connected to any numa node.
139 * For these systems the numaNodeId will be -1, so you cannot rely on this
140 * number reflecting a specific numa node.
142 struct Device
144 std::uint16_t vendorId; //!< Vendor identification
145 std::uint16_t deviceId; //!< Vendor-specific device identification
146 std::uint16_t classId; //!< class (high 8 bits) and subclass (low 8 bits)
147 std::uint16_t domain; //!< Domain, usually 0 for PCI bus
148 std::uint8_t bus; //!< Bus number in domain
149 std::uint8_t dev; //!< Device on bus
150 std::uint8_t func; //!< Function id for multi-function devices
151 int numaNodeId; //!< Numa node, -1 if the bus is not located inside a node
154 /*! \libinternal \brief Information about socket, core and hwthread for a logical processor */
155 struct LogicalProcessor
157 int socketRankInMachine; //!< Index of socket in machine
158 int coreRankInSocket; //!< Index of core in socket
159 int hwThreadRankInCore; //!< Index of hardware thread in core
160 int numaNodeId; //!< Index of numa node
163 /*! \libinternal \brief Hardware topology information about the entire machine
165 * The machine structure is a tree with top-down information about all
166 * sockets, cores, and hardware threads in the system. For example, an
167 * operating system logical processor index can be found as
168 * machine.socket[0].core[1].hwthread[2].logicalProcessorId.
169 * In some cases you might need the opposite lookup, i.e. the physical
170 * hardware data for a specific logical processor. This is present in the
171 * logicalProcessor vector for convenience.
173 * \note The logicalProcessor vector will only have non-zero length if the
174 * support level is SupportLevel::Basic or higher. You cannot use the
175 * size of this vector to query the number of logical processors on
176 * lower support levels.
178 struct Machine
180 int logicalProcessorCount; //!< Number of logical processors in system
181 std::vector<LogicalProcessor> logicalProcessors; //!< Map logical processors to socket/core
182 std::vector<Socket> sockets; //!< All the sockets in the system
183 std::vector<Cache> caches; //!< Caches in increasing level order
184 Numa numa; //!< Structure with all numa information
185 std::vector<Device> devices; //!< Devices on PCI bus
188 public:
190 /*! \brief Detects the hardware topology. */
191 static HardwareTopology detect();
193 /*! \brief Check what topology information that is available and valid
195 * The amount of hardware topology information that can be detected depends
196 * on both the hardware and whether GROMACS was linked with the external
197 * hwloc library. You cannot assume that any information is present,
198 * although we can almost always provide the number of logical processors.
199 * On x86 we can usually get basic information about how sockets, cores
200 * and hardware threads are ordered even without hwloc.
201 * With the hwloc library we can usually also get information about cache,
202 * memory and concepts such as core groups and ccNUMA nodes.
203 * Finally, if hwloc was built with support for libpci we can also
204 * detect how the PCI devices are connected.
206 SupportLevel
207 supportLevel() const { return supportLevel_; }
209 /*! \brief Return true if we actually detected hardware.
211 * \return This method will normally return true, when we actually ran
212 * the hardware detection as part of this process to construct
213 * the object. It will be false when the object was constructed
214 * by reading a cached XML file, or possibly generated from
215 * synthetic data.
217 bool
218 isThisSystem() const { return isThisSystem_; }
220 /*! \brief Return the machine topology tree
222 * You can always call this routine, but be aware that some or all contents
223 * will not be valid unless supportLevel() returns a sufficient level.
225 * - With SupportLevel::LogicalProcessorCount, only the field
226 * machine.logicalProcessorCount is valid.
227 * - With SupportLevel::Basic, you can access the vectors of sockets,
228 * cores, and hardware threads, and query what logical processorId
229 * each hardware thread corresponds to.
230 * - SupportLevel::Full adds cache, memory and ccNUMA information.
231 * - SupportLevel::FullWithDevices also adds the PCI express bus.
233 * While data that is not valid has been initialized to special values,
234 * you should not rely on those but query the supportLevel() method before
235 * accessing it.
237 const Machine &
238 machine() const { return machine_; }
240 /*! \brief Returns the number of cores.
242 * You can always call this routine, but if sufficient support is not
243 * available, it may return the logical processor count or zero instead
244 * of the physical core count.
246 int numberOfCores() const;
248 private:
250 HardwareTopology();
252 SupportLevel supportLevel_; //!< Available topology information
253 Machine machine_; //!< The machine map
254 bool isThisSystem_; //!< Machine map is real (vs. cached/synthetic)
259 #endif // GMX_HARDWARE_HARDWARETOPOLOGY_H