Skip to content

Instantly share code, notes, and snippets.

@memononen
Last active November 12, 2025 09:13
Show Gist options
  • Select an option

  • Save memononen/c4944a6815fd4c60381f5fe91d109b17 to your computer and use it in GitHub Desktop.

Select an option

Save memononen/c4944a6815fd4c60381f5fe91d109b17 to your computer and use it in GitHub Desktop.
Process entities
///
static inline int32_t mot_bitset_next(uint64_t* bitset)
{
const int32_t idx = (int32_t)mot_tzcnt64(*bitset); // trailing zero count
*bitset &= (*bitset - 1); // clear lsb
return idx;
}
typedef struct pos_comp_t {
mot_vec2_t pos;
} pos_comp_t;
typedef struct move_comp_t {
mot_vec2_t dir;
float speed;
} move_comp_t;
//
// Simple loop
//
void test_loop(int32_t iters, int32_t count, float dt)
{
pos_comp_t* pos_comps = mot_malloc(count * sizeof(pos_comp_t));
move_comp_t* move_comps = mot_malloc(count * sizeof(move_comp_t));
for (int32_t i = 0; i < count; i++)
init_pos_comp(&pos_comps[i]);
for (int32_t i = 0; i < count; i++)
init_move_comp(&move_comps[i]);
const int64_t t0 = mot_perf_timer_get();
for (int32_t it = 0; it < iters; it++) {
pos_comp_t* pos = pos_comps;
move_comp_t* move = move_comps;
int32_t n = count;
while (n--) {
pos->pos = mot_vec2_mad(pos->pos, move->dir, move->speed * dt);
pos++;
move++;
}
}
const int64_t t1 = mot_perf_timer_get();
mot_debug_log("test_loop %d x %d: %d us\n", iters, count, mot_perf_timer_elapsed_us(t0,t1));
mot_free(pos_comps);
mot_free(move_comps);
}
//
// Enabled flags + function ptr
//
typedef void process_func_sparse_t(uint64_t bitset, uint8_t** data, int32_t data_count, float dt);
void process_chunk_sparse(uint64_t bitset, uint8_t** data, int32_t data_count, float dt)
{
pos_comp_t* pos = (pos_comp_t*)data[0];
move_comp_t* move = (move_comp_t*)data[1];
while (bitset) {
const int32_t i = mot_bitset_next(&bitset);
pos[i].pos = mot_vec2_mad(pos[i].pos, move[i].dir, move[i].speed * dt);
}
}
void process_sparse(const uint64_t* enabled_bitset, uint8_t** data, const int32_t* data_stride, int32_t data_count, int32_t elem_count, float dt, process_func_sparse_t* func)
{
int32_t chunk_count = (elem_count+63) / 64;
uint8_t* chunk_data[8];
for (int32_t di = 0; di < data_count; di++)
chunk_data[di] = data[di];
for (int32_t i = 0; i < chunk_count; i++) {
// Process 64 items
uint64_t bitset = enabled_bitset[i];
func(bitset, chunk_data, data_count, dt);
// Advance to next chunk
for (int32_t di = 0; di < data_count; di++)
chunk_data[di] += data_stride[di];
}
}
void test_loop_func_sparse(int32_t iters, int32_t count, int32_t enabled_count, float dt)
{
assert(enabled_count <= count);
pos_comp_t* pos_comps = mot_malloc(count * sizeof(pos_comp_t));
move_comp_t* move_comps = mot_malloc(count * sizeof(move_comp_t));
int32_t enabled_bitset_count = (count+63)/64;
uint64_t* enabled_bitset = mot_malloc(enabled_bitset_count * sizeof(uint64_t));
memset(enabled_bitset, 0, enabled_bitset_count * sizeof(uint64_t));
enable_random(enabled_bitset, enabled_bitset_count, count, enabled_count);
for (int32_t i = 0; i < count; i++)
init_pos_comp(&pos_comps[i]);
for (int32_t i = 0; i < count; i++)
init_move_comp(&move_comps[i]);
const int64_t t0 = mot_perf_timer_get();
for (int32_t it = 0; it < iters; it++) {
uint8_t* data[2] = { (uint8_t*)pos_comps, (uint8_t*)move_comps };
const int32_t data_stride[2] = { sizeof(pos_comp_t) * 64, sizeof(move_comp_t) * 64 };
process_sparse(enabled_bitset, data, data_stride, 2, count, dt, process_chunk_sparse);
}
const int64_t t1 = mot_perf_timer_get();
mot_debug_log("test_loop_func_sparse %d x %d (%d, %.1f%%): %d us\n", iters, count, enabled_count, (float)enabled_count/(float)count*100.f, mot_perf_timer_elapsed_us(t0,t1));
mot_free(pos_comps);
mot_free(move_comps);
mot_free(enabled_bitset);
}
//
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment