← Back to C-Kernel-Engine Docs Doxygen Source Documentation
ckernel_strict.c
Go to the documentation of this file.
1 #include "ckernel_engine.h"
2 #include "ck_threadpool.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <errno.h>
7 
8 #ifdef _OPENMP
9 #include <omp.h>
10 #endif
11 
12 #if defined(USE_MKL)
13 #include <mkl.h>
14 #endif
15 
16 // =============================================================================
17 // Strict parity mode (for numerical reproducibility)
18 // =============================================================================
19 
20 static int ck_strict_parity = 0;
21 
22 void ck_set_strict_parity(int enabled)
23 {
24  ck_strict_parity = enabled ? 1 : 0;
25 #ifdef _OPENMP
26  if (ck_strict_parity) {
27  omp_set_dynamic(0);
28  omp_set_num_threads(1);
29  }
30 #endif
31 }
32 
34 {
35  return ck_strict_parity;
36 }
37 
38 // =============================================================================
39 // Thread configuration
40 // =============================================================================
41 
42 static int g_num_threads = 0;
43 static int g_threads_initialized = 0;
44 
45 static int ck_parse_env_int(const char *name)
46 {
47  const char *val = getenv(name);
48  if (!val || !val[0]) {
49  return 0;
50  }
51 
52  errno = 0;
53  char *end = NULL;
54  long n = strtol(val, &end, 10);
55  if (errno != 0 || end == val || n <= 0 || n > (1L << 20)) {
56  return 0;
57  }
58  return (int)n;
59 }
60 
61 // Detect physical CPU cores (not hyperthreads) when possible.
63 {
64  int physical_cores = 0;
65  int logical_cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
66  if (logical_cores <= 0) {
67  logical_cores = 1;
68  }
69 
70  // Read from /proc/cpuinfo (Linux) and count unique (physical id, core id) pairs.
71  FILE *f = fopen("/proc/cpuinfo", "r");
72  if (f) {
73  char line[256];
74  int physical_id = -1;
75  int core_id = -1;
76 
77  struct {
78  int physical_id;
79  int core_id;
80  } seen[8192];
81  int seen_count = 0;
82 
83  const int seen_cap = (int)(sizeof(seen) / sizeof(seen[0]));
84 
85  // Helper: add (pid,cid) to set if not present.
86  #define CK_ADD_PAIR(pid, cid) \
87  do { \
88  if ((pid) >= 0 && (cid) >= 0) { \
89  int exists = 0; \
90  for (int ii = 0; ii < seen_count; ++ii) { \
91  if (seen[ii].physical_id == (pid) && \
92  seen[ii].core_id == (cid)) { \
93  exists = 1; \
94  break; \
95  } \
96  } \
97  if (!exists && seen_count < seen_cap) { \
98  seen[seen_count].physical_id = (pid); \
99  seen[seen_count].core_id = (cid); \
100  ++seen_count; \
101  } \
102  } \
103  } while (0)
104 
105  while (fgets(line, sizeof(line), f)) {
106  int val;
107 
108  // Blank line separates processor blocks.
109  if (line[0] == '\n' || line[0] == '\0') {
110  CK_ADD_PAIR(physical_id, core_id);
111  physical_id = -1;
112  core_id = -1;
113  continue;
114  }
115 
116  if (sscanf(line, "physical id : %d", &val) == 1) {
117  physical_id = val;
118  continue;
119  }
120  if (sscanf(line, "core id : %d", &val) == 1) {
121  core_id = val;
122  continue;
123  }
124  }
125  fclose(f);
126 
127  // Handle file without trailing blank line.
128  CK_ADD_PAIR(physical_id, core_id);
129 
130  #undef CK_ADD_PAIR
131 
132  physical_cores = seen_count;
133  }
134 
135  // If we couldn't reliably detect physical cores (common in containers),
136  // fall back to logical CPUs instead of incorrectly forcing single-thread execution.
137  if (physical_cores <= 1 && logical_cores > 1) {
138  return logical_cores;
139  }
140 
141  if (physical_cores > 1) {
142  return physical_cores;
143  }
144 
145  return logical_cores;
146 }
147 
148 void ck_set_num_threads(int num_threads)
149 {
150  // 0 = auto-detect
151  if (num_threads <= 0) {
152  // Prefer explicit env controls when present:
153  // - CK_NUM_THREADS: engine-level override
154  // - OMP_NUM_THREADS: standard OpenMP control (set by `ck run --threads`)
155  int env_threads = ck_parse_env_int("CK_NUM_THREADS");
156  if (env_threads <= 0) {
157  env_threads = ck_parse_env_int("OMP_NUM_THREADS");
158  }
159  num_threads = env_threads > 0 ? env_threads : ck_get_physical_cores();
160  }
161 
162  g_num_threads = num_threads;
164 
165 #ifdef _OPENMP
166  omp_set_dynamic(0); // Disable dynamic adjustment
167  omp_set_num_threads(num_threads);
168 #endif
169 
170 #if defined(USE_MKL)
171  mkl_set_num_threads(num_threads);
172 #endif
173 
174  fprintf(stderr, "[CK] Set %d threads (auto=%d)\n",
175  num_threads, ck_get_physical_cores());
176 }
177 
179 {
180  // Auto-initialize if not set
181  if (!g_threads_initialized) {
182  ck_set_num_threads(0); // Auto-detect
183  }
184  return g_num_threads;
185 }
186 
187 // =============================================================================
188 // Thread pool lifecycle
189 // =============================================================================
190 
191 /**
192  * Initialize the global thread pool.
193  * Called once during engine startup (e.g., from ck_model_init).
194  * Uses ck_get_num_threads() for thread count (respects CK_NUM_THREADS env).
195  *
196  * Safe to call multiple times — subsequent calls are no-ops.
197  */
199 {
200  /* ck_threadpool_global() uses pthread_once internally */
201  ck_threadpool_t *pool = ck_threadpool_global();
202  (void)pool;
203 }
204 
205 /**
206  * Shut down the global thread pool.
207  * Called during engine teardown. Workers are joined and freed.
208  */
210 {
212 }
213 
214 /**
215  * Get the global thread pool handle for dispatch.
216  * Convenience wrapper — initializes on first call.
217  */
218 ck_threadpool_t *ck_get_threadpool(void)
219 {
220  return ck_threadpool_global();
221 }
Persistent pthread thread pool for CK-Engine inference.
void ck_threadpool_global_destroy(void)
ck_threadpool_t * ck_threadpool_global(void)
static int ck_parse_env_int(const char *name)
void ck_threadpool_init(void)
void ck_threadpool_shutdown(void)
void ck_set_num_threads(int num_threads)
static int g_num_threads
static int ck_strict_parity
int ck_get_physical_cores(void)
void ck_set_strict_parity(int enabled)
ck_threadpool_t * ck_get_threadpool(void)
#define CK_ADD_PAIR(pid, cid)
static int g_threads_initialized
int ck_get_num_threads(void)
int ck_strict_parity_enabled(void)
uint32_t end
Definition: utf8.c:215