← Back to C-Kernel-Engine Docs Doxygen Source Documentation
ck_metrics.h
Go to the documentation of this file.
1 /**
2  * ck_metrics.h - C-Kernel Engine Training Metrics API
3  *
4  * Lightweight metrics logging for real-time training dashboards.
5  * Sends metrics to the ANTSAND live training dashboard via HTTP POST
6  * or writes to a local file for batch upload.
7  *
8  * Usage:
9  * ck_metrics_init("run_001", "http://localhost/labs/metrics/log");
10  *
11  * for (int step = 0; step < max_steps; step++) {
12  * // ... training step ...
13  * ck_metrics_log_f("loss", loss);
14  * ck_metrics_log_f("lr", lr);
15  * ck_metrics_log_f("grad_norm", grad_norm);
16  * ck_metrics_log_i("tokens_per_sec", tokens_per_sec);
17  * ck_metrics_log_i("memory_mb", get_memory_usage_mb());
18  * ck_metrics_step(step); // Flush metrics for this step
19  * }
20  *
21  * ck_metrics_end("completed");
22  *
23  * Build:
24  * Link with -lcurl for HTTP mode, or use file mode for no dependencies.
25  */
26 
27 #ifndef CK_METRICS_H
28 #define CK_METRICS_H
29 
30 #include <stdint.h>
31 #include <stdbool.h>
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 // ═══════════════════════════════════════════════════════════════════════════════
38 // Configuration
39 // ═══════════════════════════════════════════════════════════════════════════════
40 
41 #define CK_METRICS_MAX_NAME_LEN 64
42 #define CK_METRICS_MAX_METRICS 32
43 #define CK_METRICS_MAX_URL_LEN 256
44 #define CK_METRICS_BUFFER_SIZE 4096
45 
46 // Transport modes
47 typedef enum {
48  CK_METRICS_MODE_HTTP, // Send via HTTP POST (requires libcurl)
49  CK_METRICS_MODE_FILE, // Write to local JSONL file
50  CK_METRICS_MODE_STDOUT, // Print to stdout (debug)
51  CK_METRICS_MODE_DISABLED // No-op (for benchmarking without overhead)
53 
54 // Metric types
55 typedef enum {
60 
61 // Single metric entry
62 typedef struct {
65  union {
66  double f;
67  int64_t i;
69  } value;
70 } CKMetric;
71 
72 // Metrics context
73 typedef struct {
75  char endpoint[CK_METRICS_MAX_URL_LEN];
76  char file_path[CK_METRICS_MAX_URL_LEN];
78 
79  // Current step metrics
82  int64_t current_step;
83 
84  // Config (sent once at start)
85  char model_name[CK_METRICS_MAX_NAME_LEN];
86  char dataset_name[CK_METRICS_MAX_NAME_LEN];
88  double learning_rate;
89  int max_steps;
90 
91  // Internal state
93  void* curl_handle; // libcurl easy handle
94  FILE* file_handle; // For file mode
96 
97 // Global context (for convenience API)
99 
100 // ═══════════════════════════════════════════════════════════════════════════════
101 // Core API
102 // ═══════════════════════════════════════════════════════════════════════════════
103 
104 /**
105  * Initialize metrics logging
106  *
107  * @param run_id Unique identifier for this training run (e.g., "run_20260104_093000")
108  * @param endpoint HTTP endpoint or file path depending on mode
109  * @param mode Transport mode (HTTP, FILE, STDOUT, DISABLED)
110  * @return true on success
111  */
112 bool ck_metrics_init(const char* run_id, const char* endpoint, CKMetricsMode mode);
113 
114 /**
115  * Initialize with full configuration
116  */
117 bool ck_metrics_init_full(const char* run_id, const char* endpoint, CKMetricsMode mode,
118  const char* model, const char* dataset,
119  int batch_size, double lr, int max_steps);
120 
121 /**
122  * Log a float metric (e.g., loss, learning rate)
123  */
124 void ck_metrics_log_f(const char* name, double value);
125 
126 /**
127  * Log an integer metric (e.g., step, tokens_per_sec)
128  */
129 void ck_metrics_log_i(const char* name, int64_t value);
130 
131 /**
132  * Log a string metric (e.g., phase, status)
133  */
134 void ck_metrics_log_s(const char* name, const char* value);
135 
136 /**
137  * Flush metrics for the current step and advance to next step
138  * Call this at the end of each training step
139  *
140  * @param step Current training step number
141  */
142 void ck_metrics_step(int64_t step);
143 
144 /**
145  * End the training run
146  *
147  * @param status Final status ("completed", "failed", "interrupted")
148  */
149 void ck_metrics_end(const char* status);
150 
151 /**
152  * Cleanup and free resources
153  */
155 
156 // ═══════════════════════════════════════════════════════════════════════════════
157 // Context-based API (for multiple concurrent runs)
158 // ═══════════════════════════════════════════════════════════════════════════════
159 
162 
163 bool ck_metrics_ctx_init(CKMetricsContext* ctx, const char* run_id,
164  const char* endpoint, CKMetricsMode mode);
165 void ck_metrics_ctx_log_f(CKMetricsContext* ctx, const char* name, double value);
166 void ck_metrics_ctx_log_i(CKMetricsContext* ctx, const char* name, int64_t value);
167 void ck_metrics_ctx_step(CKMetricsContext* ctx, int64_t step);
168 void ck_metrics_ctx_end(CKMetricsContext* ctx, const char* status);
169 
170 // ═══════════════════════════════════════════════════════════════════════════════
171 // Utility Functions
172 // ═══════════════════════════════════════════════════════════════════════════════
173 
174 /**
175  * Generate a unique run ID based on current timestamp
176  */
177 void ck_metrics_generate_run_id(char* buffer, size_t size);
178 
179 /**
180  * Get current memory usage in MB (platform-specific)
181  */
183 
184 /**
185  * Get current timestamp in seconds with microsecond precision
186  */
187 double ck_metrics_timestamp(void);
188 
189 #ifdef __cplusplus
190 }
191 #endif
192 
193 #endif // CK_METRICS_H
194 
195 // ═══════════════════════════════════════════════════════════════════════════════
196 // IMPLEMENTATION (define CK_METRICS_IMPLEMENTATION in ONE .c file)
197 // ═══════════════════════════════════════════════════════════════════════════════
198 
199 #ifdef CK_METRICS_IMPLEMENTATION
200 
201 #include <stdio.h>
202 #include <stdlib.h>
203 #include <string.h>
204 #include <time.h>
205 #include <sys/time.h>
206 
207 #ifdef __linux__
208 #include <sys/sysinfo.h>
209 #include <unistd.h>
210 #endif
211 
212 // Optional: libcurl for HTTP mode
213 #ifdef CK_METRICS_USE_CURL
214 #include <curl/curl.h>
215 #endif
216 
217 // Global context
219 
220 // ─────────────────────────────────────────────────────────────────────────────
221 // Internal helpers
222 // ─────────────────────────────────────────────────────────────────────────────
223 
224 static void metrics_build_json(CKMetricsContext* ctx, char* buffer, size_t size) {
225  int offset = 0;
226  offset += snprintf(buffer + offset, size - offset,
227  "{\"run_id\":\"%s\",\"step\":%lld,\"timestamp\":%.6f,\"metrics\":{",
228  ctx->run_id, (long long)ctx->current_step, ck_metrics_timestamp());
229 
230  for (int i = 0; i < ctx->metric_count; i++) {
231  CKMetric* m = &ctx->metrics[i];
232  if (i > 0) offset += snprintf(buffer + offset, size - offset, ",");
233 
234  switch (m->type) {
235  case CK_METRIC_FLOAT:
236  offset += snprintf(buffer + offset, size - offset,
237  "\"%s\":%.6g", m->name, m->value.f);
238  break;
239  case CK_METRIC_INT:
240  offset += snprintf(buffer + offset, size - offset,
241  "\"%s\":%lld", m->name, (long long)m->value.i);
242  break;
243  case CK_METRIC_STRING:
244  offset += snprintf(buffer + offset, size - offset,
245  "\"%s\":\"%s\"", m->name, m->value.s);
246  break;
247  }
248  }
249 
250  snprintf(buffer + offset, size - offset, "}}");
251 }
252 
253 static void metrics_send_http(CKMetricsContext* ctx, const char* json) {
254 #ifdef CK_METRICS_USE_CURL
255  if (!ctx->curl_handle) return;
256 
257  CURL* curl = (CURL*)ctx->curl_handle;
258  struct curl_slist* headers = NULL;
259  headers = curl_slist_append(headers, "Content-Type: application/json");
260 
261  curl_easy_setopt(curl, CURLOPT_URL, ctx->endpoint);
262  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);
263  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
264  curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); // 1 second timeout
265 
266  curl_easy_perform(curl);
267  curl_slist_free_all(headers);
268 #else
269  (void)ctx; (void)json;
270  // HTTP mode requires libcurl
271 #endif
272 }
273 
274 static void metrics_write_file(CKMetricsContext* ctx, const char* json) {
275  if (!ctx->file_handle) return;
276  fprintf(ctx->file_handle, "%s\n", json);
277  fflush(ctx->file_handle);
278 }
279 
280 static void metrics_flush(CKMetricsContext* ctx) {
281  if (ctx->metric_count == 0) return;
282 
283  char buffer[CK_METRICS_BUFFER_SIZE];
284  metrics_build_json(ctx, buffer, sizeof(buffer));
285 
286  switch (ctx->mode) {
288  metrics_send_http(ctx, buffer);
289  break;
291  metrics_write_file(ctx, buffer);
292  break;
294  printf("%s\n", buffer);
295  break;
297  break;
298  }
299 
300  ctx->metric_count = 0;
301 }
302 
303 // ─────────────────────────────────────────────────────────────────────────────
304 // Public API
305 // ─────────────────────────────────────────────────────────────────────────────
306 
307 bool ck_metrics_init(const char* run_id, const char* endpoint, CKMetricsMode mode) {
308  return ck_metrics_init_full(run_id, endpoint, mode, "unknown", "unknown", 0, 0, 0);
309 }
310 
311 bool ck_metrics_init_full(const char* run_id, const char* endpoint, CKMetricsMode mode,
312  const char* model, const char* dataset,
313  int batch_size, double lr, int max_steps) {
314  if (!ck_metrics_ctx) {
316  }
317 
319 
320  strncpy(ctx->run_id, run_id, CK_METRICS_MAX_NAME_LEN - 1);
321  strncpy(ctx->endpoint, endpoint, CK_METRICS_MAX_URL_LEN - 1);
322  strncpy(ctx->model_name, model, CK_METRICS_MAX_NAME_LEN - 1);
323  strncpy(ctx->dataset_name, dataset, CK_METRICS_MAX_NAME_LEN - 1);
324  ctx->mode = mode;
325  ctx->batch_size = batch_size;
326  ctx->learning_rate = lr;
327  ctx->max_steps = max_steps;
328  ctx->metric_count = 0;
329  ctx->current_step = 0;
330 
331  switch (mode) {
333 #ifdef CK_METRICS_USE_CURL
334  curl_global_init(CURL_GLOBAL_DEFAULT);
335  ctx->curl_handle = curl_easy_init();
336 #endif
337  break;
339  ctx->file_handle = fopen(endpoint, "a");
340  if (!ctx->file_handle) return false;
341  break;
342  default:
343  break;
344  }
345 
346  ctx->initialized = true;
347  return true;
348 }
349 
350 void ck_metrics_log_f(const char* name, double value) {
351  if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
352  ck_metrics_ctx_log_f(ck_metrics_ctx, name, value);
353 }
354 
355 void ck_metrics_log_i(const char* name, int64_t value) {
356  if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
357  ck_metrics_ctx_log_i(ck_metrics_ctx, name, value);
358 }
359 
360 void ck_metrics_log_s(const char* name, const char* value) {
361  if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
363  if (ctx->metric_count >= CK_METRICS_MAX_METRICS) return;
364 
365  CKMetric* m = &ctx->metrics[ctx->metric_count++];
366  strncpy(m->name, name, CK_METRICS_MAX_NAME_LEN - 1);
367  m->type = CK_METRIC_STRING;
368  strncpy(m->value.s, value, CK_METRICS_MAX_NAME_LEN - 1);
369 }
370 
371 void ck_metrics_step(int64_t step) {
372  if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
374  metrics_flush(ck_metrics_ctx);
375 }
376 
377 void ck_metrics_end(const char* status) {
378  if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
379 
380  // Log final status
381  ck_metrics_log_s("status", status);
382  metrics_flush(ck_metrics_ctx);
383 
385 }
386 
387 void ck_metrics_cleanup(void) {
388  if (!ck_metrics_ctx) return;
389 
390 #ifdef CK_METRICS_USE_CURL
392  curl_easy_cleanup((CURL*)ck_metrics_ctx->curl_handle);
393  curl_global_cleanup();
394  }
395 #endif
396 
398  fclose(ck_metrics_ctx->file_handle);
399  }
400 
402  ck_metrics_ctx = NULL;
403 }
404 
405 // ─────────────────────────────────────────────────────────────────────────────
406 // Context-based API
407 // ─────────────────────────────────────────────────────────────────────────────
408 
410  CKMetricsContext* ctx = (CKMetricsContext*)calloc(1, sizeof(CKMetricsContext));
411  return ctx;
412 }
413 
415  if (ctx) free(ctx);
416 }
417 
418 bool ck_metrics_ctx_init(CKMetricsContext* ctx, const char* run_id,
419  const char* endpoint, CKMetricsMode mode) {
420  if (!ctx) return false;
421  strncpy(ctx->run_id, run_id, CK_METRICS_MAX_NAME_LEN - 1);
422  strncpy(ctx->endpoint, endpoint, CK_METRICS_MAX_URL_LEN - 1);
423  ctx->mode = mode;
424  ctx->initialized = true;
425  return true;
426 }
427 
428 void ck_metrics_ctx_log_f(CKMetricsContext* ctx, const char* name, double value) {
429  if (!ctx || ctx->metric_count >= CK_METRICS_MAX_METRICS) return;
430  CKMetric* m = &ctx->metrics[ctx->metric_count++];
431  strncpy(m->name, name, CK_METRICS_MAX_NAME_LEN - 1);
432  m->type = CK_METRIC_FLOAT;
433  m->value.f = value;
434 }
435 
436 void ck_metrics_ctx_log_i(CKMetricsContext* ctx, const char* name, int64_t value) {
437  if (!ctx || ctx->metric_count >= CK_METRICS_MAX_METRICS) return;
438  CKMetric* m = &ctx->metrics[ctx->metric_count++];
439  strncpy(m->name, name, CK_METRICS_MAX_NAME_LEN - 1);
440  m->type = CK_METRIC_INT;
441  m->value.i = value;
442 }
443 
444 void ck_metrics_ctx_step(CKMetricsContext* ctx, int64_t step) {
445  if (!ctx) return;
446  ctx->current_step = step;
447  metrics_flush(ctx);
448 }
449 
450 void ck_metrics_ctx_end(CKMetricsContext* ctx, const char* status) {
451  if (!ctx) return;
452  ck_metrics_ctx_log_f(ctx, "status", 0); // Simplified
453  metrics_flush(ctx);
454 }
455 
456 // ─────────────────────────────────────────────────────────────────────────────
457 // Utility Functions
458 // ─────────────────────────────────────────────────────────────────────────────
459 
460 void ck_metrics_generate_run_id(char* buffer, size_t size) {
461  time_t t = time(NULL);
462  struct tm* tm = localtime(&t);
463  snprintf(buffer, size, "run_%04d%02d%02d_%02d%02d%02d",
464  tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
465  tm->tm_hour, tm->tm_min, tm->tm_sec);
466 }
467 
468 int64_t ck_metrics_get_memory_mb(void) {
469 #ifdef __linux__
470  FILE* f = fopen("/proc/self/statm", "r");
471  if (f) {
472  long pages = 0;
473  fscanf(f, "%ld", &pages);
474  fclose(f);
475  return (pages * sysconf(_SC_PAGESIZE)) / (1024 * 1024);
476  }
477 #endif
478  return 0;
479 }
480 
481 double ck_metrics_timestamp(void) {
482  struct timeval tv;
483  gettimeofday(&tv, NULL);
484  return tv.tv_sec + tv.tv_usec / 1000000.0;
485 }
486 
487 #endif // CK_METRICS_IMPLEMENTATION
void ck_metrics_log_i(const char *name, int64_t value)
void ck_metrics_ctx_step(CKMetricsContext *ctx, int64_t step)
#define CK_METRICS_BUFFER_SIZE
Definition: ck_metrics.h:44
void ck_metrics_end(const char *status)
void ck_metrics_generate_run_id(char *buffer, size_t size)
void ck_metrics_ctx_log_f(CKMetricsContext *ctx, const char *name, double value)
void ck_metrics_cleanup(void)
#define CK_METRICS_MAX_METRICS
Definition: ck_metrics.h:42
bool ck_metrics_ctx_init(CKMetricsContext *ctx, const char *run_id, const char *endpoint, CKMetricsMode mode)
#define CK_METRICS_MAX_URL_LEN
Definition: ck_metrics.h:43
CKMetricType
Definition: ck_metrics.h:55
@ CK_METRIC_STRING
Definition: ck_metrics.h:58
@ CK_METRIC_FLOAT
Definition: ck_metrics.h:56
@ CK_METRIC_INT
Definition: ck_metrics.h:57
bool ck_metrics_init_full(const char *run_id, const char *endpoint, CKMetricsMode mode, const char *model, const char *dataset, int batch_size, double lr, int max_steps)
void ck_metrics_log_s(const char *name, const char *value)
bool ck_metrics_init(const char *run_id, const char *endpoint, CKMetricsMode mode)
void ck_metrics_ctx_log_i(CKMetricsContext *ctx, const char *name, int64_t value)
void ck_metrics_step(int64_t step)
int64_t ck_metrics_get_memory_mb(void)
void ck_metrics_log_f(const char *name, double value)
CKMetricsMode
Definition: ck_metrics.h:47
@ CK_METRICS_MODE_STDOUT
Definition: ck_metrics.h:50
@ CK_METRICS_MODE_FILE
Definition: ck_metrics.h:49
@ CK_METRICS_MODE_HTTP
Definition: ck_metrics.h:48
@ CK_METRICS_MODE_DISABLED
Definition: ck_metrics.h:51
void ck_metrics_ctx_end(CKMetricsContext *ctx, const char *status)
void ck_metrics_destroy_context(CKMetricsContext *ctx)
CKMetricsContext * ck_metrics_create_context(void)
double ck_metrics_timestamp(void)
#define CK_METRICS_MAX_NAME_LEN
Definition: ck_metrics.h:41
CKMetricsContext * ck_metrics_ctx
char s[64]
Definition: ck_metrics.h:68
char name[64]
Definition: ck_metrics.h:63
double f
Definition: ck_metrics.h:66
int64_t i
Definition: ck_metrics.h:67
CKMetricType type
Definition: ck_metrics.h:64
union CKMetric::@0 value
char model_name[64]
Definition: ck_metrics.h:85
CKMetric metrics[32]
Definition: ck_metrics.h:80
char endpoint[256]
Definition: ck_metrics.h:75
void * curl_handle
Definition: ck_metrics.h:93
double learning_rate
Definition: ck_metrics.h:88
char dataset_name[64]
Definition: ck_metrics.h:86
char run_id[64]
Definition: ck_metrics.h:74
FILE * file_handle
Definition: ck_metrics.h:94
CKMetricsMode mode
Definition: ck_metrics.h:77
int64_t current_step
Definition: ck_metrics.h:82