use memory arena to optimize handing data to frontend

This commit is contained in:
itsmattkc 2024-11-15 16:52:19 -08:00
parent 410b002d99
commit 242386ea75
6 changed files with 103 additions and 15 deletions

View file

@ -30,6 +30,8 @@ void Backend::vanillaEventHandler()
emit vibrate(*event.data); emit vibrate(*event.data);
break; break;
} }
vanilla_free_event(&event);
} }
} }

View file

@ -3,6 +3,7 @@
#include "gamepad.h" #include "gamepad.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
@ -31,18 +32,21 @@ uint16_t PORT_AUD;
uint16_t PORT_HID; uint16_t PORT_HID;
uint16_t PORT_CMD; uint16_t PORT_CMD;
#define EVENT_BUFFER_SIZE 65536
#define EVENT_BUFFER_ARENA_SIZE VANILLA_MAX_EVENT_COUNT * 2
uint8_t *EVENT_BUFFER_ARENA[EVENT_BUFFER_ARENA_SIZE] = {0};
void send_to_console(int fd, const void *data, size_t data_size, int port) void send_to_console(int fd, const void *data, size_t data_size, int port)
{ {
struct sockaddr_in address; struct sockaddr_in address;
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_addr.s_addr = SERVER_ADDRESS; address.sin_addr.s_addr = SERVER_ADDRESS;
address.sin_port = htons((uint16_t) (port - 100)); address.sin_port = htons((uint16_t) (port - 100));
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &address.sin_addr, ip, INET_ADDRSTRLEN);
ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &address, sizeof(address)); ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &address, sizeof(address));
if (sent == -1) { if (sent == -1) {
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &address.sin_addr, ip, INET_ADDRSTRLEN);
print_info("Failed to send to Wii U socket: address: %s, fd: %d, port: %d, errno: %i", ip, fd, port - 100, errno); print_info("Failed to send to Wii U socket: address: %s, fd: %d, port: %d, errno: %i", ip, fd, port - 100, errno);
} }
} }
@ -286,12 +290,19 @@ int is_stop_code(const char *data, size_t data_length)
int push_event(event_loop_t *loop, int type, const void *data, size_t size) int push_event(event_loop_t *loop, int type, const void *data, size_t size)
{ {
pthread_mutex_lock(&loop->mutex); pthread_mutex_lock(&loop->mutex);
vanilla_event_t *ev = &loop->events[loop->new_index % VANILLA_MAX_EVENT_COUNT]; vanilla_event_t *ev = &loop->events[loop->new_index % VANILLA_MAX_EVENT_COUNT];
if (size <= sizeof(ev->data)) { if (size <= EVENT_BUFFER_SIZE) {
assert(!ev->data);
ev->data = get_event_buffer();
if (!ev->data) {
print_info("OUT OF MEMORY FOR NEW EVENTS");
return VANILLA_ERROR;
}
ev->type = type; ev->type = type;
memcpy(ev->data, data, size); memcpy(ev->data, data, size);
ev->size = size; ev->size = size;
@ -300,13 +311,14 @@ int push_event(event_loop_t *loop, int type, const void *data, size_t size)
// Prevent rollover by skipping oldest event if necessary // Prevent rollover by skipping oldest event if necessary
if (loop->new_index > loop->used_index + VANILLA_MAX_EVENT_COUNT) { if (loop->new_index > loop->used_index + VANILLA_MAX_EVENT_COUNT) {
vanilla_free_event(&loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]);
print_info("SKIPPED EVENT TO PREVENT ROLLOVER (%lu > %lu + %lu)", loop->new_index, loop->used_index, VANILLA_MAX_EVENT_COUNT); print_info("SKIPPED EVENT TO PREVENT ROLLOVER (%lu > %lu + %lu)", loop->new_index, loop->used_index, VANILLA_MAX_EVENT_COUNT);
loop->used_index++; loop->used_index++;
} }
pthread_cond_broadcast(&loop->waitcond); pthread_cond_broadcast(&loop->waitcond);
} else { } else {
print_info("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.\n", size, sizeof(ev->data)); print_info("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.\n", size, EVENT_BUFFER_SIZE);
} }
pthread_mutex_unlock(&loop->mutex); pthread_mutex_unlock(&loop->mutex);
@ -330,9 +342,11 @@ int get_event(event_loop_t *loop, vanilla_event_t *event, int wait)
vanilla_event_t *pull_event = &loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]; vanilla_event_t *pull_event = &loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT];
event->type = pull_event->type; event->type = pull_event->type;
memcpy(event->data, pull_event->data, pull_event->size); event->data = pull_event->data;
event->size = pull_event->size; event->size = pull_event->size;
pull_event->data = NULL;
loop->used_index++; loop->used_index++;
ret = 1; ret = 1;
} }
@ -341,4 +355,52 @@ int get_event(event_loop_t *loop, vanilla_event_t *event, int wait)
pthread_mutex_unlock(&loop->mutex); pthread_mutex_unlock(&loop->mutex);
return ret; return ret;
}
void *get_event_buffer()
{
void *buf = NULL;
for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) {
if (EVENT_BUFFER_ARENA[i]) {
buf = EVENT_BUFFER_ARENA[i];
EVENT_BUFFER_ARENA[i] = NULL;
break;
}
}
return buf;
}
void release_event_buffer(void *buffer)
{
for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) {
if (!EVENT_BUFFER_ARENA[i]) {
EVENT_BUFFER_ARENA[i] = buffer;
break;
}
}
}
void init_event_buffer_arena()
{
for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) {
if (!EVENT_BUFFER_ARENA[i]) {
EVENT_BUFFER_ARENA[i] = malloc(EVENT_BUFFER_SIZE);
} else {
print_info("CRITICAL: Buffer wasn't returned to the arena");
}
}
}
void free_event_buffer_arena()
{
for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) {
if (EVENT_BUFFER_ARENA[i]) {
free(EVENT_BUFFER_ARENA[i]);
EVENT_BUFFER_ARENA[i] = NULL;
} else {
print_info("CRITICAL: Buffer wasn't returned to the arena");
}
}
} }

