bolt/deps/llvm-18.1.8/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp
2025-02-14 19:21:04 +01:00

146 lines
5.7 KiB
C++

//===-- SubprocessMemory.cpp ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "SubprocessMemory.h"
#include "Error.h"
#include "llvm/Support/Error.h"
#include <cerrno>
#ifdef __linux__
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
namespace llvm {
namespace exegesis {
#if defined(__linux__) && !defined(__ANDROID__)
Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) {
// Add the PID to the shared memory name so that if we're running multiple
// processes at the same time, they won't interfere with each other.
// This comes up particularly often when running the exegesis tests with
// llvm-lit
std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ProcessID);
int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(),
O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryFD == -1)
return make_error<Failure>(
"Failed to create shared memory object for auxiliary memory: " +
Twine(strerror(errno)));
if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) {
return make_error<Failure>("Truncating the auxiliary memory failed: " +
Twine(strerror(errno)));
}
SharedMemoryNames.push_back(AuxiliaryMemoryName);
return Error::success();
}
Error SubprocessMemory::addMemoryDefinition(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ProcessPID) {
SharedMemoryNames.reserve(MemoryDefinitions.size());
for (auto &[Name, MemVal] : MemoryDefinitions) {
std::string SharedMemoryName = "/" + std::to_string(ProcessPID) + "memdef" +
std::to_string(MemVal.Index);
SharedMemoryNames.push_back(SharedMemoryName);
int SharedMemoryFD =
shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) {
return make_error<Failure>("Truncating a memory definiton failed: " +
Twine(strerror(errno)));
}
char *SharedMemoryMapping =
(char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED,
SharedMemoryFD, 0);
// fill the buffer with the specified value
size_t CurrentByte = 0;
const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8;
while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) {
memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
ValueWidthBytes);
CurrentByte += ValueWidthBytes;
}
// fill the last section
memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),
MemVal.SizeBytes - CurrentByte);
if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) {
return make_error<Failure>(
"Unmapping a memory definition in the parent failed: " +
Twine(strerror(errno)));
}
}
return Error::success();
}
Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ParentPID, int CounterFileDescriptor) {
std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ParentPID);
int AuxiliaryMemoryFileDescriptor =
shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryFileDescriptor == -1)
return make_error<Failure>(
"Getting file descriptor for auxiliary memory failed");
// set up memory value file descriptors
int *AuxiliaryMemoryMapping =
(int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,
AuxiliaryMemoryFileDescriptor, 0);
if ((intptr_t)AuxiliaryMemoryMapping == -1)
return make_error<Failure>("Mapping auxiliary memory failed");
AuxiliaryMemoryMapping[0] = CounterFileDescriptor;
for (auto &[Name, MemVal] : MemoryDefinitions) {
std::string MemoryValueName = "/" + std::to_string(ParentPID) + "memdef" +
std::to_string(MemVal.Index);
AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] =
shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1)
return make_error<Failure>("Mapping shared memory failed");
}
if (munmap(AuxiliaryMemoryMapping, 4096) == -1)
return make_error<Failure>("Unmapping auxiliary memory failed");
return AuxiliaryMemoryFileDescriptor;
}
SubprocessMemory::~SubprocessMemory() {
for (std::string SharedMemoryName : SharedMemoryNames) {
if (shm_unlink(SharedMemoryName.c_str()) != 0) {
errs() << "Failed to unlink shared memory section: " << strerror(errno)
<< "\n";
}
}
}
#else
Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) {
return make_error<Failure>(
"initializeSubprocessMemory is only supported on Linux");
}
Error SubprocessMemory::addMemoryDefinition(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ProcessPID) {
return make_error<Failure>("addMemoryDefinitions is only supported on Linux");
}
Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(
std::unordered_map<std::string, MemoryValue> MemoryDefinitions,
pid_t ParentPID, int CounterFileDescriptor) {
return make_error<Failure>(
"setupAuxiliaryMemoryInSubprocess is only supported on Linux");
}
SubprocessMemory::~SubprocessMemory() {}
#endif // defined(__linux__) && !defined(__ANDROID__)
} // namespace exegesis
} // namespace llvm