Android: Pin emu thread to exclusive cores where supported

This commit is contained in:
Connor McLaughlin 2021-01-27 00:36:13 +10:00
parent 700f916a34
commit 35dc530b9a
3 changed files with 45 additions and 0 deletions

View file

@ -22,6 +22,8 @@
#include "scmversion/scmversion.h" #include "scmversion/scmversion.h"
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include <cmath> #include <cmath>
#include <unistd.h>
#include <sched.h>
#include <imgui.h> #include <imgui.h>
Log_SetChannel(AndroidHostInterface); Log_SetChannel(AndroidHostInterface);
@ -952,6 +954,31 @@ DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_getFullScmVersion, jobject
g_scm_branch_str, __DATE__, __TIME__)); g_scm_branch_str, __DATE__, __TIME__));
} }
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setThreadAffinity, jobject unused, jintArray cores)
{
// https://github.com/googlearchive/android-audio-high-performance/blob/c232c21bf35d3bfea16537b781c526b8abdcc3cf/SimpleSynth/app/src/main/cpp/audio_player.cc
int length = env->GetArrayLength(cores);
int* p_cores = env->GetIntArrayElements(cores, nullptr);
pid_t current_thread_id = gettid();
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
for (int i = 0; i < length; i++)
{
Log_InfoPrintf("Binding to CPU %d", p_cores[i]);
CPU_SET(p_cores[i], &cpu_set);
}
int result = sched_setaffinity(current_thread_id, sizeof(cpu_set_t), &cpu_set);
if (result != 0)
Log_InfoPrintf("Thread affinity set.");
else
Log_ErrorPrintf("Error setting thread affinity: %d", result);
env->ReleaseIntArrayElements(cores, p_cores, 0);
}
DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused, jobject context_object, DEFINE_JNI_ARGS_METHOD(jobject, AndroidHostInterface_create, jobject unused, jobject context_object,
jstring user_directory) jstring user_directory)
{ {

View file

@ -45,6 +45,8 @@ public class AndroidHostInterface {
static public native String getFullScmVersion(); static public native String getFullScmVersion();
static public native boolean setThreadAffinity(int[] cpus);
static public native AndroidHostInterface create(Context context, String userDirectory); static public native AndroidHostInterface create(Context context, String userDirectory);
public native boolean isEmulationThreadRunning(); public native boolean isEmulationThreadRunning();

View file

@ -1,5 +1,6 @@
package com.github.stenzek.duckstation; package com.github.stenzek.duckstation;
import android.os.Build;
import android.os.Process; import android.os.Process;
import android.util.Log; import android.util.Log;
import android.view.Surface; import android.view.Surface;
@ -28,10 +29,25 @@ public class EmulationThread extends Thread {
return thread; return thread;
} }
private void setExclusiveCores() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
int[] cores = Process.getExclusiveCores();
if (cores == null || cores.length == 0)
throw new Exception("Invalid return value from getExclusiveCores()");
AndroidHostInterface.setThreadAffinity(cores);
}
} catch (Exception e) {
Log.e("EmulationThread", "getExclusiveCores() failed");
}
}
@Override @Override
public void run() { public void run() {
try { try {
Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE); Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
setExclusiveCores();
} catch (Exception e) { } catch (Exception e) {
Log.i("EmulationThread", "Failed to set priority for emulation thread: " + e.getMessage()); Log.i("EmulationThread", "Failed to set priority for emulation thread: " + e.getMessage());
} }