memory: change defaults

This commit is contained in:
nmzik
2026-10-27 09:12:53 +01:00
parent 9d8c458535
commit 09753bf8ff
7 changed files with 103 additions and 64 deletions
-4
View File
@@ -99,10 +99,6 @@ static void Init(const Config::ConfigOptions& cfg, const std::filesystem::path&
if (Common::File::IsFileExisting(param_json)) {
Loader::SystemContentLoadParamSfo(param_json);
if (const auto flexible_memory_size = Loader::SystemContentGetFlexibleMemorySize();
flexible_memory_size != 0) {
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
}
}
if (cfg.splash_enabled) {
Libs::Graphics::InitializeSplashScreen(param_json.parent_path());
@@ -533,16 +533,16 @@ void DrawMemoryAndIo(const Snapshot& shown) {
Bytes(guest.pooled_allocated) + " (" + Bytes(guest.pool_committed) + " committed)");
Row("Flexible", Bytes(guest.flexible_used) + " / " + Bytes(guest.flexible_total));
Row("Extended", Bytes(guest.automatic_allocated));
// Past the pool size the guest sees no page-table entries available.
const auto entries = std::max(guest.cpu_page_entries, guest.gpu_page_entries);
// Past its total a side sees no page-table entries available.
const auto percent = std::max(guest.cpu_page_entries * 100 / guest.cpu_page_entries_total,
guest.gpu_page_entries * 100 / guest.gpu_page_entries_total);
Row("Page table (2 MB)",
Fmt("CPU %llu GPU %llu / %llu",
Fmt("CPU %llu / %llu GPU %llu / %llu",
static_cast<unsigned long long>(guest.cpu_page_entries),
static_cast<unsigned long long>(guest.cpu_page_entries_total),
static_cast<unsigned long long>(guest.gpu_page_entries),
static_cast<unsigned long long>(guest.page_entries_total)),
entries > guest.page_entries_total ? BAD
: entries * 10 > guest.page_entries_total * 9 ? MEDIUM
: GOOD);
static_cast<unsigned long long>(guest.gpu_page_entries_total)),
LevelColor(static_cast<double>(percent), 90, 100));
ImGui::EndTable();
}
if (BeginSection("Emulator process")) {
+40 -29
View File
@@ -9,6 +9,7 @@
#include "graphics/host_gpu/renderer/renderContext.h"
#include "libs/errno.h"
#include "libs/libs.h"
#include "loader/systemContent.h"
#include <algorithm>
#include <array>
@@ -63,15 +64,21 @@ constexpr int PROT_GPU_WRITE = 0x20;
enum class GpuAccessMode { NoAccess, Read, Write, ReadWrite };
constexpr uint64_t PAGE_TABLE_POOL_SIZE = 4ull * 1024ull * 1024ull * 1024ull;
constexpr uint64_t PAGE_TABLE_GRANULARITY = 2ull * 1024ull * 1024ull;
constexpr int PAGE_TABLE_POOL_ENTRIES =
static_cast<int>(PAGE_TABLE_POOL_SIZE / PAGE_TABLE_GRANULARITY);
constexpr uint64_t PAGE_TABLE_GRANULARITY = 2ull * 1024ull * 1024ull;
constexpr uint64_t DEFAULT_FLEXIBLE_MEMORY_SIZE = 448ull * 1024ull * 1024ull;
// A game gets 12.5 GiB. A fixed 64 MiB cache and mapping table memory past the 64 MiB included
// for each of the CPU, GPU and AMM tables come off the top; flexible and direct memory share what
// is left. One 4 KiB table maps 2 MiB.
constexpr uint64_t GUEST_MEMORY_BUDGET = 12800ull * 1024ull * 1024ull;
constexpr uint64_t RESERVED_CACHE_SIZE = 64ull * 1024ull * 1024ull;
constexpr uint64_t INCLUDED_TABLE_MEMORY = 64ull * 1024ull * 1024ull;
constexpr uint64_t MAPPING_TABLE_SIZE = 4ull * 1024ull;
static uint64_t g_flexible_memory_size = DEFAULT_FLEXIBLE_MEMORY_SIZE;
static bool g_flexible_memory_size_frozen = false;
static Graphics::RenderContext* g_gpu_resources = nullptr;
static uint64_t g_guest_memory_size = GUEST_MEMORY_BUDGET - RESERVED_CACHE_SIZE;
static uint64_t g_flexible_memory_size = DEFAULT_FLEXIBLE_MEMORY_SIZE;
static uint64_t g_cpu_table_memory = INCLUDED_TABLE_MEMORY;
static uint64_t g_gpu_table_memory = INCLUDED_TABLE_MEMORY;
static Graphics::RenderContext* g_gpu_resources = nullptr;
#if defined(KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS)
static void (*g_test_gpu_range)(bool, uint64_t, size_t) = nullptr;
#endif
@@ -664,11 +671,8 @@ public:
KYTY_CLASS_NO_COPY(PhysicalMemory);
static constexpr uint64_t TotalSize() { return static_cast<uint64_t>(13824) * 1024 * 1024; }
static uint64_t Size() {
EXIT_IF(g_flexible_memory_size >= TotalSize());
return TotalSize() - g_flexible_memory_size;
}
static uint64_t TotalSize() { return g_guest_memory_size; }
static uint64_t Size() { return TotalSize() - g_flexible_memory_size; }
bool Alloc(uint64_t search_start, uint64_t search_end, size_t len, size_t alignment,
uint64_t* phys_addr_out, int memory_type,
@@ -998,7 +1002,22 @@ static bool SelfTestSub64SharedPlaceholderAlias() {
static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size);
void Initialize() {
g_flexible_memory_size_frozen = true;
const auto params = Loader::SystemContentGetMemoryParams();
if (params.flexible_size != 0) {
g_flexible_memory_size = params.flexible_size;
}
g_cpu_table_memory = std::max(params.cpu_table_memory, INCLUDED_TABLE_MEMORY);
g_gpu_table_memory = std::max(params.gpu_table_memory, INCLUDED_TABLE_MEMORY);
const auto table_overhead = g_cpu_table_memory + g_gpu_table_memory +
std::max(params.amm_table_memory, INCLUDED_TABLE_MEMORY) -
3 * INCLUDED_TABLE_MEMORY;
EXIT_IF(g_flexible_memory_size + table_overhead >= GUEST_MEMORY_BUDGET - RESERVED_CACHE_SIZE);
g_guest_memory_size = GUEST_MEMORY_BUDGET - RESERVED_CACHE_SIZE - table_overhead;
LOGF("\t flexible memory size = %" PRIu64 " MiB, direct memory size = %" PRIu64 " MiB\n",
g_flexible_memory_size / (1024ull * 1024ull),
(g_guest_memory_size - g_flexible_memory_size) / (1024ull * 1024ull));
VirtualMemory::Init();
g_guest_address_space = std::make_unique<GuestAddressSpace>(PhysicalMemory::TotalSize());
g_physical_memory = std::make_unique<PhysicalMemory>();
@@ -1066,15 +1085,6 @@ void RegisterCallbacks(callback_func_t alloc_func, callback_func_t free_func) {
}
}
void SetFlexibleMemorySize(uint64_t size) {
constexpr uint64_t GuestPageSize = 0x4000;
EXIT_IF(g_flexible_memory_size_frozen || g_guest_address_space != nullptr);
EXIT_IF(size == 0 || (size & (GuestPageSize - 1u)) != 0 || size >= PhysicalMemory::TotalSize());
g_flexible_memory_size = size;
LOGF("\t flexible memory size = 0x%016" PRIx64 " (%" PRIu64 " MiB)\n", size,
size / (1024ull * 1024ull));
}
bool PhysicalMemory::Alloc(uint64_t search_start, uint64_t search_end, size_t len, size_t alignment,
uint64_t* phys_addr_out, int memory_type, AllocationKind kind) {
if (phys_addr_out == nullptr) {
@@ -2655,12 +2665,12 @@ int KYTY_SYSV_ABI KernelGetPageTableStats(int* cpu_total, int* cpu_available, in
const auto gpu_used =
(g_virtual_ranges != nullptr ? g_virtual_ranges->CountPageTableEntries(true) : 0);
*cpu_total = PAGE_TABLE_POOL_ENTRIES;
*gpu_total = PAGE_TABLE_POOL_ENTRIES;
*cpu_available = PAGE_TABLE_POOL_ENTRIES -
static_cast<int>(std::min<uint64_t>(cpu_used, PAGE_TABLE_POOL_ENTRIES));
*gpu_available = PAGE_TABLE_POOL_ENTRIES -
static_cast<int>(std::min<uint64_t>(gpu_used, PAGE_TABLE_POOL_ENTRIES));
const auto cpu_tables = g_cpu_table_memory / MAPPING_TABLE_SIZE;
const auto gpu_tables = g_gpu_table_memory / MAPPING_TABLE_SIZE;
*cpu_total = static_cast<int>(cpu_tables);
*gpu_total = static_cast<int>(gpu_tables);
*cpu_available = static_cast<int>(cpu_tables - std::min(cpu_used, cpu_tables));
*gpu_available = static_cast<int>(gpu_tables - std::min(gpu_used, gpu_tables));
LOGF_COLOR(Log::Color::Green,
"\t cpu_total = %d\n"
@@ -4381,7 +4391,8 @@ DebugStats GetDebugStats() {
stats.direct_total = PhysicalMemory::Size();
stats.flexible_total = FlexibleMemory::Size();
stats.pool_committed = g_memory_pool_committed.load(std::memory_order_relaxed);
stats.page_entries_total = PAGE_TABLE_POOL_ENTRIES;
stats.cpu_page_entries_total = g_cpu_table_memory / MAPPING_TABLE_SIZE;
stats.gpu_page_entries_total = g_gpu_table_memory / MAPPING_TABLE_SIZE;
if (g_physical_memory != nullptr) {
Common::LockGuard lock(g_physical_memory->GetMutex());
for (const auto& [start, block]: g_physical_memory->GetPhysicalBlocks()) {
+4 -4
View File
@@ -26,9 +26,10 @@ struct DebugStats {
uint64_t flexible_total = 0;
uint64_t flexible_used = 0;
uint64_t pool_committed = 0;
uint64_t cpu_page_entries = 0; // 2 MiB page-table entries in use.
uint64_t gpu_page_entries = 0;
uint64_t page_entries_total = 0; // Per side.
uint64_t cpu_page_entries = 0; // 2 MiB page-table entries in use.
uint64_t gpu_page_entries = 0;
uint64_t cpu_page_entries_total = 0;
uint64_t gpu_page_entries_total = 0;
};
[[nodiscard]] DebugStats GetDebugStats();
@@ -125,7 +126,6 @@ static_assert(sizeof(KernelMemoryPoolBlockStats) == 16,
"KernelMemoryPoolBlockStats struct size is incorrect");
void RegisterCallbacks(callback_func_t alloc_func, callback_func_t free_func);
void SetFlexibleMemorySize(uint64_t size);
int AllocateDirectMemory(int64_t search_start, int64_t search_end, size_t size, size_t alignment,
int memory_type, int64_t* phys_addr_out, bool automatic = false);
int MapAutomaticMemory(uint64_t vaddr, size_t size, int type, int prot);
+21 -11
View File
@@ -35,7 +35,7 @@ public:
bool GetParamInt(const char* name, int32_t* value);
bool GetParamString(const char* name, std::string* value);
bool GetParamString(const char* name, char* value, size_t value_size);
uint64_t GetFlexibleMemorySize();
MemoryParams GetMemoryParams();
void DbgPrint();
@@ -61,7 +61,7 @@ private:
Common::Mutex m_mutex;
bool m_opened = false;
std::vector<Param> m_params;
uint64_t m_flexible_memory_size = 0;
MemoryParams m_memory_params;
};
class PlayGo {
@@ -172,11 +172,21 @@ void Psf::OpenJson(const std::filesystem::path& file_name) {
add_int_param("userDefinedParam3", "USER_DEFINED_PARAM_3");
add_int_param("userDefinedParam4", "USER_DEFINED_PARAM_4");
auto read_size = [](const nlohmann::ordered_json& object, const char* key, uint64_t* size,
uint64_t unit = 1) {
if (auto it = object.find(key); it != object.end()) {
*size = it->get<uint64_t>() * unit;
}
};
if (auto kernel = param_json.find("kernel");
kernel != param_json.end() && kernel->is_object()) {
if (auto it = kernel->find("flexibleMemorySize"); it != kernel->end()) {
m_flexible_memory_size = it->get<uint64_t>();
}
read_size(*kernel, "flexibleMemorySize", &m_memory_params.flexible_size);
read_size(*kernel, "cpuPageTableSize", &m_memory_params.cpu_table_memory);
read_size(*kernel, "gpuPageTableSize", &m_memory_params.gpu_table_memory);
}
if (auto amm = param_json.find("amm"); amm != param_json.end() && amm->is_object()) {
read_size(*amm, "pagetableMemorySizeInMib", &m_memory_params.amm_table_memory,
1024ull * 1024ull);
}
auto localized = param_json.find("localizedParameters");
@@ -227,8 +237,8 @@ void Psf::Close() {
Common::LockGuard lock(m_mutex);
m_params.clear();
m_flexible_memory_size = 0;
m_opened = false;
m_memory_params = {};
m_opened = false;
}
bool Psf::IsValid() {
@@ -339,10 +349,10 @@ bool Psf::GetParamString(const char* name, char* value, size_t value_size) {
return false;
}
uint64_t Psf::GetFlexibleMemorySize() {
MemoryParams Psf::GetMemoryParams() {
Common::LockGuard lock(m_mutex);
return m_flexible_memory_size;
return m_memory_params;
}
PlayGo::~PlayGo() {
@@ -646,10 +656,10 @@ bool SystemContentParamSfoGetString(const char* name, char* value, size_t value_
return sc->psf.GetParamString(name, value, value_size);
}
uint64_t SystemContentGetFlexibleMemorySize() {
MemoryParams SystemContentGetMemoryParams() {
auto* sc = Common::Singleton<SystemContent>::Instance();
return sc->psf.GetFlexibleMemorySize();
return sc->psf.GetMemoryParams();
}
bool SystemContentGetIconPath(std::filesystem::path* path) {
+10 -1
View File
@@ -14,7 +14,16 @@ void SystemContentLoadParamSfo(const std::filesystem::path& file_name);
bool SystemContentParamSfoGetInt(const char* name, int32_t* value);
bool SystemContentParamSfoGetString(const char* name, std::string* value);
bool SystemContentParamSfoGetString(const char* name, char* value, size_t value_size);
uint64_t SystemContentGetFlexibleMemorySize();
// Memory sizes a game's param.json sets, in bytes; 0 where it sets none.
struct MemoryParams {
uint64_t flexible_size = 0;
uint64_t cpu_table_memory = 0;
uint64_t gpu_table_memory = 0;
uint64_t amm_table_memory = 0;
};
MemoryParams SystemContentGetMemoryParams();
bool SystemContentGetIconPath(std::filesystem::path* path);
bool SystemContentGetChunksNum(uint32_t* num);
+21 -8
View File
@@ -88,9 +88,14 @@ using Libs::LibKernel::Memory::VirtualQueryInfo;
// Prospero ABI?
constexpr uint64_t SceKernelPageSize = 0x4000;
constexpr uint64_t SceKernelTotalPhysicalSize = 13824ull * 1024ull * 1024ull;
constexpr uint64_t SceKernelFlexibleMemorySize = 448ull * 1024ull * 1024ull;
constexpr uint64_t TestFlexibleMemorySize = 3072ull * 1024ull * 1024ull;
constexpr uint64_t GuestMemoryBudget = 12800ull * 1024ull * 1024ull;
constexpr uint64_t ReservedCacheSize = 64ull * 1024ull * 1024ull;
// The 128 MiB CPU and 96 MiB AMM mapping tables add 64 + 32 MiB; a zero GPU table size adds none.
constexpr uint64_t TestCpuTableMemory = 128ull * 1024ull * 1024ull;
constexpr uint64_t TestAmmTableMemory = 96ull * 1024ull * 1024ull;
constexpr uint64_t TestTableOverhead = 96ull * 1024ull * 1024ull;
constexpr int SceKernelProtCpuRead = 0x01;
constexpr int SceKernelProtCpuRw = 0x02;
constexpr int SceKernelProtCpuExec = 0x04;
@@ -175,7 +180,9 @@ void InitSubsystems() {
const auto param_json = std::filesystem::temp_directory_path() /
("kyty_virtual_memory_" +
std::to_string(reinterpret_cast<uintptr_t>(&initialized)) + ".json");
constexpr char json[] = R"({"kernel":{"flexibleMemorySize":3221225472}})";
constexpr char json[] =
R"({"kernel":{"flexibleMemorySize":3221225472,"cpuPageTableSize":134217728,)"
R"("gpuPageTableSize":0},"amm":{"pagetableMemorySizeInMib":96}})";
Common::File param_file;
Check("InitSubsystems", param_file.Create(param_json), "failed to create temporary param.json");
uint32_t bytes_written = 0;
@@ -185,16 +192,19 @@ void InitSubsystems() {
"failed to write temporary param.json");
Loader::SystemContentLoadParamSfo(param_json);
const auto flexible_memory_size = Loader::SystemContentGetFlexibleMemorySize();
const auto params = Loader::SystemContentGetMemoryParams();
Check("InitSubsystems", Common::File::DeleteFile(param_json),
"failed to remove temporary param.json");
Check("InitSubsystems", flexible_memory_size == TestFlexibleMemorySize,
Check("InitSubsystems", params.flexible_size == TestFlexibleMemorySize,
"failed to read flexible memory size from param.json");
Check("InitSubsystems",
params.cpu_table_memory == TestCpuTableMemory && params.gpu_table_memory == 0 &&
params.amm_table_memory == TestAmmTableMemory,
"failed to read mapping table sizes from param.json");
size_t default_flexible_memory_size = 0;
Libs::LibKernel::Memory::KernelConfiguredFlexibleMemorySize(&default_flexible_memory_size);
Check("InitSubsystems", default_flexible_memory_size == SceKernelFlexibleMemorySize,
"flexible memory does not default to 448 MiB without param.json");
Libs::LibKernel::Memory::SetFlexibleMemorySize(flexible_memory_size);
subsystems.Initialize<Libs::LibKernel::Memory::Lifecycle>();
@@ -822,8 +832,8 @@ void TestFlexibleMemoryCapacityIsBootFixed() {
Check(test, configured == TestFlexibleMemorySize,
"boot flexible pool did not use the param.json value");
Check(test, configured == baseline, "boot flexible pool did not start at configured capacity");
Check(test, backing == SceKernelTotalPhysicalSize,
"boot backing is not the single 13.5 GiB physical file");
Check(test, backing == GuestMemoryBudget - ReservedCacheSize - TestTableOverhead,
"boot backing is not the 12.5 GiB budget less the reserved cache and table overhead");
Check(test, backing == Libs::LibKernel::Memory::KernelGetDirectMemorySize() + configured,
"direct and flexible regions do not partition the boot backing");
@@ -1409,7 +1419,10 @@ void TestPageTableStatsTrackRangeEdits() {
"KernelGetPageTableStats");
return stats;
};
const auto baseline = read_stats();
// A 4 KiB table maps 2 MiB: 128 MiB of CPU tables gives 32768, the default 64 MiB GPU 16384.
const auto baseline = read_stats();
Check(test, baseline[0] == 32768 && baseline[2] == 16384,
"page-table totals do not follow the configured table memory");
const auto expect_used = [&](int cpu, int gpu, const char* action) {
const auto stats = read_stats();
Check(test,