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.
37 * Tests for gmx::HardwareTopology
39 * \author Erik Lindahl <erik.lindahl@gmail.com>
40 * \ingroup module_hardware
44 #include "gromacs/hardware/hardwaretopology.h"
50 #include <gtest/gtest.h>
55 // There is no way we can compare to any reference data since that
56 // depends on the architecture, but we can at least make sure that it
57 // works to execute the tests and that they are self-consistent
59 // Although it is not strictly an error, for the very basic execution tests
60 // we also report if we cannot extract the hardware topology on systems
61 // where we expect to be able to. Since this might happen to users, we
62 // provide a bit more information and ask them to mail us in this case.
64 TEST(HardwareTopologyTest
, Execute
)
66 // There is no way we can compare to any reference data since that
67 // depends on the architecture, but we can at least make sure that it
68 // works to execute the tests
70 gmx::HardwareTopology
hwTop(gmx::HardwareTopology::detect());
72 // If we cannot even find the number of logical processors we want to flag it
73 EXPECT_GT(hwTop
.supportLevel(), gmx::HardwareTopology::SupportLevel::None
)
74 << "Cannot determine number of processors. " << std::endl
75 << "GROMACS might still work, but it will likely hurt your performance." << std::endl
76 << "Please mail gmx-developers@gromacs.org so we can try to fix it.";
80 TEST(HardwareTopologyTest
, HwlocExecute
)
82 #if defined(__linux__)
83 gmx::HardwareTopology
hwTop(gmx::HardwareTopology::detect());
85 // On Linux with hwloc support we should be able to get at least basic information
86 EXPECT_GE(hwTop
.supportLevel(), gmx::HardwareTopology::SupportLevel::Basic
)
87 << "Cannot determine basic hardware topology from hwloc. GROMACS will still\n" << std::endl
88 << "work, but it might affect your performance for large nodes." << std::endl
89 << "Please mail gmx-developers@gromacs.org so we can try to fix it.";
94 TEST(HardwareTopologyTest
, ProcessorSelfconsistency
)
96 gmx::HardwareTopology
hwTop(gmx::HardwareTopology::detect());
98 if (hwTop
.supportLevel() >= gmx::HardwareTopology::SupportLevel::Basic
)
100 int socketsInMachine
= hwTop
.machine().sockets
.size();
101 int coresPerSocket
= hwTop
.machine().sockets
[0].cores
.size();
102 int hwThreadsPerCore
= hwTop
.machine().sockets
[0].cores
[0].hwThreads
.size();
104 // Check that logical processor information is reasonable
105 for (auto &l
: hwTop
.machine().logicalProcessors
)
107 EXPECT_TRUE(l
.socketRankInMachine
>= 0 && l
.socketRankInMachine
< socketsInMachine
);
108 EXPECT_TRUE(l
.coreRankInSocket
>= 0 && l
.coreRankInSocket
< coresPerSocket
);
109 EXPECT_TRUE(l
.hwThreadRankInCore
>= 0 && l
.hwThreadRankInCore
< hwThreadsPerCore
);
112 // Double-check that the tree is self-consistent with logical processor info
113 for (int s
= 0; s
< socketsInMachine
; s
++)
115 for (int c
= 0; c
< coresPerSocket
; c
++)
117 for (int t
= 0; t
< hwThreadsPerCore
; t
++)
119 int idx
= hwTop
.machine().sockets
[s
].cores
[c
].hwThreads
[t
].logicalProcessorId
;
120 EXPECT_LT(idx
, hwTop
.machine().logicalProcessorCount
);
121 EXPECT_EQ(hwTop
.machine().logicalProcessors
[idx
].socketRankInMachine
, s
);
122 EXPECT_EQ(hwTop
.machine().logicalProcessors
[idx
].coreRankInSocket
, c
) << "logical:" << idx
;
123 EXPECT_EQ(hwTop
.machine().logicalProcessors
[idx
].hwThreadRankInCore
, t
);
130 TEST(HardwareTopologyTest
, NumaCacheSelfconsistency
)
132 gmx::HardwareTopology
hwTop(gmx::HardwareTopology::detect());
134 if (hwTop
.supportLevel() >= gmx::HardwareTopology::SupportLevel::Full
)
136 // Check that numa node id corresponds to rank
137 for (std::size_t i
= 0; i
< hwTop
.machine().numa
.nodes
.size(); i
++)
139 EXPECT_EQ(hwTop
.machine().numa
.nodes
[i
].id
, i
);
142 // Check that the sum of numa domains is the total processor count
143 int processorsinNumaNudes
= 0;
144 for (auto &n
: hwTop
.machine().numa
.nodes
)
146 processorsinNumaNudes
+= n
.logicalProcessorId
.size();
148 EXPECT_EQ(processorsinNumaNudes
, hwTop
.machine().logicalProcessorCount
);
150 // Check that every processor is in a numa domain (i.e., that they are unique)
151 std::vector
<int> v(hwTop
.machine().logicalProcessorCount
);
156 for (auto &n
: hwTop
.machine().numa
.nodes
)
158 for (auto &idx
: n
.logicalProcessorId
)
163 int uniqueProcessorsinNumaNudes
= std::count(v
.begin(), v
.end(), 1);
164 EXPECT_EQ(uniqueProcessorsinNumaNudes
, hwTop
.machine().logicalProcessorCount
);
166 // We must have some memory in a numa node
167 for (auto &n
: hwTop
.machine().numa
.nodes
)
169 EXPECT_GT(n
.memory
, 0);
172 // Check latency matrix size and contents
173 EXPECT_GT(hwTop
.machine().numa
.baseLatency
, 0);
174 EXPECT_GT(hwTop
.machine().numa
.maxRelativeLatency
, 0);
175 // Check number of rows matches # numa nodes
176 EXPECT_EQ(hwTop
.machine().numa
.relativeLatency
.size(), hwTop
.machine().numa
.nodes
.size());
177 for (auto &v2
: hwTop
.machine().numa
.relativeLatency
)
179 // Check that size of each row matches # numa nodes
180 EXPECT_EQ(v2
.size(), hwTop
.machine().numa
.nodes
.size());
181 for (auto &latency
: v2
)
183 // Latency values should be positive
184 EXPECT_GT(latency
, 0);
188 // Check cache. The hwloc cache detection is fragile and can report
189 // 0 for line size or associativity (=unknown), so we just check the size.
190 for (auto &c
: hwTop
.machine().caches
)
192 EXPECT_GT(c
.size
, 0);