← Back to C-Kernel-Engine Docs Doxygen Source Documentation
 
Loading...
Searching...
No Matches
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
34extern "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
47typedef 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
60
61// Single metric entry
62typedef struct {
65 union {
66 double f;
67 int64_t i;
69 } value;
70} CKMetric;
71
72// Metrics context
73typedef 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];
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 */
112bool ck_metrics_init(const char* run_id, const char* endpoint, CKMetricsMode mode);
113
114/**
115 * Initialize with full configuration
116 */
117bool 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 */
124void ck_metrics_log_f(const char* name, double value);
125
126/**
127 * Log an integer metric (e.g., step, tokens_per_sec)
128 */
129void ck_metrics_log_i(const char* name, int64_t value);
130
131/**
132 * Log a string metric (e.g., phase, status)
133 */
134void 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 */
142void ck_metrics_step(int64_t step);
143
144/**
145 * End the training run
146 *
147 * @param status Final status ("completed", "failed", "interrupted")
148 */
149void 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
163bool ck_metrics_ctx_init(CKMetricsContext* ctx, const char* run_id,
164 const char* endpoint, CKMetricsMode mode);
165void ck_metrics_ctx_log_f(CKMetricsContext* ctx, const char* name, double value);
166void ck_metrics_ctx_log_i(CKMetricsContext* ctx, const char* name, int64_t value);
167void ck_metrics_ctx_step(CKMetricsContext* ctx, int64_t step);
168void 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 */
177void 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 */
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
224static 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
253static 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
274static 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
280static 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
307bool 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
311bool 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
350void ck_metrics_log_f(const char* name, double value) {
351 if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
353}
354
355void ck_metrics_log_i(const char* name, int64_t value) {
356 if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
358}
359
360void 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);
368 strncpy(m->value.s, value, CK_METRICS_MAX_NAME_LEN - 1);
369}
370
371void ck_metrics_step(int64_t step) {
372 if (!ck_metrics_ctx || !ck_metrics_ctx->initialized) return;
374 metrics_flush(ck_metrics_ctx);
375}
376
377void 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
387void 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
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
418bool 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
428void 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);
433 m->value.f = value;
434}
435
436void 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
444void ck_metrics_ctx_step(CKMetricsContext* ctx, int64_t step) {
445 if (!ctx) return;
446 ctx->current_step = step;
447 metrics_flush(ctx);
448}
449
450void 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
460void 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
468int64_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
481double 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
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
CKMetricsMode mode
Definition ck_metrics.h:77
int64_t current_step
Definition ck_metrics.h:82