Hardware detection clean-up and pre/post-processing
[gromacs.git] / src / gromacs / hardware / tests / hardwaretopology.cpp
blobed7897b015c2ba785dd935d566aa9d12352485de
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 /*! \internal \file
36 * \brief
37 * Tests for gmx::HardwareTopology
39 * \author Erik Lindahl <erik.lindahl@gmail.com>
40 * \ingroup module_hardware
42 #include "gmxpre.h"
44 #include "gromacs/hardware/hardwaretopology.h"
46 #include "config.h"
48 #include <algorithm>
50 #include <gtest/gtest.h>
52 namespace
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.";
79 #if GMX_HWLOC
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.";
90 #endif
92 #endif
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);
152 for (auto &elem : v)
154 elem = 0;
156 for (auto &n : hwTop.machine().numa.nodes)
158 for (auto &idx : n.logicalProcessorId)
160 v[idx] = 1;
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);
198 } // namespace