diff --git a/assets/languages/en/Options.xml b/assets/languages/en/Options.xml index 1cde775d71..39be41cb80 100644 --- a/assets/languages/en/Options.xml +++ b/assets/languages/en/Options.xml @@ -206,6 +206,9 @@ Offset in Charter If checked, this will enable the Song Offset option in the Chart Editor too. + + Legacy Memory Counter + If checked, the memory counter will show the Haxe GC memory usage and its peak (the original behavior) instead of the working set memory seen in Task Manager. \ No newline at end of file diff --git a/assets/languages/es/Options.xml b/assets/languages/es/Options.xml index 60ad120cd9..1f9bb0517d 100644 --- a/assets/languages/es/Options.xml +++ b/assets/languages/es/Options.xml @@ -180,6 +180,9 @@ Esto controla por cuánto tiempo te advertirá el editor antes de autoguardar (en segundos..., 0 para desactivar) Carpeta de Autoguardados - Si está activado, el autoguardado se guardará en otra carpeta con su fecha en vez de sobreescribir el archivo actual. (song/autosaves/) + Si está activado, el autoguardado se guardará en otra carpeta con su fecha en vez de sobreescribir el archivo actual. (song/autosaves/) + + Contador de Memoria Clásico + Si está activado, el contador de memoria mostrará el uso de memoria del GC de Haxe y su máximo (el comportamiento original) en vez de la memoria de trabajo vista en el Administrador de Tareas. \ No newline at end of file diff --git a/assets/languages/it/Options.xml b/assets/languages/it/Options.xml index ed24a8ee31..42b9c1ce9e 100644 --- a/assets/languages/it/Options.xml +++ b/assets/languages/it/Options.xml @@ -199,5 +199,8 @@ Offset Editor Chart Se abilitato, questo attiverà l'opzione Offset Canzone anche nel Editor Chart. + + Contatore Memoria Classico + Se attivato, il contatore di memoria mostrerà l'uso di memoria del GC di Haxe e il suo picco (il comportamento originale) invece della memoria di lavoro vista nel Task Manager. diff --git a/assets/languages/pl/Options.xml b/assets/languages/pl/Options.xml index f14687f33f..9a518f35cd 100644 --- a/assets/languages/pl/Options.xml +++ b/assets/languages/pl/Options.xml @@ -175,6 +175,9 @@ Folder Autozapisów Jeśli włączone, Edytor będzie zapisywać pliki w osobnym folderze, zamiast nadpisywania aktualnego pliku. (song/autosaves/) + + Klasyczny Licznik Pamięci + Jeśli włączone, licznik pamięci pokaże użycie pamięci GC Haxe i jego szczyt (oryginalne zachowanie) zamiast pamięci roboczej widocznej w Menedżerze Zadań. diff --git a/assets/languages/pt/Options.xml b/assets/languages/pt/Options.xml index 82ce97c7d7..4b418925ec 100644 --- a/assets/languages/pt/Options.xml +++ b/assets/languages/pt/Options.xml @@ -206,6 +206,9 @@ Atraso no Mapeador Se marcado, irá ativar o Atraso da Música no Editor de Mapas, também. + + Contador de Memória Clássico + Se marcado, o contador de memória mostrará o uso de memória do GC de Haxe e o seu máximo (o comportamento original) em vez da memória de trabalho vista no Gerenciador de Tarefas. \ No newline at end of file diff --git a/source/funkin/backend/system/framerate/MemoryCounter.hx b/source/funkin/backend/system/framerate/MemoryCounter.hx index 068399b512..39962e2399 100644 --- a/source/funkin/backend/system/framerate/MemoryCounter.hx +++ b/source/funkin/backend/system/framerate/MemoryCounter.hx @@ -28,14 +28,57 @@ class MemoryCounter extends Sprite { addChild(label); } memoryPeakText.alpha = 0.5; + #if !(cpp && (windows || mac || linux)) + memoryPeakText.visible = false; + #end } public function reload() {} + private var usingLegacy:Bool = false; + public override function __enterFrame(t:Int) { if (alpha <= 0.05) return; super.__enterFrame(t); + #if (cpp && (windows || mac || linux)) + var legacy = funkin.options.Options.legacyMemoryCounter; + + if (legacy) { + if (legacy != usingLegacy) { + usingLegacy = legacy; + memoryPeak = 0; + } + + final mem = MemoryUtil.currentMemUsage(); + if (memoryPeak < mem) memoryPeak = mem; + if (mem == memory) { + updateLabelPosition(); + return; + } + + memory = mem; + memoryPeakText.visible = true; + memoryText.text = CoolUtil.getSizeString(memory); + memoryPeakText.text = ' / ${CoolUtil.getSizeString(memoryPeak)}'; + } else { + if (legacy != usingLegacy) usingLegacy = legacy; + + final gcMem = MemoryUtil.currentMemUsage(); + final osMem = MemoryUtil.currentProcessMemUsage(); + + if (gcMem == memory && osMem == memoryPeak) { + updateLabelPosition(); + return; + } + + memory = gcMem; + memoryPeak = osMem; + memoryPeakText.visible = true; + memoryText.text = CoolUtil.getSizeString(gcMem); + memoryPeakText.text = ' / ${CoolUtil.getSizeString(osMem)}'; + } + #else final mem = MemoryUtil.currentMemUsage(); if (mem == memory) { @@ -44,9 +87,8 @@ class MemoryCounter extends Sprite { } memory = mem; - if (memoryPeak < memory) memoryPeak = memory; - memoryText.text = CoolUtil.getSizeString(memory); - memoryPeakText.text = ' / ${CoolUtil.getSizeString(memoryPeak)}'; + memoryText.text = CoolUtil.getSizeString(mem); + #end updateLabelPosition(); } diff --git a/source/funkin/backend/utils/MemoryUtil.hx b/source/funkin/backend/utils/MemoryUtil.hx index 2de56184c1..87d75fdd15 100644 --- a/source/funkin/backend/utils/MemoryUtil.hx +++ b/source/funkin/backend/utils/MemoryUtil.hx @@ -119,6 +119,23 @@ final class MemoryUtil { #end } + /** + * Gets the current process memory usage (Working Set / RSS) from the OS. + * This is much more granular than Haxe GC memory and updates more frequently. + * Returns the value in bytes, matching what you see in Task Manager / Activity Monitor. + */ + public static inline function currentProcessMemUsage():Float { + #if (cpp && windows) + return funkin.backend.utils.native.Windows.getCurrentProcessMemory(); + #elseif (cpp && mac) + return funkin.backend.utils.native.Mac.getCurrentProcessMemory(); + #elseif (cpp && linux) + return funkin.backend.utils.native.Linux.getCurrentProcessMemory(); + #else + return currentMemUsage(); + #end + } + /** * Gets the memory type of the system. diff --git a/source/funkin/backend/utils/native/Linux.hx b/source/funkin/backend/utils/native/Linux.hx index 661c584267..001929d009 100644 --- a/source/funkin/backend/utils/native/Linux.hx +++ b/source/funkin/backend/utils/native/Linux.hx @@ -28,5 +28,25 @@ final class Linux { { return 0; } + + @:functionCode(' + FILE *status = fopen("/proc/self/status", "r"); + if (status == NULL) return 0.0; + + char line[256]; + while (fgets(line, sizeof(line), status)) { + long rss; + if (sscanf(line, "VmRSS: %ld kB", &rss) == 1) { + fclose(status); + return (double)(rss * 1024); // kB -> bytes + } + } + fclose(status); + return 0.0; + ') + public static function getCurrentProcessMemory():Float + { + return 0; + } } #end \ No newline at end of file diff --git a/source/funkin/backend/utils/native/Mac.hx b/source/funkin/backend/utils/native/Mac.hx index afd9d58981..86924dc2eb 100644 --- a/source/funkin/backend/utils/native/Mac.hx +++ b/source/funkin/backend/utils/native/Mac.hx @@ -5,6 +5,7 @@ import funkin.backend.utils.NativeAPI.CodeCursor; import openfl.ui.Mouse; @:headerInclude('sys/sysctl.h') +@:headerInclude('mach/mach.h') @:dox(hide) final class Mac { @@ -23,6 +24,19 @@ final class Mac return 0; } + @:functionCode(' + task_basic_info_data_t info; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) { + return (double)info.resident_size; + } + return 0.0; + ') + public static function getCurrentProcessMemory():Float + { + return 0; + } + public static function setMouseCursorIcon(icon:CodeCursor):Void { final valid:Bool = external.ExternalMac.setCursorIcon(icon.toInt(), null, 0, 0); diff --git a/source/funkin/backend/utils/native/Windows.hx b/source/funkin/backend/utils/native/Windows.hx index 545e34b62a..706eba21c2 100644 --- a/source/funkin/backend/utils/native/Windows.hx +++ b/source/funkin/backend/utils/native/Windows.hx @@ -27,6 +27,7 @@ import funkin.backend.utils.NativeAPI.MessageBoxIcon; #include #include #include +#include #define SAFE_RELEASE(punk) \\ if ((punk) != NULL) \\ @@ -267,5 +268,17 @@ final class Windows { { return 0; } + + @:functionCode(" + PROCESS_MEMORY_COUNTERS_EX pmc; + if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) { + return (double)pmc.WorkingSetSize; + } + return 0.0; + ") + public static function getCurrentProcessMemory():Float + { + return 0; + } } #end \ No newline at end of file diff --git a/source/funkin/options/Options.hx b/source/funkin/options/Options.hx index b3984580fe..447b7d45cf 100644 --- a/source/funkin/options/Options.hx +++ b/source/funkin/options/Options.hx @@ -38,6 +38,7 @@ class Options public static var devMode:Bool = false; public static var betaUpdates:Bool = false; public static var splashesEnabled:Bool = true; + public static var legacyMemoryCounter:Bool = false; @:dox(hide) @:doNotSave public static var hitWindow:Float = 250; // DEPRECATED public static var songOffset:Float = 0; public static var framerate:Int = 120; diff --git a/source/funkin/options/categories/DebugOptions.hx b/source/funkin/options/categories/DebugOptions.hx index 4f63da38be..b1a0263270 100644 --- a/source/funkin/options/categories/DebugOptions.hx +++ b/source/funkin/options/categories/DebugOptions.hx @@ -20,5 +20,8 @@ class DebugOptions extends TreeMenuScreen { add(new NumOption(getNameID("charterAutoSaveWarningTime"), getDescID("charterAutoSaveWarningTime"), 0, 15, 1, "charterAutoSaveWarningTime")); add(new Checkbox(getNameID("charterAutoSavesSeparateFolder"), getDescID("charterAutoSavesSeparateFolder"), "charterAutoSavesSeparateFolder")); add(new Checkbox(getNameID("songOffsetAffectEditors"), getDescID("songOffsetAffectEditors"), "songOffsetAffectEditors")); + #if (cpp && (windows || mac || linux)) + add(new Checkbox(getNameID("legacyMemoryCounter"), getDescID("legacyMemoryCounter"), "legacyMemoryCounter")); + #end } } \ No newline at end of file