llama.cpp — Startup Flow
2.1 Entry Points
llama.cpp has two main entry points:
Server Entry Point
File: tools/server/server.cpp:74 — int main(int argc, char ** argv)
CLI Entry Point
File: tools/cli/cli.cpp — int main(int argc, char ** argv)
Both entry points follow a similar initialization pattern using shared common_params for argument parsing.
2.2 Server Initialization Sequence
The server startup flow in tools/server/server.cpp:
- Parse CLI flags (server.cpp:82) —
common_params_parse(argc, argv, params, LLAMA_EXAMPLE_SERVER)parses all command-line arguments intocommon_params - Validate batch parameters (server.cpp:89) — Ensures
n_batch <= n_ubatchfor embeddings mode - Auto-configure parallelism (server.cpp:95-100) — If
n_parallel < 0, setsn_parallel = 4andkv_unified = true - Initialize backend (server.cpp:110) —
llama_backend_init()initializes GGML backend registry and discovers available hardware backends - Initialize NUMA (server.cpp:111) —
llama_numa_init(params.numa)configures NUMA memory policy - Create server context (server.cpp:108) —
server_context ctx_server— the primary inference orchestrator - Initialize HTTP context (server.cpp:116-120) —
ctx_http.init(params)sets up the HTTP server (httplib-based), loads API keys, registers middleware - Register API routes (server.cpp:127-225) — All REST endpoints are registered via
ctx_http.get()/ctx_http.post() - Start HTTP server (server.cpp:265) —
ctx_http.start()begins listening on configured port (before model load, so/healthis available) - Load model (server.cpp:280) —
ctx_server.load_model(params)loads GGUF weights, createsllama_modelandllama_context - Register signal handlers (server.cpp:302-313) —
sigaction(SIGINT/SIGTERM)registerssignal_handlerfor graceful shutdown - Enter main loop (server.cpp:336) —
ctx_server.start_loop()blocks the main thread, processing inference tasks from the queue
Router Mode
If params.model.path is empty, the server starts in router mode (server.cpp:130-170). In router mode:
- No model is loaded in the main process
- A
server_models_routesobject manages child server processes - All inference endpoints are proxied to child servers
- Additional routes
/models/loadand/models/unloadare registered for dynamic model management
2.3 CLI Initialization Sequence
- Parse CLI flags —
common_params_parse()intocommon_params - Initialize backend —
llama_backend_init() - Load model — via
server_context::load_model() - Register signal handler — SIGINT sets
g_is_interruptedflag for mid-generation cancellation - Enter interactive loop — reads user input, formats chat messages, calls
generate_completion()
2.4 Thread Model (Server)
| Thread | Created At | Role |
|---|---|---|
| main | OS | CLI parsing, init, then blocks on start_loop() |
| http-thread | ctx_http.start() | HTTP request listener (httplib server) |
| io-worker-N | httplib internal | Process HTTP requests, dispatch to route handlers |
| compute | ggml threadpool | CPU inference workers (configurable via n_threads) |
| monitor-thread | server_models::setup_child_server() (conditional) | Heartbeat to router server when running as child |
GPU Thread Usage
When a GPU backend is active (CUDA, Metal, Vulkan), compute graph execution is dispatched to the GPU via the backend's graph_compute function pointer. The CPU thread that submits the graph may block on synchronize() until GPU work completes. Multiple slots can be batched together for efficient GPU utilization.
2.5 Process Model (Router Mode)
In router mode, the server spawns child server processes via server_models:
- Spawn: Child processes are started with
fork/execor equivalent, each loading a specific model - IPC: Child servers communicate with the router via HTTP (same machine, different ports)
- Lifecycle: The router tracks child server health via a monitor thread heartbeat mechanism
- Scaling: Multiple child servers can run concurrently, each on a different port
2.6 Memory Layout at Startup
Model Weights (largest allocation)
- Method: Memory-mapped file (
mmap) viallama_mmap(src/llama-mmap.cpp) - The GGUF file is mapped into virtual address space; tensors are accessed directly from the mapping
- On GPU backends, tensors are copied to VRAM via
ggml_backend_bufferallocation
KV Cache
- Allocation:
ggml_backend_alloc_ctx_tensors()reserves GPU or CPU memory for KV cache tensors - Size depends on
n_ctx(context window),n_layer,n_embd_head_k,n_embd_head_v, andn_seq_max - Typically the second-largest memory consumer after model weights
Compute Buffers
- Purpose: Intermediate tensors (activations) during graph execution
- Allocation:
ggml_backend_alloc_ctx_tensors()duringsched_reserve() - Size depends on batch size and model architecture
CPU Arena
- GGML uses a custom allocator (
ggml_alloc) for tensor metadata (not data) ggml_contextobjects allocate tensor structs from pools, avoiding per-tensormalloc
GPU VRAM Layout
On CUDA/Metal backends:
- Model weights → VRAM (via
ggml_backend_buffer) - KV cache → VRAM (via
ggml_backend_buffer) - Compute scratch → VRAM (temporary, reused per graph execution)