mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 18:22:33 +01:00
Implement utils::memory_map_fd (partial)
Improve JIT profiling dump format (data + name, mmap) Improve objdump interception util (better speed, fix bugs) Rename spu_ubertrampoline to __ub+number
This commit is contained in:
parent
ffe00e8619
commit
dba2baba9c
@ -24,26 +24,54 @@ void jit_announce(uptr func, usz size, std::string_view name)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!name.empty())
|
|
||||||
{
|
|
||||||
// If directory ASMJIT doesn't exist, nothing will be written
|
// If directory ASMJIT doesn't exist, nothing will be written
|
||||||
static const fs::file s_asm = []()
|
static constexpr u64 c_dump_size = 0x1'0000'0000;
|
||||||
|
static constexpr u64 c_index_size = c_dump_size / 16;
|
||||||
|
static atomic_t<u64> g_index_off = 0;
|
||||||
|
static atomic_t<u64> g_data_off = c_index_size;
|
||||||
|
|
||||||
|
static void* g_asm = []() -> void*
|
||||||
{
|
{
|
||||||
fs::remove_all(fs::get_cache_dir() + "/ASMJIT/", false);
|
fs::remove_all(fs::get_cache_dir() + "/ASMJIT/", false);
|
||||||
|
|
||||||
return fs::file(fmt::format("%s/ASMJIT/.objects", fs::get_cache_dir()), fs::rewrite + fs::append);
|
fs::file objs(fmt::format("%s/ASMJIT/.objects", fs::get_cache_dir()), fs::read + fs::rewrite);
|
||||||
}();
|
|
||||||
|
|
||||||
if (s_asm)
|
if (!objs || !objs.trunc(c_dump_size))
|
||||||
{
|
{
|
||||||
// Dump object: addr + size + bytes
|
return nullptr;
|
||||||
s_asm.write(fmt::format("%s%s%s",
|
|
||||||
std::string_view(reinterpret_cast<char*>(&func), 8),
|
|
||||||
std::string_view(reinterpret_cast<char*>(&size), 8),
|
|
||||||
std::string_view(reinterpret_cast<char*>(func), size)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_asm && name[0] != '_')
|
return utils::memory_map_fd(objs.get_handle(), c_dump_size, utils::protection::rw);
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (g_asm && size < c_index_size)
|
||||||
|
{
|
||||||
|
struct entry
|
||||||
|
{
|
||||||
|
u64 addr; // RPCS3 process address
|
||||||
|
u32 size; // Function size
|
||||||
|
u32 off; // Function offset
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write index entry at the beginning of file, and data + NTS name at fixed offset
|
||||||
|
const u64 index_off = g_index_off.fetch_add(1);
|
||||||
|
const u64 size_all = size + name.size() + 1;
|
||||||
|
const u64 data_off = g_data_off.fetch_add(size_all);
|
||||||
|
|
||||||
|
// If either index or data area is exhausted, nothing will be written
|
||||||
|
if (index_off < c_index_size / sizeof(entry) && data_off + size_all < c_dump_size)
|
||||||
|
{
|
||||||
|
entry& index = static_cast<entry*>(g_asm)[index_off];
|
||||||
|
|
||||||
|
std::memcpy(static_cast<char*>(g_asm) + data_off, reinterpret_cast<char*>(func), size);
|
||||||
|
std::memcpy(static_cast<char*>(g_asm) + data_off + size, name.data(), name.size());
|
||||||
|
index.size = static_cast<u32>(size);
|
||||||
|
index.off = static_cast<u32>(data_off);
|
||||||
|
atomic_storage<u64>::store(index.addr, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_asm && !name.empty() && name[0] != '_')
|
||||||
{
|
{
|
||||||
// Save some objects separately
|
// Save some objects separately
|
||||||
fs::file dump(fmt::format("%s/ASMJIT/%s", fs::get_cache_dir(), name), fs::rewrite);
|
fs::file dump(fmt::format("%s/ASMJIT/%s", fs::get_cache_dir(), name), fs::rewrite);
|
||||||
@ -53,7 +81,6 @@ void jit_announce(uptr func, usz size, std::string_view name)
|
|||||||
dump.write(reinterpret_cast<uchar*>(func), size);
|
dump.write(reinterpret_cast<uchar*>(func), size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
static const fs::file s_map(fmt::format("/tmp/perf-%d.map", getpid()), fs::rewrite + fs::append);
|
static const fs::file s_map(fmt::format("/tmp/perf-%d.map", getpid()), fs::rewrite + fs::append);
|
||||||
|
106
objdump.cpp
106
objdump.cpp
@ -21,10 +21,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <spawn.h>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
@ -53,58 +50,92 @@ int main(int argc, char* argv[])
|
|||||||
// Get cache path
|
// Get cache path
|
||||||
home += "/rpcs3/ASMJIT/";
|
home += "/rpcs3/ASMJIT/";
|
||||||
|
|
||||||
// Get object names
|
// Get objects
|
||||||
int fd = open((home + ".objects").c_str(), O_RDONLY);
|
int fd = open((home + ".objects").c_str(), O_RDONLY);
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// Addr -> offset;size in .objects
|
// Map 4GiB (full size)
|
||||||
std::unordered_map<std::uint64_t, std::pair<std::uint64_t, std::uint64_t>> objects;
|
const auto data = mmap(nullptr, 0x10000'0000, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
while (true)
|
struct entry
|
||||||
{
|
{
|
||||||
// Size is name size, not object size
|
std::uint64_t addr;
|
||||||
std::uint64_t ptr, size;
|
std::uint32_t size;
|
||||||
if (read(fd, &ptr, 8) != 8 || read(fd, &size, 8) != 8)
|
std::uint32_t off;
|
||||||
break;
|
};
|
||||||
std::uint64_t off = lseek(fd, 0, SEEK_CUR);
|
|
||||||
objects.emplace(ptr, std::make_pair(off, size));
|
// Index part (precedes actual data)
|
||||||
lseek(fd, size, SEEK_CUR);
|
const auto index = static_cast<const entry*>(data);
|
||||||
}
|
|
||||||
|
const entry* found = nullptr;
|
||||||
|
|
||||||
|
std::string out_file;
|
||||||
|
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
|
||||||
std::uint64_t addr = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
for (int i = 0; i < argc; i++)
|
||||||
{
|
{
|
||||||
// Replace args
|
// Replace args
|
||||||
std::string arg = argv[i];
|
std::string arg = argv[i];
|
||||||
|
|
||||||
if (arg.find("--start-address=0x") == 0)
|
if (std::uintptr_t(data) != -1 && arg.find("--start-address=0x") == 0)
|
||||||
{
|
{
|
||||||
|
// Decode address and try to find the object
|
||||||
|
std::uint64_t addr = -1;
|
||||||
|
|
||||||
std::from_chars(arg.data() + strlen("--start-address=0x"), arg.data() + arg.size(), addr, 16);
|
std::from_chars(arg.data() + strlen("--start-address=0x"), arg.data() + arg.size(), addr, 16);
|
||||||
|
|
||||||
if (objects.count(addr))
|
for (int j = 0; j < 0x100'0000; j++)
|
||||||
{
|
{
|
||||||
// Extract object into a tmp file
|
if (index[j].addr == 0)
|
||||||
lseek(fd, objects[addr].first, SEEK_SET);
|
{
|
||||||
const int fd2 = open("/tmp/rpcs3.objdump.tmp", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
break;
|
||||||
sendfile(fd2, fd, nullptr, objects[addr].second);
|
}
|
||||||
|
|
||||||
|
if (index[j].addr == addr)
|
||||||
|
{
|
||||||
|
found = index + j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
// Extract object into a new file (read file name from the mapped memory)
|
||||||
|
const char* name = static_cast<char*>(data) + found->off + found->size;
|
||||||
|
|
||||||
|
if (name[0])
|
||||||
|
{
|
||||||
|
out_file = home + name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out_file = "/tmp/rpcs3.objdump." + std::to_string(getpid());
|
||||||
|
unlink(out_file.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const int fd2 = open(out_file.c_str(), O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
|
||||||
|
if (fd2 > 0)
|
||||||
|
{
|
||||||
|
// Don't overwrite if exists
|
||||||
|
write(fd2, static_cast<char*>(data) + found->off, found->size);
|
||||||
close(fd2);
|
close(fd2);
|
||||||
|
}
|
||||||
|
|
||||||
args.emplace_back("--adjust-vma=" + to_hex(addr));
|
args.emplace_back("--adjust-vma=" + to_hex(addr));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects.count(addr) && arg.find("--stop-address=0x") == 0)
|
if (found && arg.find("--stop-address=0x") == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects.count(addr) && arg == "-d")
|
if (found && arg == "-d")
|
||||||
{
|
{
|
||||||
arg = "-D";
|
arg = "-D";
|
||||||
}
|
}
|
||||||
@ -117,14 +148,14 @@ int main(int argc, char* argv[])
|
|||||||
args.emplace_back(std::move(arg));
|
args.emplace_back(std::move(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objects.count(addr))
|
if (found)
|
||||||
{
|
{
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
args.emplace_back("-b");
|
args.emplace_back("-b");
|
||||||
args.emplace_back("binary");
|
args.emplace_back("binary");
|
||||||
args.emplace_back("-m");
|
args.emplace_back("-m");
|
||||||
args.emplace_back("i386");
|
args.emplace_back("i386:x86-64");
|
||||||
args.emplace_back("/tmp/rpcs3.objdump.tmp");
|
args.emplace_back(std::move(out_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
args[0] = "/usr/bin/objdump";
|
args[0] = "/usr/bin/objdump";
|
||||||
@ -138,12 +169,11 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
new_argv.push_back(nullptr);
|
new_argv.push_back(nullptr);
|
||||||
|
|
||||||
if (objects.count(addr))
|
if (found)
|
||||||
{
|
{
|
||||||
int fds[2];
|
int fds[2];
|
||||||
pipe(fds);
|
pipe(fds);
|
||||||
|
|
||||||
// objdump is broken; fix address truncation
|
|
||||||
if (fork() > 0)
|
if (fork() > 0)
|
||||||
{
|
{
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
@ -158,20 +188,6 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
// Replace broken address
|
|
||||||
if ((buf[0] >= '0' && buf[0] <= '9') || (buf[0] >= 'a' && buf[0] <= 'f'))
|
|
||||||
{
|
|
||||||
std::uint64_t ptr = -1;
|
|
||||||
auto cvt = std::from_chars(buf.data(), buf.data() + buf.size(), ptr, 16);
|
|
||||||
|
|
||||||
if (cvt.ec == std::errc() && ptr < addr)
|
|
||||||
{
|
|
||||||
auto fix = to_hex((ptr - std::uint32_t(addr)) + addr, false);
|
|
||||||
write(STDOUT_FILENO, fix.data(), fix.size());
|
|
||||||
buf = std::string(cvt.ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write(STDOUT_FILENO, buf.data(), buf.size());
|
write(STDOUT_FILENO, buf.data(), buf.size());
|
||||||
buf.clear();
|
buf.clear();
|
||||||
}
|
}
|
||||||
|
@ -1074,7 +1074,9 @@ spu_function_t spu_runtime::rebuild_ubertrampoline(u32 id_inst)
|
|||||||
workload.clear();
|
workload.clear();
|
||||||
result = reinterpret_cast<spu_function_t>(reinterpret_cast<u64>(wxptr));
|
result = reinterpret_cast<spu_function_t>(reinterpret_cast<u64>(wxptr));
|
||||||
|
|
||||||
jit_announce(wxptr, raw - wxptr, "spu_ubertrampoline");
|
std::string fname;
|
||||||
|
fmt::append(fname, "__ub%u", m_flat_list.size());
|
||||||
|
jit_announce(wxptr, raw - wxptr, fname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto _old = stuff_it->trampoline.compare_and_swap(nullptr, result))
|
if (auto _old = stuff_it->trampoline.compare_and_swap(nullptr, result))
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
using native_handle = void*;
|
||||||
|
#else
|
||||||
|
using native_handle = int;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Memory protection type
|
// Memory protection type
|
||||||
enum class protection
|
enum class protection
|
||||||
{
|
{
|
||||||
@ -43,6 +49,9 @@ namespace utils
|
|||||||
// Lock pages in memory
|
// Lock pages in memory
|
||||||
bool memory_lock(void* pointer, usz size);
|
bool memory_lock(void* pointer, usz size);
|
||||||
|
|
||||||
|
// Map file descriptor
|
||||||
|
void* memory_map_fd(native_handle fd, usz size, protection prot);
|
||||||
|
|
||||||
// Shared memory handle
|
// Shared memory handle
|
||||||
class shm
|
class shm
|
||||||
{
|
{
|
||||||
|
@ -296,6 +296,23 @@ namespace utils
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* memory_map_fd(native_handle fd, usz size, protection prot)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
|
const auto result = ::mmap(nullptr, size, +prot, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
|
if (result == reinterpret_cast<void*>(uptr{umax}))
|
||||||
|
{
|
||||||
|
[[unlikely]] return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
shm::shm(u32 size, u32 flags)
|
shm::shm(u32 size, u32 flags)
|
||||||
: m_flags(flags)
|
: m_flags(flags)
|
||||||
, m_size(utils::align(size, 0x10000))
|
, m_size(utils::align(size, 0x10000))
|
||||||
|
Loading…
Reference in New Issue
Block a user