View file

@ -42,4 +42,9 @@ int is_stop_code(const char *data, size_t data_length);
int push_event(event_loop_t *loop, int type, const void *data, size_t size); int push_event(event_loop_t *loop, int type, const void *data, size_t size);
int get_event(event_loop_t *loop, vanilla_event_t *event, int wait); int get_event(event_loop_t *loop, vanilla_event_t *event, int wait);
void init_event_buffer_arena();
void free_event_buffer_arena();
void *get_event_buffer();
void release_event_buffer(void *buffer);
#endif // VANILLA_GAMEPAD_H #endif // VANILLA_GAMEPAD_H

View file

@ -30,9 +30,13 @@ void *start_gamepad(void *arg)
struct gamepad_data_t *data = (struct gamepad_data_t *) arg; struct gamepad_data_t *data = (struct gamepad_data_t *) arg;
pthread_mutex_lock(&event_loop.mutex); pthread_mutex_lock(&event_loop.mutex);
init_event_buffer_arena();
event_loop.active = 1; event_loop.active = 1;
event_loop.new_index = 0; event_loop.new_index = 0;
event_loop.used_index = 0; event_loop.used_index = 0;
for (int i = 0; i < VANILLA_MAX_EVENT_COUNT; i++) {
event_loop.events[i].data = NULL;
}
pthread_cond_broadcast(&event_loop.waitcond); pthread_cond_broadcast(&event_loop.waitcond);
pthread_mutex_unlock(&event_loop.mutex); pthread_mutex_unlock(&event_loop.mutex);
@ -42,6 +46,7 @@ void *start_gamepad(void *arg)
pthread_mutex_lock(&event_loop.mutex); pthread_mutex_lock(&event_loop.mutex);
event_loop.active = 0; event_loop.active = 0;
free_event_buffer_arena();
pthread_cond_broadcast(&event_loop.waitcond); pthread_cond_broadcast(&event_loop.waitcond);
pthread_mutex_unlock(&event_loop.mutex); pthread_mutex_unlock(&event_loop.mutex);
@ -170,4 +175,12 @@ int vanilla_poll_event(vanilla_event_t *event)
int vanilla_wait_event(vanilla_event_t *event) int vanilla_wait_event(vanilla_event_t *event)
{ {
return get_event(&event_loop, event, 1); return get_event(&event_loop, event, 1);
}
int vanilla_free_event(vanilla_event_t *event)
{
if (event->data) {
release_event_buffer(event->data);
event->data = NULL;
}
} }

