#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <math.h>
#include "exp_rs.h"
#include "common_allocator.h"
#define NUM_EXPRESSIONS 7
#define NUM_PARAMETERS 10
#define RING_BUFFER_SIZE 4
#define UPDATE_RATE_HZ 1000
typedef struct {
const char* expressions[NUM_EXPRESSIONS];
const char* param_names[NUM_PARAMETERS];
double param_values_ring[RING_BUFFER_SIZE][NUM_PARAMETERS];
double results_ring[RING_BUFFER_SIZE][NUM_EXPRESSIONS];
double* param_value_ptrs[NUM_PARAMETERS];
double* result_ptrs[NUM_EXPRESSIONS];
uint32_t write_index;
uint32_t read_index;
void* batch_builder;
void* eval_context;
uint64_t total_evals;
uint64_t max_eval_time_us;
uint64_t total_eval_time_us;
} EmbeddedPool;
static EmbeddedPool g_pool = {0};
Real native_sin(const Real* args, uintptr_t n_args) {
return sin(args[0]);
}
Real native_sqrt(const Real* args, uintptr_t n_args) {
return sqrt(args[0]);
}
int embedded_pool_init(void) {
g_pool.expressions[0] = "p0 + p1";
g_pool.expressions[1] = "p0 * p1 + p2";
g_pool.expressions[2] = "sqrt(p0*p0 + p1*p1)";
g_pool.expressions[3] = "p3 * sin(p4)";
g_pool.expressions[4] = "p5 + p6 - p7";
g_pool.expressions[5] = "p8 * p8 * p9";
g_pool.expressions[6] = "(p0 + p1 + p2) / 3.0";
for (int i = 0; i < NUM_PARAMETERS; i++) {
static char names[NUM_PARAMETERS][4];
sprintf(names[i], "p%d", i);
g_pool.param_names[i] = names[i];
}
g_pool.eval_context = expr_context_new();
if (!g_pool.eval_context) {
printf("Failed to create context\n");
return -1;
}
int32_t result;
result = expr_context_add_function(g_pool.eval_context, "sin", 1, native_sin);
if (result != 0) {
printf("Failed to register sin function: %d\n", result);
return -1;
}
result = expr_context_add_function(g_pool.eval_context, "sqrt", 1, native_sqrt);
if (result != 0) {
printf("Failed to register sqrt function: %d\n", result);
return -1;
}
g_pool.batch_builder = expr_batch_new(16384); if (!g_pool.batch_builder) {
printf("Failed to create batch builder\n");
expr_context_free(g_pool.eval_context);
return -1;
}
for (int i = 0; i < NUM_EXPRESSIONS; i++) {
ExprResult result = expr_batch_add_expression(
g_pool.batch_builder,
g_pool.expressions[i]
);
if (result.status != 0) {
printf("Failed to add expression %d: %s (error: %s)\n", i, g_pool.expressions[i], result.error);
return -1;
}
}
for (int i = 0; i < NUM_PARAMETERS; i++) {
ExprResult result = expr_batch_add_variable(
g_pool.batch_builder,
g_pool.param_names[i],
0.0
);
if (result.status != 0) {
printf("Failed to add parameter %s (error: %s)\n", g_pool.param_names[i], result.error);
return -1;
}
}
g_pool.write_index = 0;
g_pool.read_index = 0;
return 0;
}
void embedded_pool_update_params(const double* new_values) {
uint32_t idx = g_pool.write_index & (RING_BUFFER_SIZE - 1);
memcpy(g_pool.param_values_ring[idx], new_values,
NUM_PARAMETERS * sizeof(double));
g_pool.write_index++;
}
int embedded_pool_process(void) {
if (g_pool.read_index >= g_pool.write_index) {
return 0; }
uint32_t idx = g_pool.read_index & (RING_BUFFER_SIZE - 1);
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i = 0; i < NUM_PARAMETERS; i++) {
expr_batch_set_variable(
g_pool.batch_builder,
i,
g_pool.param_values_ring[idx][i]
);
}
int32_t result = expr_batch_evaluate(
g_pool.batch_builder,
g_pool.eval_context
);
if (result != 0) {
printf("Evaluation failed with code %d\n", result);
return -1;
}
for (int i = 0; i < NUM_EXPRESSIONS; i++) {
g_pool.results_ring[idx][i] = expr_batch_get_result(
g_pool.batch_builder,
i
);
}
clock_gettime(CLOCK_MONOTONIC, &end);
uint64_t elapsed_us = (end.tv_sec - start.tv_sec) * 1000000 +
(end.tv_nsec - start.tv_nsec) / 1000;
g_pool.total_eval_time_us += elapsed_us;
if (elapsed_us > g_pool.max_eval_time_us) {
g_pool.max_eval_time_us = elapsed_us;
}
g_pool.total_evals++;
g_pool.read_index++;
return 1; }
int embedded_pool_get_results(uint32_t batch_offset, double* results) {
if (batch_offset >= RING_BUFFER_SIZE) {
return -1;
}
uint32_t idx = (g_pool.read_index - 1 - batch_offset) & (RING_BUFFER_SIZE - 1);
if (g_pool.read_index <= batch_offset) {
return -2; }
memcpy(results, g_pool.results_ring[idx],
NUM_EXPRESSIONS * sizeof(double));
return 0;
}
void embedded_pool_cleanup(void) {
if (g_pool.batch_builder) {
expr_batch_free(g_pool.batch_builder);
g_pool.batch_builder = NULL;
}
if (g_pool.eval_context) {
expr_context_free(g_pool.eval_context);
g_pool.eval_context = NULL;
}
}
int main() {
init_memory_tracking();
printf("=== Embedded Memory Pool Test ===\n");
printf("Expressions: %d, Parameters: %d, Rate: %d Hz\n\n",
NUM_EXPRESSIONS, NUM_PARAMETERS, UPDATE_RATE_HZ);
if (embedded_pool_init() != 0) {
printf("Failed to initialize pool\n");
return 1;
}
printf("Memory pool initialized successfully\n");
printf("All expressions parsed, no further allocations will occur\n\n");
int iterations = UPDATE_RATE_HZ;
double params[NUM_PARAMETERS];
double results[NUM_EXPRESSIONS];
for (int i = 0; i < iterations; i++) {
for (int j = 0; j < NUM_PARAMETERS; j++) {
params[j] = (double)(i + j) / 100.0;
}
embedded_pool_update_params(params);
while (embedded_pool_process() > 0) {
}
if (i % 100 == 99) {
embedded_pool_get_results(0, results);
printf("Iteration %d: First result = %.6f\n", i + 1, results[0]);
}
}
printf("\n=== Performance Statistics ===\n");
printf("Total evaluations: %llu\n", (unsigned long long)g_pool.total_evals);
printf("Average eval time: %.2f μs\n",
(double)g_pool.total_eval_time_us / g_pool.total_evals);
printf("Maximum eval time: %llu μs\n", (unsigned long long)g_pool.max_eval_time_us);
printf("Total memory allocated: 0 bytes (after initialization)\n");
embedded_pool_get_results(0, results);
printf("\nFinal results:\n");
for (int i = 0; i < NUM_EXPRESSIONS; i++) {
printf(" Expression %d: %.6f\n", i, results[i]);
}
embedded_pool_cleanup();
printf("\nTest complete\n");
return 0;
}