Add memory pool test, fix bugs

This commit is contained in:
Rickey Fehr
2025-10-17 18:01:34 -07:00
parent 16059ab632
commit 138792df48
11 changed files with 171 additions and 25 deletions
+3
View File
@@ -53,6 +53,9 @@ jobs:
echo "UID=$(id -u)" >> "$GITHUB_ENV" echo "UID=$(id -u)" >> "$GITHUB_ENV"
echo "GID=$(id -g)" >> "$GITHUB_ENV" echo "GID=$(id -g)" >> "$GITHUB_ENV"
- name: Run Tests
run: cd tests && ./run_tests.sh
- name: Build the project - name: Build the project
run: docker compose -f docker-compose.yml run --rm balatro sh -c "make -j$(nproc) && ./scripts/get_memory_map.sh" run: docker compose -f docker-compose.yml run --rm balatro sh -c "make -j$(nproc) && ./scripts/get_memory_map.sh"
+1
View File
@@ -4,3 +4,4 @@
*.sln *.sln
*.vcxproj* *.vcxproj*
/balatro-gba/x64/** /balatro-gba/x64/**
/tests/pool/build
+10 -8
View File
@@ -25,13 +25,14 @@ LIBTONC := $(DEVKITPRO)/libtonc
# the makefile is found # the makefile is found
# #
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR)) TARGET := $(notdir $(CURDIR))
BUILD := build BUILD := build
SOURCES := source SOURCES := source
INCLUDES := include INCLUDES := include
DATA := DATA :=
MUSIC := audio MUSIC := audio
GRAPHICS := graphics GRAPHICS := graphics
POOLS_DEF_FILE := \"pools.def\"
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# options for code generation # options for code generation
@@ -42,7 +43,8 @@ GIT_DIRTY := $(shell git diff-index --quiet HEAD -- || echo "-dirty")
GIT_HASH := $(shell git rev-parse --short HEAD || echo "undef") GIT_HASH := $(shell git rev-parse --short HEAD || echo "undef")
GIT_C_FLAGS := -DGIT_HASH=\"$(GIT_HASH)\" -DGIT_DIRTY=\"$(GIT_DIRTY)\" GIT_C_FLAGS := -DGIT_HASH=\"$(GIT_HASH)\" -DGIT_DIRTY=\"$(GIT_DIRTY)\"
CFLAGS := -g -O3 -Wall -Werror\ CFLAGS := -g -O3 -Wall -Werror \
-DPOOLS_DEF_FILE=$(POOLS_DEF_FILE) \
-mcpu=arm7tdmi -mtune=arm7tdmi \ -mcpu=arm7tdmi -mtune=arm7tdmi \
-ffast-math -fomit-frame-pointer -funroll-loops \ -ffast-math -fomit-frame-pointer -funroll-loops \
$(ARCH) $(ARCH)
+9 -9
View File
@@ -1,16 +1,16 @@
#ifndef POOL_H #ifndef POOL_H
#define POOL_H #define POOL_H
#include <tonc.h> #include <stdint.h>
#define POOL_BITS_PER_WORD 32 #define POOL_BITS_PER_WORD 32
#define POOL_MAX_CAPACITY 128 #define POOL_BITMAP_BYTES 8
typedef struct PoolBitmap { typedef struct PoolBitmap {
u32 *w; uint32_t *w;
u32 nbits; uint32_t nbits;
u32 nwords; uint32_t nwords;
u32 cap; uint32_t cap;
} PoolBitmap; } PoolBitmap;
void pool_bm_clear_idx(PoolBitmap *bm, int idx); void pool_bm_clear_idx(PoolBitmap *bm, int idx);
@@ -27,13 +27,13 @@ int pool_bm_get_free_idx(PoolBitmap *bm);
#define POOL_DEFINE_TYPE(type, capacity) \ #define POOL_DEFINE_TYPE(type, capacity) \
static type type##_storage[capacity]; \ static type type##_storage[capacity]; \
static u32 type##_bitmap_w[sizeof(u32)] = {0}; \ static uint32_t type##_bitmap_w[POOL_BITMAP_BYTES] = {0}; \
static type##Pool type##_pool = \ static type##Pool type##_pool = \
{ \ { \
.bm = { \ .bm = { \
.w = type##_bitmap_w, \ .w = type##_bitmap_w, \
.nbits = POOL_BITS_PER_WORD, \ .nbits = POOL_BITS_PER_WORD, \
.nwords = sizeof(u32), \ .nwords = POOL_BITMAP_BYTES, \
.cap = capacity, \ .cap = capacity, \
}, \ }, \
.objects = type##_storage, \ .objects = type##_storage, \
@@ -56,7 +56,7 @@ int pool_bm_get_free_idx(PoolBitmap *bm);
#define POOL_ENTRY(name, capacity) \ #define POOL_ENTRY(name, capacity) \
POOL_DECLARE_TYPE(name); POOL_DECLARE_TYPE(name);
#include "pools.def" #include POOLS_DEF_FILE
#undef POOL_ENTRY #undef POOL_ENTRY
#endif // POOL_H #endif // POOL_H
-1
View File
@@ -61,7 +61,6 @@ for name in $(get_pool_names); do
pool_size="$(cut -d ' ' -f 3 <<< $output_pool)" pool_size="$(cut -d ' ' -f 3 <<< $output_pool)"
func_size="$(cut -d ' ' -f 3 <<< $output_func)" func_size="$(cut -d ' ' -f 3 <<< $output_func)"
bm_size="$(cut -d ' ' -f 3 <<< $output_bm)" bm_size="$(cut -d ' ' -f 3 <<< $output_bm)"
#bm_size=16 #always gonna be 16, 4 * sizeof(u32)
TOTAL_BYTES=$(( TOTAL_BYTES + pool_size + func_size + bm_size )) TOTAL_BYTES=$(( TOTAL_BYTES + pool_size + func_size + bm_size ))
+7 -7
View File
@@ -3,17 +3,17 @@
void pool_bm_clear_idx(PoolBitmap *bm, int idx) void pool_bm_clear_idx(PoolBitmap *bm, int idx)
{ {
// Divide by 32 to get the word index // Divide by 32 to get the word index
u32 i = idx >> 5; uint32_t i = idx >> 5;
// Get last 5-bits, same as a modulo (% 32) operation on positive numbers // Get last 5-bits, same as a modulo (% 32) operation on positive numbers
u32 b = idx & 0x1F; uint32_t b = idx & 0x1F;
bm->w[i] &= ~((u32)1 << b); bm->w[i] &= ~((uint32_t)1 << b);
} }
int pool_bm_get_free_idx(PoolBitmap *bm) int pool_bm_get_free_idx(PoolBitmap *bm)
{ {
for (u32 i = 0; i < bm->nwords; i++) for (uint32_t i = 0; i < bm->nwords; i++)
{ {
u32 inv = ~bm->w[i]; uint32_t inv = ~bm->w[i];
// guard so we don't call `ctz` with 0, since __builtin_ctz(0) is undefined // guard so we don't call `ctz` with 0, since __builtin_ctz(0) is undefined
// https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html#index-_005f_005fbuiltin_005fctz // https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html#index-_005f_005fbuiltin_005fctz
@@ -26,7 +26,7 @@ int pool_bm_get_free_idx(PoolBitmap *bm)
if (inv) if (inv)
{ {
int bit = __builtin_ctz(inv); int bit = __builtin_ctz(inv);
bm->w[i] |= ((u32)1 << bit); bm->w[i] |= ((uint32_t)1 << bit);
int idx = i * POOL_BITS_PER_WORD + bit; int idx = i * POOL_BITS_PER_WORD + bit;
return (idx < bm->cap) ? idx : -1; return (idx < bm->cap) ? idx : -1;
} }
@@ -38,5 +38,5 @@ int pool_bm_get_free_idx(PoolBitmap *bm)
#define POOL_ENTRY(name, capacity) \ #define POOL_ENTRY(name, capacity) \
POOL_DEFINE_TYPE(name, capacity); POOL_DEFINE_TYPE(name, capacity);
#include "pools.def" #include POOLS_DEF_FILE
#undef POOL_ENTRY #undef POOL_ENTRY
+17
View File
@@ -0,0 +1,17 @@
POOLS_DEF_FILE := \"test_pools.def\"
CC := gcc
CFLAGS := -I../../include -I. \
-g -O3 -Wall -Werror -DPOOLS_DEF_FILE=$(POOLS_DEF_FILE)
SRC := pool_test.c ../../source/pool.c
OUT := build/pool_test
$(OUT): $(SRC) | build
$(CC) $(CFLAGS) -o $@ $^
build:
mkdir -p build
clean:
rm -f $(OUT)
+87
View File
@@ -0,0 +1,87 @@
#include "pool.h"
#include "test_structures.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int get_random(int low, int high)
{
srand(time(NULL));
int n = low + rand() % (high - low + 1);
return n;
}
bool test_fill(ChunkOfData* myPtrs[], int check_size)
{
int itr = 0;
ChunkOfData* test_chunk = NULL;
do
{
test_chunk = POOL_GET(ChunkOfData);
if(test_chunk != NULL) myPtrs[itr++] = test_chunk;
} while(test_chunk != NULL);
if(itr != check_size)
{
fprintf(stderr, "Error: failed to get expected number of valid pointers\n"
" expected: %d, actual %d\n", check_size, itr);
return false;
}
return true;
}
bool test_fill_and_empty(void)
{
ChunkOfData* myPtrs[TEST_SIZE];
if(!test_fill(myPtrs, TEST_SIZE)) return false;
for(int itr = TEST_SIZE; itr >= 0; --itr)
{
POOL_FREE(ChunkOfData, myPtrs[itr]);
}
return true;
}
bool test_fill_and_remove_at_random_and_refill_and_empty(void)
{
ChunkOfData* myPtrs[TEST_SIZE];
if(!test_fill(myPtrs, TEST_SIZE)) return false;
// remove between 10 and TEST_SIZE
int number_to_remove = get_random(100, TEST_SIZE);
for(int itr = 0; itr < number_to_remove; itr++)
{
POOL_FREE(ChunkOfData, myPtrs[itr]);
}
if(!test_fill(myPtrs, number_to_remove)) return false;
for(int itr = 0; itr < TEST_SIZE; itr++)
{
POOL_FREE(ChunkOfData, myPtrs[itr]);
}
return true;
}
int main(void)
{
// Test it twice to make sure empty works, kinda hacky.
if(!test_fill_and_empty()) return -1;
if(!test_fill_and_empty()) return -1;
// Similarly here, verify that fill, random num removal, refill, and empty
// by refilling and emptying again
if(!test_fill_and_remove_at_random_and_refill_and_empty()) return -1;
if(!test_fill_and_empty()) return -1;
printf("Pool Tests Passed\n");
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
#include "test_structures.h"
#define TEST_SIZE 240
POOL_ENTRY(ChunkOfData, TEST_SIZE);
+18
View File
@@ -0,0 +1,18 @@
#ifndef POOL_TEST_STRUCTURES
#define POOL_TEST_STRUCTURES
#include <stddef.h>
typedef struct
{
union
{
int my_int;
float my_float;
char my_char;
} GenericData;
int my_type;
} ChunkOfData;
#endif // POOL_TEST_STRUCTURES
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
set -eu
run_pool_test() {
cd pool
make clean
make
./build/pool_test
cd - > /dev/null
}
run_pool_test