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