Open and map the GGUF once. Metal needs a shared mapping for no-copy * MTLBuffers; CPU uses a private read-only mapping to avoid Darwin VM stress. * Tokenizer-only callers pass prefetch_cpu=false so inspecting tokens never * walks the huge tensor payload. */
| 1943 | |
| 1944 | for (uint32_t i = 1; i < n_threads; i++) { |
| 1945 | if (pthread_create(&g_pool.threads[i], NULL, ds4_worker_main, (void *)(uintptr_t)i) != 0) { |
| 1946 | ds4_die("failed to create worker thread"); |
| 1947 | } |
| 1948 | } |
| 1949 | } |
| 1950 | |
| 1951 | static void ds4_threads_shutdown(void) { |
| 1952 | if (!g_pool.initialized) return; |
| 1953 | |
| 1954 | pthread_mutex_lock(&g_pool.mutex); |
| 1955 | g_pool.shutdown = true; |
| 1956 | g_pool.generation++; |
| 1957 | pthread_cond_broadcast(&g_pool.work_cond); |
| 1958 | pthread_mutex_unlock(&g_pool.mutex); |
| 1959 | |
| 1960 | for (uint32_t i = 1; i < g_pool.n_threads; i++) { |
| 1961 | pthread_join(g_pool.threads[i], NULL); |
| 1962 | } |
| 1963 | |
| 1964 | pthread_cond_destroy(&g_pool.done_cond); |
| 1965 | pthread_cond_destroy(&g_pool.work_cond); |
| 1966 | pthread_mutex_destroy(&g_pool.mutex); |
| 1967 | memset(&g_pool, 0, sizeof(g_pool)); |
| 1968 | } |
| 1969 | |
| 1970 | /* Run a row-parallel CPU kernel, falling back to serial execution for small |
| 1971 | * jobs or nested calls where spawning more work would only add latency. */ |
| 1972 | static void ds4_parallel_for_min_rows(uint64_t n_rows, ds4_parallel_fn fn, void *ctx, uint64_t min_parallel_rows) { |
| 1973 | ds4_threads_init(); |
| 1974 | |
| 1975 | if (g_parallel_depth > 0 || g_pool.n_threads <= 1 || n_rows < min_parallel_rows) { |
| 1976 | fn(ctx, 0, n_rows); |
| 1977 | return; |
| 1978 | } |
| 1979 | |
| 1980 | pthread_mutex_lock(&g_pool.mutex); |
| 1981 | g_pool.fn = fn; |
| 1982 | g_pool.ctx = ctx; |
| 1983 | g_pool.n_rows = n_rows; |
| 1984 | g_pool.done = 0; |
| 1985 | g_pool.generation++; |
| 1986 | pthread_cond_broadcast(&g_pool.work_cond); |
| 1987 | |
| 1988 | const uint64_t rows_per_thread = (n_rows + g_pool.n_threads - 1) / g_pool.n_threads; |
| 1989 | uint64_t main_row1 = rows_per_thread; |
| 1990 | if (main_row1 > n_rows) main_row1 = n_rows; |
| 1991 | pthread_mutex_unlock(&g_pool.mutex); |
| 1992 | |
| 1993 | if (main_row1 > 0) { |
| 1994 | g_parallel_depth++; |
no test coverage detected