xref: /llvm-project/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp (revision 0b6b400b98b921279fc08c63a2a68ebfcb12a3e2)
1 //===-- SubprocessMemory.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 #include "Error.h"
11 #include "llvm/Support/Error.h"
12 
13 #ifdef __linux__
14 #include <fcntl.h>
15 #include <sys/mman.h>
16 #include <unistd.h>
17 #endif
18 
19 namespace llvm {
20 namespace exegesis {
21 
22 #ifdef __linux__
23 
24 Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) {
25   // Add the PID to the shared memory name so that if we're running multiple
26   // processes at the same time, they won't interfere with each other.
27   // This comes up particularly often when running the exegesis tests with
28   // llvm-lit
29   std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ProcessID);
30   int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(),
31                                    O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
32   if (AuxiliaryMemoryFD == -1)
33     return make_error<Failure>(
34         "Failed to create shared memory object for auxiliary memory: " +
35         Twine(strerror(errno)));
36   if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) {
37     return make_error<Failure>("Truncating the auxiliary memory failed: " +
38                                Twine(strerror(errno)));
39   }
40   return Error::success();
41 }
42 
43 Error SubprocessMemory::addMemoryDefinition(
44     std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
45     pid_t ProcessPID) {
46   SharedMemoryNames.reserve(MemoryDefinitions.size());
47   for (auto &[Name, MemVal] : MemoryDefinitions) {
48     std::string SharedMemoryName = "/" + std::to_string(ProcessPID) + "memdef" +
49                                    std::to_string(MemVal.Index);
50     SharedMemoryNames.push_back(SharedMemoryName);
51     int SharedMemoryFD =
52         shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
53     if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) {
54       return make_error<Failure>("Truncating a memory definiton failed: " +
55                                  Twine(strerror(errno)));
56     }
57 
58     char *SharedMemoryMapping =
59         (char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
60                      SharedMemoryFD, 0);
61     // fill the buffer with the specified value
62     size_t CurrentByte = 0;
63     const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8;
64     while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) {
65       memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
66              ValueWidthBytes);
67       CurrentByte += ValueWidthBytes;
68     }
69     // fill the last section
70     memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
71            MemVal.SizeBytes - CurrentByte);
72     if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) {
73       return make_error<Failure>(
74           "Unmapping a memory definition in the parent failed: " +
75           Twine(strerror(errno)));
76     }
77   }
78   return Error::success();
79 }
80 
81 Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
82     std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
83     pid_t ParentPID, int CounterFileDescriptor) {
84   std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ParentPID);
85   int AuxiliaryMemoryFileDescriptor =
86       shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
87   if (AuxiliaryMemoryFileDescriptor == -1)
88     return make_error<Failure>(
89         "Getting file descriptor for auxiliary memory failed");
90   // set up memory value file descriptors
91   int *AuxiliaryMemoryMapping =
92       (int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,
93                   AuxiliaryMemoryFileDescriptor, 0);
94   if ((intptr_t)AuxiliaryMemoryMapping == -1)
95     return make_error<Failure>("Mapping auxiliary memory failed");
96   AuxiliaryMemoryMapping[0] = CounterFileDescriptor;
97   for (auto &[Name, MemVal] : MemoryDefinitions) {
98     std::string MemoryValueName = "/" + std::to_string(ParentPID) + "memdef" +
99                                   std::to_string(MemVal.Index);
100     AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] =
101         shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
102     if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1)
103       return make_error<Failure>("Mapping shared memory failed");
104   }
105   if (munmap(AuxiliaryMemoryMapping, 4096) == -1)
106     return make_error<Failure>("Unmapping auxiliary memory failed");
107   return AuxiliaryMemoryFileDescriptor;
108 }
109 
110 SubprocessMemory::~SubprocessMemory() {
111   for (std::string SharedMemoryName : SharedMemoryNames) {
112     if (shm_unlink(SharedMemoryName.c_str()) != 0) {
113       errs() << "Failed to unlink shared memory section: " << strerror(errno)
114              << "\n";
115     }
116   }
117 }
118 
119 #else
120 
121 Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) {
122   return make_error<Failure>(
123       "initializeSubprocessMemory is only supported on Linux");
124 }
125 
126 Error SubprocessMemory::addMemoryDefinition(
127     std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
128     pid_t ProcessPID) {
129   return make_error<Failure>("addMemoryDefinitions is only supported on Linux");
130 }
131 
132 Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
133     std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
134     pid_t ParentPID, int CounterFileDescriptor) {
135   return make_error<Failure>(
136       "setupAuxiliaryMemoryInSubprocess is only supported on Linux");
137 }
138 
139 SubprocessMemory::~SubprocessMemory() {}
140 
141 #endif // __linux__
142 
143 } // namespace exegesis
144 } // namespace llvm
145