xref: /llvm-project/llvm/unittests/tools/llvm-exegesis/X86/SubprocessMemoryTest.cpp (revision fac87b889c50f493ba332950f613fa15a45be9a9)
1 //===-- SubprocessMemoryTest.cpp --------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "SubprocessMemory.h"
10 
11 #include "X86/TestBase.h"
12 #include "gtest/gtest.h"
13 #include <string>
14 #include <unordered_map>
15 
16 #ifdef __linux__
17 #include <endian.h>
18 #include <fcntl.h>
19 #include <sys/mman.h>
20 #include <sys/syscall.h>
21 #include <unistd.h>
22 #endif // __linux__
23 
24 namespace llvm {
25 namespace exegesis {
26 
27 #if defined(__linux__) && !defined(__ANDROID__) &&                             \
28     !(defined(__powerpc__) || defined(__s390x__) || defined(__sparc__))
29 
30 // This needs to be updated anytime a test is added or removed from the test
31 // suite.
32 static constexpr const size_t TestCount = 4;
33 
34 class SubprocessMemoryTest : public X86TestBase {
35 protected:
36   int getSharedMemoryNumber(const unsigned TestNumber) {
37     // Do a process similar to 2D array indexing so that each process gets it's
38     // own shared memory space to avoid collisions. This will not overflow as
39     // the maximum value a PID can take on is 10^22.
40     return getpid() * TestCount + TestNumber;
41   }
42 
43   void
44   testCommon(std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
45              const unsigned TestNumber) {
46     EXPECT_FALSE(
47         SM.initializeSubprocessMemory(getSharedMemoryNumber(TestNumber)));
48     EXPECT_FALSE(SM.addMemoryDefinition(MemoryDefinitions,
49                                         getSharedMemoryNumber(TestNumber)));
50   }
51 
52   std::string getSharedMemoryName(const unsigned TestNumber,
53                                   const unsigned DefinitionNumber) {
54     long CurrentTID = syscall(SYS_gettid);
55     return "/" + std::to_string(getSharedMemoryNumber(TestNumber)) + "t" +
56            std::to_string(CurrentTID) + "memdef" +
57            std::to_string(DefinitionNumber);
58   }
59 
60   void checkSharedMemoryDefinition(const std::string &DefinitionName,
61                                    size_t DefinitionSize,
62                                    std::vector<uint8_t> ExpectedValue) {
63     int SharedMemoryFD =
64         shm_open(DefinitionName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
65     uint8_t *SharedMemoryMapping = (uint8_t *)mmap(
66         NULL, DefinitionSize, PROT_READ, MAP_SHARED, SharedMemoryFD, 0);
67     EXPECT_NE(reinterpret_cast<intptr_t>(SharedMemoryMapping), -1);
68     for (size_t I = 0; I < ExpectedValue.size(); ++I) {
69       EXPECT_EQ(SharedMemoryMapping[I], ExpectedValue[I]);
70     }
71     munmap(SharedMemoryMapping, DefinitionSize);
72   }
73 
74   SubprocessMemory SM;
75 };
76 
77 // Some of the tests below are failing on s390x and PPC due to the shared
78 // memory calls not working in some cases, so they have been disabled.
79 // TODO(boomanaiden154): Investigate and fix this issue on PPC.
80 
81 TEST_F(SubprocessMemoryTest, OneDefinition) {
82   testCommon({{"test1", {APInt(8, 0xff), 4096, 0}}}, 0);
83   checkSharedMemoryDefinition(getSharedMemoryName(0, 0), 4096, {0xff});
84 }
85 
86 TEST_F(SubprocessMemoryTest, MultipleDefinitions) {
87   testCommon({{"test1", {APInt(8, 0xaa), 4096, 0}},
88               {"test2", {APInt(8, 0xbb), 4096, 1}},
89               {"test3", {APInt(8, 0xcc), 4096, 2}}},
90              1);
91   checkSharedMemoryDefinition(getSharedMemoryName(1, 0), 4096, {0xaa});
92   checkSharedMemoryDefinition(getSharedMemoryName(1, 1), 4096, {0xbb});
93   checkSharedMemoryDefinition(getSharedMemoryName(1, 2), 4096, {0xcc});
94 }
95 
96 TEST_F(SubprocessMemoryTest, DefinitionFillsCompletely) {
97   testCommon({{"test1", {APInt(8, 0xaa), 4096, 0}},
98               {"test2", {APInt(16, 0xbbbb), 4096, 1}},
99               {"test3", {APInt(24, 0xcccccc), 4096, 2}}},
100              2);
101   std::vector<uint8_t> Test1Expected(512, 0xaa);
102   std::vector<uint8_t> Test2Expected(512, 0xbb);
103   std::vector<uint8_t> Test3Expected(512, 0xcc);
104   checkSharedMemoryDefinition(getSharedMemoryName(2, 0), 4096, Test1Expected);
105   checkSharedMemoryDefinition(getSharedMemoryName(2, 1), 4096, Test2Expected);
106   checkSharedMemoryDefinition(getSharedMemoryName(2, 2), 4096, Test3Expected);
107 }
108 
109 // The following test is only supported on little endian systems.
110 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
111 TEST_F(SubprocessMemoryTest, DISABLED_DefinitionEndTruncation) {
112 #else
113 TEST_F(SubprocessMemoryTest, DefinitionEndTruncation) {
114 #endif
115   testCommon({{"test1", {APInt(48, 0xaabbccddeeff), 4096, 0}}}, 3);
116   std::vector<uint8_t> Test1Expected(512, 0);
117   // order is reversed since we're assuming a little endian system.
118   for (size_t I = 0; I < Test1Expected.size(); ++I) {
119     switch (I % 6) {
120     case 0:
121       Test1Expected[I] = 0xff;
122       break;
123     case 1:
124       Test1Expected[I] = 0xee;
125       break;
126     case 2:
127       Test1Expected[I] = 0xdd;
128       break;
129     case 3:
130       Test1Expected[I] = 0xcc;
131       break;
132     case 4:
133       Test1Expected[I] = 0xbb;
134       break;
135     case 5:
136       Test1Expected[I] = 0xaa;
137     }
138   }
139   checkSharedMemoryDefinition(getSharedMemoryName(3, 0), 4096, Test1Expected);
140 }
141 
142 #endif // __linux__ && !__ANDROID__ && !(__powerpc__ || __s390x__ || __sparc__)
143 
144 } // namespace exegesis
145 } // namespace llvm
146