← Back to C-Kernel-Engine Docs Doxygen Source Documentation
ckernel_strict.c File Reference
#include "ckernel_engine.h"
#include "ck_threadpool.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

Go to the source code of this file.

Macros

#define CK_ADD_PAIR(pid, cid)
 

Functions

int ck_get_num_threads (void)
 
int ck_get_physical_cores (void)
 
ck_threadpool_t * ck_get_threadpool (void)
 
static int ck_parse_env_int (const char *name)
 
void ck_set_num_threads (int num_threads)
 
void ck_set_strict_parity (int enabled)
 
int ck_strict_parity_enabled (void)
 
void ck_threadpool_init (void)
 
void ck_threadpool_shutdown (void)
 

Variables

static int ck_strict_parity = 0
 
static int g_num_threads = 0
 
static int g_threads_initialized = 0
 

Macro Definition Documentation

◆ CK_ADD_PAIR

#define CK_ADD_PAIR (   pid,
  cid 
)
Value:
do { \
if ((pid) >= 0 && (cid) >= 0) { \
int exists = 0; \
for (int ii = 0; ii < seen_count; ++ii) { \
if (seen[ii].physical_id == (pid) && \
seen[ii].core_id == (cid)) { \
exists = 1; \
break; \
} \
} \
if (!exists && seen_count < seen_cap) { \
seen[seen_count].physical_id = (pid); \
seen[seen_count].core_id = (cid); \
++seen_count; \
} \
} \
} while (0)

Function Documentation

◆ ck_get_num_threads()

int ck_get_num_threads ( void  )

Definition at line 178 of file ckernel_strict.c.

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 }
void ck_set_num_threads(int num_threads)
static int g_num_threads
static int g_threads_initialized

References ck_set_num_threads(), g_num_threads, and g_threads_initialized.

Referenced by gemm_blocked_serial(), and global_pool_init().

◆ ck_get_physical_cores()

int ck_get_physical_cores ( void  )

Definition at line 62 of file ckernel_strict.c.

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 }
#define CK_ADD_PAIR(pid, cid)

References CK_ADD_PAIR.

Referenced by ck_set_num_threads(), and ck_threadpool_create().

◆ ck_get_threadpool()

ck_threadpool_t* ck_get_threadpool ( void  )

Get the global thread pool handle for dispatch. Convenience wrapper — initializes on first call.

Definition at line 218 of file ckernel_strict.c.

219 {
220  return ck_threadpool_global();
221 }
ck_threadpool_t * ck_threadpool_global(void)

References ck_threadpool_global().

◆ ck_parse_env_int()

static int ck_parse_env_int ( const char *  name)
static

Definition at line 45 of file ckernel_strict.c.

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 }
uint32_t end
Definition: utf8.c:215

References end.

Referenced by ck_set_num_threads().

◆ ck_set_num_threads()

void ck_set_num_threads ( int  num_threads)

Definition at line 148 of file ckernel_strict.c.

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 }
static int ck_parse_env_int(const char *name)
int ck_get_physical_cores(void)

References ck_get_physical_cores(), ck_parse_env_int(), g_num_threads, and g_threads_initialized.

Referenced by ck_get_num_threads().

◆ ck_set_strict_parity()

void ck_set_strict_parity ( int  enabled)

Definition at line 22 of file ckernel_strict.c.

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 }
static int ck_strict_parity

References ck_strict_parity.

◆ ck_strict_parity_enabled()

◆ ck_threadpool_init()

void ck_threadpool_init ( void  )

Initialize the global thread pool. Called once during engine startup (e.g., from ck_model_init). Uses ck_get_num_threads() for thread count (respects CK_NUM_THREADS env).

Safe to call multiple times — subsequent calls are no-ops.

Definition at line 198 of file ckernel_strict.c.

199 {
200  /* ck_threadpool_global() uses pthread_once internally */
201  ck_threadpool_t *pool = ck_threadpool_global();
202  (void)pool;
203 }

References ck_threadpool_global().

◆ ck_threadpool_shutdown()

void ck_threadpool_shutdown ( void  )

Shut down the global thread pool. Called during engine teardown. Workers are joined and freed.

Definition at line 209 of file ckernel_strict.c.

210 {
212 }
void ck_threadpool_global_destroy(void)

References ck_threadpool_global_destroy().

Variable Documentation

◆ ck_strict_parity

int ck_strict_parity = 0
static

Definition at line 20 of file ckernel_strict.c.

Referenced by ck_set_strict_parity(), and ck_strict_parity_enabled().

◆ g_num_threads

int g_num_threads = 0
static

Definition at line 42 of file ckernel_strict.c.

Referenced by ck_get_num_threads(), and ck_set_num_threads().

◆ g_threads_initialized

int g_threads_initialized = 0
static

Definition at line 43 of file ckernel_strict.c.

Referenced by ck_get_num_threads(), and ck_set_num_threads().