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