View file

@ -98,7 +98,7 @@ static const uint8_t VANILLA_PPS_PARAMS[] = {
typedef struct typedef struct
{ {
int type; int type;
uint8_t data[65536]; uint8_t *data;
size_t size; size_t size;
} vanilla_event_t; } vanilla_event_t;
@ -110,6 +110,7 @@ int vanilla_sync(uint16_t code, uint32_t server_address);
int vanilla_poll_event(vanilla_event_t *event); int vanilla_poll_event(vanilla_event_t *event);
int vanilla_wait_event(vanilla_event_t *event); int vanilla_wait_event(vanilla_event_t *event);
int vanilla_free_event(vanilla_event_t *event);
/** /**
* Attempt to stop the current action * Attempt to stop the current action

View file

@ -105,23 +105,25 @@ static SDL_mutex *decode_loop_mutex;
static SDL_cond *decode_loop_cond; static SDL_cond *decode_loop_cond;
static int decode_loop_running = 0; static int decode_loop_running = 0;
static int decode_pkt_ready = 0; static int decode_pkt_ready = 0;
static vanilla_event_t decode_event; static uint8_t decode_data[65536];
static size_t decode_size = 0;
int decode_loop(void *) int decode_loop(void *)
{ {
vanilla_event_t our_pkt; uint8_t our_data[65536];
size_t our_data_size = 0;
SDL_LockMutex(decode_loop_mutex); SDL_LockMutex(decode_loop_mutex);
while (decode_loop_running) { while (decode_loop_running) {
while (!decode_pkt_ready) { while (!decode_pkt_ready) {
SDL_CondWait(decode_loop_cond, decode_loop_mutex); SDL_CondWait(decode_loop_cond, decode_loop_mutex);
} }
our_pkt = decode_event; memcpy(our_data, decode_data, decode_size);
decode_pkt_ready = 0; our_data_size = decode_size;
SDL_UnlockMutex(decode_loop_mutex); SDL_UnlockMutex(decode_loop_mutex);
decode(our_pkt.data, our_pkt.size); decode(our_data, decode_size);
SDL_LockMutex(decode_loop_mutex); SDL_LockMutex(decode_loop_mutex);
} }
@ -153,7 +155,8 @@ int run_backend(void *data)
while (vanilla_wait_event(&event)) { while (vanilla_wait_event(&event)) {
if (event.type == VANILLA_EVENT_VIDEO) { if (event.type == VANILLA_EVENT_VIDEO) {
SDL_LockMutex(decode_loop_mutex); SDL_LockMutex(decode_loop_mutex);
decode_event = event; memcpy(decode_data, event.data, event.size);
decode_size = event.size;
decode_pkt_ready = 1; decode_pkt_ready = 1;
SDL_CondBroadcast(decode_loop_cond); SDL_CondBroadcast(decode_loop_cond);
SDL_UnlockMutex(decode_loop_mutex); SDL_UnlockMutex(decode_loop_mutex);
@ -167,6 +170,8 @@ int run_backend(void *data)
} else if (event.type == VANILLA_EVENT_VIBRATE) { } else if (event.type == VANILLA_EVENT_VIBRATE) {
vibrate = event.data[0]; vibrate = event.data[0];
} }
vanilla_free_event(&event);
} }
SDL_LockMutex(decode_loop_mutex); SDL_LockMutex(decode_loop_mutex);