aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimmy Andersson <cyaspik@gmail.com>2021-01-09 22:18:57 +0100
committerGitHub <noreply@github.com>2021-01-09 22:18:57 +0100
commitbf97387f26813415d0a4f56d816eeb8e50711b17 (patch)
treef26ddb5447d598a04db10ff25861d1fda8ccdd9a /src
parent6b306e18a563b0118012a0e601f7be1446bf4e83 (diff)
Improved SRAM performance (#925)
* Offload NDS SRAM writing to separate thread, debounce writes to two seconds after last flush or DeInit. * Fixed printf messages. * Fixes after CR. * Fixed potential portability issue with time_t
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/NDS.cpp3
-rw-r--r--src/NDSCart.cpp15
-rw-r--r--src/NDSCart_SRAMManager.cpp147
-rw-r--r--src/NDSCart_SRAMManager.h33
-rw-r--r--src/Platform.h2
-rw-r--r--src/frontend/qt_sdl/Platform.cpp5
7 files changed, 195 insertions, 11 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9f07cea..bd1f31e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -33,6 +33,7 @@ add_library(core STATIC
melonDLDI.h
NDS.cpp
NDSCart.cpp
+ NDSCart_SRAMManager.cpp
Platform.h
ROMList.h
RTC.cpp
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 7131bae..00c7389 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -32,6 +32,7 @@
#include "Wifi.h"
#include "AREngine.h"
#include "Platform.h"
+#include "NDSCart_SRAMManager.h"
#ifdef JIT_ENABLED
#include "ARMJIT.h"
@@ -190,6 +191,7 @@ bool Init()
DMAs[6] = new DMA(1, 2);
DMAs[7] = new DMA(1, 3);
+ if (!NDSCart_SRAMManager::Init()) return false;
if (!NDSCart::Init()) return false;
if (!GBACart::Init()) return false;
if (!GPU::Init()) return false;
@@ -217,6 +219,7 @@ void DeInit()
for (int i = 0; i < 8; i++)
delete DMAs[i];
+ NDSCart_SRAMManager::DeInit();
NDSCart::DeInit();
GBACart::DeInit();
GPU::DeInit();
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp
index fa235a4..0765288 100644
--- a/src/NDSCart.cpp
+++ b/src/NDSCart.cpp
@@ -27,7 +27,7 @@
#include "Config.h"
#include "ROMList.h"
#include "melonDLDI.h"
-
+#include "NDSCart_SRAMManager.h"
namespace NDSCart_SRAM
{
@@ -145,6 +145,8 @@ void LoadSave(const char* path, u32 type)
}
}
+ NDSCart_SRAMManager::Setup(path, SRAM, SRAMLength);
+
switch (SRAMLength)
{
case 512: WriteFunc = Write_EEPROMTiny; break;
@@ -450,17 +452,10 @@ void Write(u8 val, u32 hold)
void FlushSRAMFile()
{
- if (!SRAMFileDirty)
- return;
+ if (!SRAMFileDirty) return;
SRAMFileDirty = false;
-
- FILE* f = Platform::OpenFile(SRAMPath, "wb");
- if (f)
- {
- fwrite(SRAM, SRAMLength, 1, f);
- fclose(f);
- }
+ NDSCart_SRAMManager::RequestFlush();
}
}
diff --git a/src/NDSCart_SRAMManager.cpp b/src/NDSCart_SRAMManager.cpp
new file mode 100644
index 0000000..88ff40b
--- /dev/null
+++ b/src/NDSCart_SRAMManager.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright 2016-2020 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include "NDSCart_SRAMManager.h"
+#include "Platform.h"
+
+namespace NDSCart_SRAMManager
+{
+ Platform::Thread* FlushThread;
+ bool FlushThreadRunning;
+ Platform::Mutex* SecondaryBufferLock;
+
+ char Path[1024];
+
+ u8* Buffer;
+ u32 Length;
+
+ u8* SecondaryBuffer;
+ u32 SecondaryBufferLength;
+
+ time_t TimeAtLastFlushRequest;
+
+ // We keep versions in case the user closes the application before
+ // a flush cycle is finished.
+ u32 PreviousFlushVersion;
+ u32 FlushVersion;
+
+ void FlushThreadFunc();
+ void FlushSecondaryBufferToFile();
+
+ bool Init()
+ {
+ FlushThread = Platform::Thread_Create(FlushThreadFunc);
+ FlushThreadRunning = true;
+
+ SecondaryBufferLock = Platform::Mutex_Create();
+
+ return true;
+ }
+
+ void DeInit()
+ {
+ if (FlushThreadRunning)
+ {
+ FlushThreadRunning = false;
+ Platform::Thread_Wait(FlushThread);
+ Platform::Thread_Free(FlushThread);
+ FlushSecondaryBufferToFile();
+ }
+
+ delete SecondaryBuffer;
+
+ Platform::Mutex_Free(SecondaryBufferLock);
+ }
+
+ void Setup(const char* path, u8* buffer, u32 length)
+ {
+ // Flush SRAM in case there is unflushed data from previous state.
+ FlushSecondaryBufferToFile();
+
+ Platform::Mutex_Lock(SecondaryBufferLock);
+
+ strncpy(Path, path, 1023);
+ Path[1023] = '\0';
+
+ Buffer = buffer;
+ Length = length;
+
+ delete SecondaryBuffer; // Delete secondary buffer, there might be previous state.
+
+ SecondaryBuffer = new u8[length];
+ SecondaryBufferLength = length;
+
+ FlushVersion = 0;
+ PreviousFlushVersion = 0;
+ TimeAtLastFlushRequest = 0;
+
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+ }
+
+ void RequestFlush()
+ {
+ Platform::Mutex_Lock(SecondaryBufferLock);
+ printf("NDS SRAM: Flush requested\n");
+ memcpy(SecondaryBuffer, Buffer, Length);
+ FlushVersion++;
+ TimeAtLastFlushRequest = time(NULL);
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+ }
+
+ void FlushThreadFunc()
+ {
+ for (;;)
+ {
+ Platform::Sleep(100 * 1000); // 100ms
+
+ if (!FlushThreadRunning) return;
+
+ // We debounce for two seconds after last flush request to ensure that writing has finished.
+ if (TimeAtLastFlushRequest == 0 || difftime(time(NULL), TimeAtLastFlushRequest) < 2)
+ {
+ continue;
+ }
+
+ FlushSecondaryBufferToFile();
+ }
+ }
+
+ void FlushSecondaryBufferToFile()
+ {
+ if (FlushVersion == PreviousFlushVersion)
+ {
+ return;
+ }
+
+ Platform::Mutex_Lock(SecondaryBufferLock);
+ FILE* f = Platform::OpenFile(Path, "wb");
+ if (f)
+ {
+ printf("NDS SRAM: Written\n");
+ fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
+ fclose(f);
+ }
+ PreviousFlushVersion = FlushVersion;
+ TimeAtLastFlushRequest = 0;
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+ }
+}
diff --git a/src/NDSCart_SRAMManager.h b/src/NDSCart_SRAMManager.h
new file mode 100644
index 0000000..2486af2
--- /dev/null
+++ b/src/NDSCart_SRAMManager.h
@@ -0,0 +1,33 @@
+/*
+ Copyright 2016-2020 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NDSCART_SRAMMANAGER_H
+#define NDSCART_SRAMMANAGER_H
+
+#include "types.h"
+
+namespace NDSCart_SRAMManager
+{
+ bool Init();
+ void DeInit();
+
+ void Setup(const char* path, u8* buffer, u32 length);
+ void RequestFlush();
+}
+
+#endif // NDSCART_SRAMMANAGER_H \ No newline at end of file
diff --git a/src/Platform.h b/src/Platform.h
index b4dda9e..42e1e24 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -102,6 +102,8 @@ void LAN_DeInit();
int LAN_SendPacket(u8* data, int len);
int LAN_RecvPacket(u8* data);
+void Sleep(u64 usecs);
+
}
#endif // PLATFORM_H
diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp
index d3480e4..7c4b553 100644
--- a/src/frontend/qt_sdl/Platform.cpp
+++ b/src/frontend/qt_sdl/Platform.cpp
@@ -207,7 +207,6 @@ void Thread_Wait(Thread* thread)
((QThread*) thread)->wait();
}
-
Semaphore* Semaphore_Create()
{
return (Semaphore*)new QSemaphore();
@@ -443,5 +442,9 @@ int LAN_RecvPacket(u8* data)
return LAN_Socket::RecvPacket(data);
}
+void Sleep(u64 usecs)
+{
+ QThread::usleep(usecs);
+}
}