This guide is designed to transform your home-lab from a "black box" of inconsistent performance into a transparent, measurable research environment. When you are dealing with `llama.cpp`, OpenWebUI, and MTP (Multi-Token Prediction), the "feel" of the model is often a byproduct of three competing variables: **Memory Bandwidth**, **KV Cache Management**, and **Compute Utilization**.

To solve your inconsistency, we must move away from "vibe-based" testing and toward "deterministic benchmarking."

---

# Quick Diagnosis

Before you run a single benchmark, we need to identify the "flavor" of your inconsistency. Most `llama.cpp` issues fall into three categories:

### 1. The "Slow First Token" (TTFT - Time To First Token)
If the model takes 5–10 seconds to start typing but then moves at a steady speed, your bottleneck is **Prefill**.
*   **Cause A:** Your prompt is too large for the GPU's active memory, forcing a "split" where the prompt is processed on the CPU.
*   **Cause B:** You are using a high `n_batch` size that exceeds your GPU's compute capability, causing memory swapping.
*   **Cause C:** The KV Cache is being re-allocated or "shuffled" at the start of the request.

### 2. The "GPU Memory Jump"
If you see VRAM usage spike and then settle, or fluctuate wildly during generation:
*   **Cause A:** **Dynamic KV Cache.** If you aren't using a fixed cache size, `llama.cpp` may be allocating memory on the fly.
*   **Cause B:** **MTP Buffer.** Multi-Token Prediction requires extra buffers to hold the "lookahead" tokens. If these aren't pre-allocated, the first few tokens will trigger a memory allocation spike.
*   **Cause C:** **Context Overflow.** If your prompt + generation exceeds the `ctx_size`, the system may be frantically trying to "evict" old tokens.

### 3. The "MTP Uncertainty"
MTP is designed to speed up **Decoding** (the speed of the words appearing) by predicting multiple tokens at once.
*   **The Trap:** MTP can sometimes *slow down* the first token because the model has to do more work per "step" to predict the sequence.
*   **The Check:** If your TPS (Tokens Per Second) is high but the logic feels "mushy" or repetitive, MTP might be over-predicting common patterns at the expense of nuance.

---

# Data Collection Plan

To fix the inconsistency, you need a "Clean Room" environment. You cannot benchmark while browsing the web or running other apps.

### 1. The Environment Setup
*   **Isolate the GPU:** Close all browsers (Chrome/Edge are VRAM hogs) and other AI tools.
*   **Fixed Parameters:** For every test, you must use the exact same:
    *   `temp`: 0.7 (or your preferred)
    *   `top_p`: 0.9
    *   `repeat_penalty`: 1.1
    *   `ctx_size`: (e.g., 8192)
    *   `n_gpu_layers`: (Maxed out)
    *   `n_batch`: (Start with 512, then test 2048)

### 2. The Toolchain
*   **Flight Recorder Proxy:** Use this to capture the raw JSON responses. It will give you the exact `time_to_first_token` and `tokens_per_second` for every request.
*   **ServerTop:** Run this in a dedicated terminal. You need to capture the **VRAM Usage** and **GPU Utilization %** at the exact moment the prompt is sent.
*   **SQLite Reports:** Ensure your OpenWebUI or Proxy is logging every request into a local SQLite database. This allows us to run aggregate queries later.

### 3. Standardized Request Method
Do not use the OpenWebUI chat interface for benchmarking. The UI adds overhead and variable latency. Use `curl` to send identical payloads.

**Example Benchmark Curl:**
```bash
# Test 1: Baseline (No MTP)
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "your-model-name",
    "messages": [{"role": "user", "content": "Write a 500-word essay on the thermodynamics of steam engines."}],
    "temperature": 0.7,
    "max_tokens": 500,
    "stream": false
  }' > baseline_test_1.json

# Test 2: MTP Enabled
# (Change the model name or the specific MTP flag in your llama.cpp server startup)
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "your-model-name-mtp",
    "messages": [{"role": "user", "content": "Write a 500-word essay on the thermodynamics of steam engines."}],
    "temperature": 0.7,
    "max_tokens": 500,
    "stream": false
  }' > mtp_test_1.json
```

---

# MTP Comparison Plan

You need to determine if MTP is actually providing a net gain or just "faking" speed by sacrificing quality.

### The "A/B" Test Matrix
Run 5 iterations of each of the following prompts for both **Non-MTP** and **MTP** profiles.

| Test Type | Prompt Example | Goal |
| :--- | :--- | :--- |
| **Short Logic** | "Solve for x: 2x + 5 = 15" | Check if MTP breaks simple logic. |
| **Creative Flow** | "Write a poem about a lonely robot in a forest." | Check if MTP makes the prose repetitive. |
| **Coding Snippet** | "Write a Python function to sort a list of dictionaries by a key." | Check if MTP messes up syntax/indentation. |
| **Long Context** | (Paste a 2000-word article) + "Summarize this in 3 bullets." | Check if MTP handles large prefill correctly. |

### Metrics to Compare:
1.  **TTFT (Time to First Token):** Does MTP make the "start" slower?
2.  **Average TPS (Tokens Per Second):** Is the "typing" speed actually faster?
3.  **Perplexity/Quality Score:** (Subjective) Does the MTP version feel "hallucination-prone"?

---

# Reasoning Budget Plan

"Reasoning" in local models is often a function of **Chain of Thought (CoT)**. If a model is "slow," it might be because it's thinking too much, or it might be because the hardware is struggling.

### How to Measure Reasoning Budget:
1.  **The "Think" Ratio:** For a complex task (e.g., "Plan a 3-day trip to Tokyo"), measure the number of tokens generated before the final answer.
2.  **The Cost of Thought:**
    *   Run the prompt with a "Brief" instruction: "Give me a 3-day Tokyo itinerary."
    *   Run the prompt with a "Reasoning" instruction: "Think step-by-step about the logistics, budget, and geography of Tokyo, then provide a 3-day itinerary."
3.  **The Benchmark:**
    *   Calculate: `(Reasoning Tokens / Total Tokens) * 100`.
    *   If your model spends 80% of its budget on "thinking" but the output is still wrong, your model is "over-reasoning" (looping) or the weights are poorly tuned for that context.

---

# Long Output Test Plan

This is where most home-labs fail. As the context fills up, the KV Cache grows, and performance usually degrades.

### The "Stress Test" Procedure:
1.  **The Growing Prompt:** Create a test where you increase the prompt length by 500 words every iteration (e.g., 500, 1000, 1500... up to 8000).
2.  **The TPS Decay Curve:** Record the TPS at each step.
    *   *Ideal:* TPS stays relatively flat.
    *   *Problematic:* TPS drops by 50% once you hit 4000 tokens. This indicates your KV Cache is hitting a memory limit or your GPU is swapping to system RAM.
3.  **The "Lost in the Middle" Test:**
    *   Place a specific fact (e.g., "The secret code is 9921") in the middle of a 4000-word prompt.
    *   Ask the model: "What is the secret code?"
    *   Compare MTP vs. Non-MTP. MTP can sometimes "skip" over middle-context details because it is optimized for the *next* token, not the *entire* history.

---

# SQLite Queries

Assuming your Flight Recorder or OpenWebUI is logging to a database (e.g., `logs` table with columns `model`, `ttft`, `tps`, `prompt_tokens`, `completion_tokens`, `mtp_enabled`).

### 1. Average Performance by Model
```sql
SELECT 
    model, 
    AVG(ttft) as avg_ttft, 
    AVG(tps) as avg_tps,
    COUNT(*) as total_requests
FROM logs
GROUP BY model;
```

### 2. MTP Impact Analysis
```sql
SELECT 
    mtp_enabled,
    AVG(ttft) as avg_ttft, 
    AVG(tps) as avg_tps,
    (AVG(tps) - AVG(ttft)) as net_speed_delta
FROM logs
GROUP BY mtp_enabled;
```

### 3. Identifying "Slow" Outliers
Find requests that took longer than 10 seconds to start (TTFT).
```sql
SELECT 
    prompt_tokens, 
    ttft, 
    tps, 
    model 
FROM logs 
WHERE ttft > 10000 
ORDER BY ttft DESC;
```
*Analysis: If `prompt_tokens` is high in these results, you have a Prefill/VRAM bottleneck.*

---

# Dashboard Screenshots To Capture

When you present your findings (or review them), you need these three specific visual "proofs":

### 1. The ServerTop "VRAM Sawtooth"
*   **What to capture:** A screenshot of the VRAM usage during a long generation.
*   **What to look for:** If the VRAM usage looks like a "sawtooth" (spiking up and down), your `llama.cpp` is likely re-allocating memory or hitting a cache limit. You want a flat line after the initial prompt is processed.

### 2. The Flight Recorder "Latency Distribution"
*   **What to capture:** A histogram of TTFT (Time to First Token).
*   **What to look for:** A "Bimodal" distribution (two humps). One hump at 200ms (fast) and one at 5000ms (slow). This tells you that your system is inconsistent—likely due to some prompts triggering a "slow path" (CPU offloading).

### 3. The TPS vs. Context Length Chart
*   **What to capture:** A line graph where X-axis is `prompt_tokens` and Y-axis is `tps`.
*   **What to look for:** The "Cliff." The point where the line drops sharply is your hardware's effective context limit.

---

# Weekend Checklist

### Saturday: The Baseline (The "Control" Group)
- [ ] **Clean the House:** Close all non-essential apps.
- [ ] **Standardize:** Pick one model (e.g., Llama-3-8B-Instruct-GGUF).
- [ ] **Disable MTP:** Run 10 iterations of the "Short Logic" and "Creative Flow" prompts.
- [ ] **Record:** Capture TTFT, TPS, and VRAM usage for each.
- [ ] **SQL Log:** Ensure all 10 runs are in your SQLite DB.
- [ ] **Analyze:** Calculate your "Baseline TPS."

### Sunday: The MTP & Stress Test
- [ ] **Enable MTP:** Run the same 10 iterations with MTP enabled.
- [ ] **Compare:** Run the SQL query to see the delta in TTFT and TPS.
- [ ] **Stress Test:** Run the "Growing Prompt" test (500 to 8000 tokens).
- [ ] **Identify the Cliff:** Note the token count where TPS drops by >30%.
- [ ] **Final Decision:** Decide if MTP is worth the "quality" cost based on your Creative vs. Logic tests.

---

# Interpreting Results

How do you decide what to do with the data? Use this decision matrix:

### 1. If TTFT is high, but TPS is great:
*   **Diagnosis:** Prefill Bottleneck.
*   **Fix:** Increase `n_batch` (if VRAM allows) or decrease `ctx_size`. If you are using a very large prompt, you may need to move to a model with a smaller "hidden dimension" or use a faster GPU.

### 2. If TPS is low, and VRAM is jumping:
*   **Diagnosis:** Memory Swapping.
*   **Fix:** You are trying to fit too much into the GPU. Reduce `n_gpu_layers` slightly to see if a stable, slower speed is better than an inconsistent, "jumping" speed.

### 3. If MTP makes the model "stupid":
*   **Diagnosis:** MTP Over-optimization.
*   **Fix:** Disable MTP for **Coding** and **Agentic** work. Keep MTP enabled for **Creative Writing** or **Chat** where "flow" matters more than perfect logic.

### 4. Use-Case Recommendations:
*   **Coding:** Prioritize **Non-MTP**, high `n_batch`, and high `ctx_size`. Accuracy is king; "flow" is secondary.
*   **RAG (Retrieval Augmented Generation):** Prioritize **TTFT**. You want the answer to start immediately. Use a smaller model with a massive KV cache.
*   **Agentic Work:** Prioritize **Consistency**. You need the model to follow instructions perfectly. Avoid MTP here as it can cause "drift" in long chains of thought.
*   **Creative Writing:** Prioritize **TPS**. This is where MTP shines. You want the words to pour out of the screen like a fountain.

---

# Common Mistakes

1.  **The "Moving Target" Mistake:** Changing the `temperature` or `top_p` between tests. This changes the "randomness" of the output, making it impossible to tell if MTP caused a hallucination or if the dice just rolled poorly.
2.  **Ignoring Thermal Throttling:** If you run a benchmark for 30 minutes, your GPU might heat up and downclock. **Run benchmarks in "bursts"** (e.g., 3 requests, then wait 60 seconds) to keep temperatures stable.
3.  **The "OpenWebUI Overhead" Trap:** If you are benchmarking through the web UI, the time it takes for the browser to render the text is added to your "latency." Always use `curl` for raw numbers.
4.  **Context Confusion:** Forgetting that `ctx_size` includes the prompt *and* the generation. If you set `ctx_size` to 8192 and your prompt is 8000, you only have 192 tokens of "room" left. The model will feel like it's "choking" because it's hitting the ceiling immediately.
5.  **MTP vs. Quantization:** Don't confuse MTP slowdowns with quantization artifacts. If a model feels "dumb," check if you've gone too low on bits (e.g., 3-bit). Always start your tests at 4-bit or 6-bit to ensure the "intelligence" is intact before testing the "speed."

### Advanced Parameter Deep Dive

To move beyond "vibe-based" tuning, you must understand the mechanics of the parameters you are adjusting in `llama.cpp`. Each one affects the balance between **Latency** (how fast a single token appears), **Throughput** (how many tokens are generated per second), and **Memory Footprint**.

#### 1. `n_batch` vs. `n_ubatch`
These are often confused, but they serve different roles in the inference pipeline.
*   **`n_batch`**: This defines the maximum number of tokens the model can process in a single "forward pass" during the **prefill** stage (the prompt). If you have a 1000-token prompt and `n_batch` is 512, `llama.cpp` will process the prompt in two chunks.
    *   *Optimization:* If your TTFT is slow, increase `n_batch` to the highest value your VRAM can handle (e.g., 2048 or 4096).
*   **`n_ubatch`**: This is the "micro-batch" size. It determines how many tokens are processed in parallel during the **decoding** stage.
    *   *Optimization:* For most home-lab setups, `n_ubatch` should be kept relatively small (e.g., 128 or 256) to ensure that the GPU's compute units are saturated without overflowing the cache.

#### 2. `flash_attn` (Flash Attention)
If your hardware supports it (NVIDIA Ampere and newer, or certain Mac Silicon configurations), always enable Flash Attention.
*   **Why it matters:** Standard attention has a quadratic complexity $O(n^2)$ relative to context length. Flash Attention uses a tiling approach to reduce memory overhead and speed up the calculation of the attention matrix.
*   **The Impact:** It significantly reduces the memory "spike" during the prefill of long prompts and allows for much larger context windows before the "TPS Cliff" occurs.

#### 3. `mmap` and `threads`
*   **`mmap`**: This allows the OS to map the model file into memory.
    *   *Pro:* Faster startup times and lower initial RAM overhead.
    *   *Con:* On some filesystems (like networked drives or slow HDDs), it can cause stuttering during the first few tokens as the OS pages the weights into memory. For a home lab with an NVMe SSD, keep `mmap` enabled.
*   **`threads`**: This is the number of CPU threads used for the non-GPU parts of the computation.
    *   *The Rule:* Do not set this to your total logical core count. Set it to your number of **physical cores**. Over-threading leads to "context switching" overhead, which actually slows down the model.

---

### The KV Cache Architecture & Memory Math

One of the biggest sources of "inconsistency" is the KV (Key-Value) Cache. Every token generated requires the model to "remember" the previous tokens. This memory grows as the conversation progresses.

#### How to Calculate Your Cache Limit
To avoid the "GPU Memory Jump," you need to know how much VRAM your context window actually consumes. The formula for KV Cache size is roughly:
$$\text{Memory (Bytes)} = 2 \times \text{Layers} \times \text{Heads} \times \text{Head\_Dim} \times \text{Precision} \times \text{Context\_Size}$$

**Example: Llama-3-8B (Standard Configuration)**
*   Layers: 32
*   Heads: 32
*   Head_Dim: 1280
*   Precision: 2 bytes (FP16)
*   Context Size: 8192

$$\text{Calculation: } 2 \times 32 \times 32 \times 1280 \times 2 \times 8192 \approx 4.2 \text{ GB}$$

**The Takeaway:** If you have a 12GB GPU and a 7B model (which takes ~5GB in 4-bit), and you want an 8k context, you only have about 3GB of "headroom" left. If your prompt is large, the KV cache will quickly eat that remaining space, causing the "Memory Jump" or an Out-of-Memory (OOM) error.

#### Cache Optimization Strategies
*   **`cache_type_k` and `cache_type_v`**: You can quantize the KV cache itself. Using `q4_0` or `q8_0` for the cache can reduce the memory footprint by 50-75% with negligible impact on logic. This is the single best way to "stabilize" memory usage for long conversations.
*   **`ctx_size`**: Always set this to the maximum you *expect* to use, plus a 10% buffer. If you set it too low, the model will "forget" the start of the conversation. If you set it too high, you waste VRAM that could be used for larger models.

---

### Quantization & MTP Dynamics

Multi-Token Prediction (MTP) works by training the model to predict the next $N$ tokens simultaneously. This creates a "lookahead" buffer.

#### The Precision Conflict
When you use heavy quantization (e.g., 3-bit or 2-bit), the "noise" in the weights can interfere with MTP's ability to predict accurately.
*   **The Observation:** You may find that MTP works beautifully on a 6-bit (Q6_K) model but causes the model to "loop" or "hallucinate" on a 3-bit (Q3_K_S) model.
*   **The Recommendation:** If you are using MTP, do not go below 4-bit quantization. The "intelligence" required to maintain a coherent multi-token lookahead is significantly higher than the intelligence required for single-token generation.

#### MTP Buffer Management
MTP requires extra memory for the "lookahead" tokens. If you see a memory jump specifically when MTP is enabled, it is likely because the buffer is being allocated dynamically.
*   **Fix:** Check your `llama.cpp` build/flags to see if you can pre-allocate the MTP buffer. This will move the "jump" to the startup phase, making the actual generation smooth.

---

### Hardware-Specific Optimization

Your hardware dictates the "ceiling" of your performance.

#### 1. NVIDIA (CUDA)
*   **Bottleneck:** PCIe Bandwidth. If you are offloading layers to a GPU but the model is still partially on the CPU, the data must travel across the PCIe bus.
*   **Optimization:** Ensure your GPU is in a PCIe x16 slot. If you are using a multi-GPU setup, ensure they are connected via NVLink if possible, or that your `n_gpu_layers` is balanced across both.

#### 2. AMD (ROCm)
*   **Bottleneck:** Memory Bandwidth. ROCm is highly efficient but can be sensitive to `n_batch` sizes.
*   **Optimization:** AMD cards often perform better with slightly smaller `n_batch` sizes than NVIDIA cards. If you see "stuttering," drop `n_batch` from 512 to 256.

#### 3. Apple Silicon (Metal)
*   **Bottleneck:** Unified Memory Bandwidth. Since the CPU and GPU share memory, "Memory Jumps" are often actually the OS moving memory pages between the CPU and GPU pools.
*   **Optimization:** Use the `mmap` flag and ensure you are using the `Metal` backend. On Mac, the "Slow First Token" is often just the system waking up the GPU's unified memory controller.

---

### Agentic Workflow & Tool-Calling Benchmarks

If you are using the model for agents (e.g., AutoGPT, LangChain, or OpenWebUI Functions), "Tokens Per Second" is a secondary metric. The primary metric is **Instruction Adherence** and **Loop Success Rate**.

#### How to Benchmark Agents:
1.  **The "Tool Call" Test:** Give the model a tool (e.g., a calculator or a search function) and a complex math problem.
    *   *Metric:* Did it call the tool correctly? (Pass/Fail).
    *   *MTP Impact:* MTP can sometimes cause the model to "skip" the tool call and jump straight to a fake answer because it "predicted" the answer too early.
2.  **The "Loop" Test:** Give the model a task that requires 3 steps (e.g., "Find the weather in Tokyo, then find a restaurant there, then write an email to my friend about it").
    *   *Metric:* How many "turns" did it take to finish?
    *   *Inconsistency Check:* If the model succeeds 8/10 times without MTP but only 4/10 times with MTP, the MTP is "over-predicting" and causing the agent to lose the thread of the multi-step plan.

---

### RAG-Specific Latency & Context Injection

In Retrieval Augmented Generation (RAG), the "Slow First Token" is your biggest enemy. Users hate waiting 10 seconds for a response after the system has already spent 3 seconds "searching" the database.

#### Benchmarking RAG:
*   **Context Injection Latency:** Measure the time from "Prompt Sent" to "First Token" when the prompt contains 500 words of retrieved text.
*   **The "Needle in a Haystack" Test:**
    *   Insert a random fact into a 4000-word context.
    *   Ask the model about that fact.
    *   *Why:* RAG systems often fail because the model "ignores" the retrieved context in favor of its internal weights. If MTP makes the model "ignore" the context more often, it is useless for RAG.

---

### Advanced SQL for Statistical Analysis

To truly see if your model is "inconsistent," you need to look at the **Standard Deviation** of your metrics. A model with an average of 50 TPS but a standard deviation of 30 is "unreliable." A model with an average of 40 TPS and a standard deviation of 2 is "stable."

#### 1. Standard Deviation of TTFT (The "Inconsistency" Score)
```sql
SELECT 
    model, 
    AVG(ttft) as avg_ttft, 
    STDDEV(ttft) as ttft_instability,
    AVG(tps) as avg_tps
FROM logs
GROUP BY model;
```
*Interpretation:* If `ttft_instability` is high, your system is struggling with memory allocation or CPU/GPU handoffs.

#### 2. TPS Decay over Context Length
This query helps you find the "Cliff" where your hardware gives up.
```sql
SELECT 
    prompt_tokens, 
    AVG(tps) as avg_tps,
    COUNT(*) as sample_count
FROM logs
WHERE model = 'your-model-name'
GROUP BY prompt_tokens
ORDER BY prompt_tokens ASC;
```
*Analysis:* Plot this in a spreadsheet. The point where the line drops sharply is your hardware's "Context Ceiling."

---

### The "Golden Set" of Prompts

Use these exact prompts for your weekend benchmark. They are designed to trigger different "modes" of the model.

#### Category: Logic & Reasoning (Non-MTP Preferred)
1. "If I have three apples and you take away two, how many apples do you have?"
2. "Write a Python script to find the first non-repeating character in a string."
3. "Explain the difference between 'affect' and 'effect' with three examples."
4. "Solve for x: 3x^2 - 12x + 9 = 0."
5. "A man is looking at a photo. He says, 'Brothers and sisters I have none, but that man's father is my father's son.' Who is in the photo?"

#### Category: Creative Flow (MTP Preferred)
6. "Write a noir detective story about a missing toaster."
7. "Describe a futuristic city where the buildings are made of living coral."
8. "Write a poem in the style of Robert Frost about a broken smartphone."
9. "Create a dialogue between a grumpy wizard and a hyperactive goblin."
10. "Write a 200-word description of a forest where the trees whisper secrets."

#### Category: Long Context & RAG (Stress Test)
11. (Paste a 2000-word news article) + "Summarize the three most important economic impacts mentioned."
12. (Paste a 2000-word news article) + "What did the author say about the specific impact on small businesses?"
13. (Paste a 2000-word news article) + "Write a counter-argument to the author's main thesis."
14. (Paste a 2000-word news article) + "Extract all dates and events into a chronological list."
15. (Paste a 2000-word news article) + "Who is the primary antagonist of this piece and why?"

#### Category: Agentic / Tool Use
16. "You have a tool `get_weather(city)`. Use it to find the weather in London and tell me if I need an umbrella."
17. "You have a tool `search_database(query)`. Find the price of 'Item X' and tell me if it's under $50."
18. "Plan a 5-step itinerary for a trip to Kyoto, including a restaurant for each day."
19. "Refactor the following code to be more memory efficient: [Insert a messy Python function]."
20. "Write a professional email to a client explaining that their project will be delayed by two days due to a server outage."

---

### Troubleshooting "Stuck" Generations & Deadlocks

Sometimes, the model won't just be slow; it will stop entirely or "hang."

#### 1. The "Infinite Loop"
*   **Symptom:** The model repeats the same word or phrase forever (e.g., "and the and the and the...").
*   **Cause:** Usually a combination of low `repeat_penalty`, high `temperature`, and MTP over-predicting a common sequence.
*   **Fix:** Increase `repeat_penalty` to 1.15 or 1.2. Lower `temperature` to 0.7.

#### 2. The "Silent Hang"
*   **Symptom:** The prompt is sent, the "Time to First Token" keeps climbing, and eventually, the connection times out.
*   **Cause:** This is usually a **Deadlock**. It happens when the GPU is trying to access a memory address that the CPU has locked, or when the `n_batch` is so large that the GPU's command queue is overwhelmed.
*   **Fix:** Reduce `n_batch` to 512. Ensure your `llama.cpp` is compiled with the correct flags for your specific GPU (e.g., `GGML_CUDA=1`).

#### 3. The "Context Overflow" Crash
*   **Symptom:** The model works fine for 3 turns, but on the 4th turn, the server crashes or returns a 500 error.
*   **Cause:** You hit the hard limit of your VRAM. The KV cache grew until there was no room left for the next token's calculation.
*   **Fix:** Decrease your `ctx_size` or use a more aggressive KV cache quantization (like `q4_0`).

---

### Long-term Monitoring & Grafana Integration

If you want to stop guessing and start "knowing," you need to move from "Weekend Benchmarks" to "Continuous Monitoring."

#### The Stack:
1.  **Prometheus:** To scrape metrics.
2.  **Grafana:** To visualize the data.
3.  **Exporter:** Use a `llama.cpp` exporter (or a custom script that reads your SQLite logs) to feed data into Prometheus.

#### What to Track Daily:
*   **Average TPS per Model:** Identify which models are "fast" for your users.
*   **TTFT Percentiles:** Don't just look at the average. Look at the **P99** (the 99th percentile). If your P99 is 10 seconds, it means 1% of your users are having a terrible experience.
*   **VRAM Utilization:** Track how much VRAM is "free" on average. If it's always near 95%, you are one long prompt away from a crash.
*   **Token Count per User:** Identify "power users" who might be hitting your context limits more often than others.

#### The "Health Check" Dashboard:
Create a dashboard with three "Red Alert" gauges:
1.  **TTFT > 3 seconds:** (Alerts you to a prefill bottleneck).
2.  **TPS < 10:** (Alerts you to a decoding bottleneck or thermal throttling).
3.  **VRAM > 90%:** (Alerts you to an impending OOM crash).

By implementing this system, you transform your home lab from a hobbyist's playground into a professional-grade inference engine. You will no longer ask "Why does it feel slow?" You will look at your dashboard and say, "The P99 TTFT is high because the KV cache is hitting the 8k limit; I need to increase the cache quantization." That is the difference between a user and a lab assistant.

### Model Selection Matrix: The "Right Tool" Philosophy

One of the most common mistakes in home-lab management is trying to force a single model to perform every task perfectly. In a professional lab environment, we use a "Multi-Model Routing" strategy. Depending on your weekend results, you should categorize your models into specific "Workstreams."

#### 1. The Coding Workstream
*   **Priority:** Logic, Syntax Accuracy, Context Retention.
*   **Model Choice:** Larger parameter counts (e.g., 30B+ or 70B) are significantly better here.
*   **Quantization:** Use **Q6_K** or **Q8_0**. Coding requires high precision; a 3-bit quantization can lead to "hallucinated" library functions or incorrect indentation.
*   **MTP Status:** **OFF**. MTP can occasionally cause the model to skip a closing bracket or a semicolon because it is "predicting" the end of the block too aggressively.
*   **Context:** High (at least 8k-16k).

#### 2. The RAG (Retrieval Augmented Generation) Workstream
*   **Priority:** TTFT (Time to First Token), Contextual Grounding.
*   **Model Choice:** Smaller, faster models (e.g., 7B or 8B) are often superior because they can be fed massive amounts of retrieved context without hitting the "TPS Cliff" as quickly.
*   **Quantization:** **Q4_K_M** is the "Goldilocks" zone—it provides the best balance of speed and intelligence.
*   **MTP Status:** **OFF**. In RAG, you want the model to be extremely literal. MTP can sometimes cause the model to "summarize" the retrieved context too much, losing the specific details you need.
*   **Context:** Very High (32k+ if your hardware allows).

#### 3. The Creative & Chat Workstream
*   **Priority:** Flow, Prose Quality, Variety.
*   **Model Choice:** 7B to 30B models.
*   **Quantization:** **Q4_K_M** or **Q5_K_M**.
*   **MTP Status:** **ON**. This is where MTP shines. It makes the "typing" feel like a human is writing at high speed, and it helps maintain a consistent "voice" in long-form creative writing.
*   **Context:** Moderate (4k-8k).

#### 4. The Agentic Workstream
*   **Priority:** Instruction Following, Tool Calling, Reliability.
*   **Model Choice:** High-reasoning models (e.g., Llama-3-70B or specialized "Instruct" variants).
*   **Quantization:** **Q6_K** or higher.
*   **MTP Status:** **OFF**. Agents require 100% reliability in the "Chain of Thought." Any "prediction" that skips a logical step in a tool-call sequence will break the entire agent loop.
*   **Context:** Moderate (8k).

---

### The Quantization Spectrum: Finding the Sweet Spot

When you see "inconsistency" in `llama.cpp`, it is often a result of the quantization method. Not all 4-bit quants are created equal.

#### K-Quants (The Modern Standard)
If you are using GGUF files, you will see "K-Quants" (like Q4_K_M, Q5_K_S). These are designed to distribute the "importance" of weights more intelligently.
*   **Q4_K_M:** The industry standard. It retains about 95-98% of the original model's intelligence while being extremely fast.
*   **Q5_K_M:** The "High Fidelity" choice. If you notice the model is starting to lose its "edge" or making silly mistakes in logic, move from Q4 to Q5. The memory jump will be slightly larger, but the stability will increase.
*   **Q8_0:** Use this only for your "Master" models (the ones you use for complex coding or high-stakes reasoning). It is nearly indistinguishable from the FP16 original but takes up significantly more VRAM.

#### The "Perplexity" Trade-off
Every time you lower the bits, you increase the "Perplexity" (a measure of how confused the model is).
*   **Rule of Thumb:** If your model feels "inconsistent" (sometimes smart, sometimes dumb), your quantization is likely too low for the complexity of the task.
*   **Action:** If a 7B model at Q3_K feels inconsistent, move to a 13B or 30B model at Q4_K_M. **Size beats bits** in almost every scenario.

---

### System-Level Optimization: Squeezing the Hardware

Sometimes the "inconsistency" isn't the model—it's the OS or the driver.

#### 1. Linux (The Gold Standard for Stability)
*   **NVIDIA Persistence Mode:** Ensure this is on. It keeps the driver loaded even when no process is using the GPU, preventing the "slow first token" caused by the driver "waking up."
    *   `sudo nvidia-smi -pm 1`
*   **HugePages:** Enabling HugePages can improve memory access speeds for large models.
*   **GPU Priority:** Use `nice` or `renice` to ensure the `llama.cpp` process has high CPU priority.

#### 2. Windows (The "Power Management" Trap)
*   **High Performance Mode:** Ensure your Windows Power Plan is set to "High Performance." Windows often tries to "park" CPU cores or downclock the GPU to save power, which causes massive TPS fluctuations.
*   **Hardware-Accelerated GPU Scheduling (HAGS):** For some users, turning HAGS *off* in Windows Settings improves `llama.cpp` stability. For others, turning it *on* helps. You must test both.
*   **NVIDIA Control Panel:** Set "Power Management Mode" to "Prefer Maximum Performance" specifically for the `llama.cpp` executable.

#### 3. Apple Silicon (The Unified Memory Factor)
*   **Metal Performance:** Ensure you are using the Metal backend.
*   **Memory Pressure:** On a Mac, if you have 16GB of RAM and you try to run a 12GB model, the system will start "swapping" to the SSD. This will cause the "TPS Cliff" to happen almost immediately.
*   **Rule:** Always leave at least 4GB of "System RAM" free. If you have 32GB of RAM, do not try to load a model that takes up more than 24GB.

---

### The Subjective Quality Scorecard

Because "intelligence" is hard to measure with a single number, you should use a **Subjective Quality Scorecard** during your weekend test. After every prompt in your "A/B Test Matrix," give the model a score from 1 to 5 on the following:

| Metric | Definition | Score (1-5) |
| :--- | :--- | :--- |
| **Coherence** | Did the response make sense from start to finish? | |
| **Factuality** | Did it hallucinate any dates, names, or facts? | |
| **Instruction Adherence** | Did it follow every constraint (e.g., "no adjectives")? | |
| **Style/Flow** | Did the prose feel natural or "robotic"? | |
| **Logic** | Did it solve the math/coding problem correctly? | |

**How to use this:**
Compare the **Average Score** of the Non-MTP vs. MTP runs.
*   If MTP has a higher **Style/Flow** score but a lower **Logic** score, you have your answer: Use MTP for creative writing, but turn it off for coding.
*   If MTP has a lower score in *every* category, MTP is not working correctly with your current quantization or model.

---

### Final Lab Report Template

At the end of your weekend, fill out this report. This will be your "Source of Truth" for the next six months.

**Model Name:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
**Quantization:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
**MTP Enabled:** [Yes / No]

**Performance Metrics:**
*   **Avg TTFT (Non-MTP):** \_\_\_\_\_\_\_\_ ms
*   **Avg TTFT (MTP):** \_\_\_\_\_\_\_\_ ms
*   **Avg TPS (Non-MTP):** \_\_\_\_\_\_\_\_ tokens/sec
*   **Avg TPS (MTP):** \_\_\_\_\_\_\_\_ tokens/sec
*   **Context Cliff Point:** \_\_\_\_\_\_\_\_ tokens (Where TPS drops >30%)

**Quality Metrics (Average Scores):**
*   **Logic Score:** \_\_\_\_\_\_\_\_ / 5
*   **Creative Score:** \_\_\_\_\_\_\_\_ / 5
*   **Instruction Score:** \_\_\_\_\_\_\_\_ / 5

**Final Verdict:**
*   **Best Use Case:** (e.g., "Coding only," "Creative only," "General Chat")
*   **Recommendation:** (e.g., "Keep MTP off for this model," "Increase n_batch to 2048")

---

### Advanced Troubleshooting: The "Ghost in the Machine"

If you follow all the steps and still see "inconsistency," check these three "Ghost" issues:

#### 1. The "Zombie" Process
Sometimes, a previous `llama.cpp` instance doesn't close properly and hangs onto a portion of the VRAM.
*   **Fix:** Restart your machine. It sounds simple, but it clears the GPU's memory registers and ensures a clean slate for your benchmark.

#### 2. The "Thermal Throttling" Ghost
If your GPU hits 80°C+, it will automatically downclock. This causes the TPS to drop mid-generation.
*   **Fix:** Use a tool like MSI Afterburner (Windows) or `nvidia-smi` (Linux) to monitor temperatures during your "Long Output Test." If you see a temperature spike coinciding with a TPS drop, you need to increase your fan speeds or lower your power limit.

#### 3. The "Context Shuffling" Ghost
In some versions of `llama.cpp`, if the KV cache is not pre-allocated, the system has to "re-calculate" the attention for the entire prompt every time a new token is added.
*   **Fix:** Ensure you are using the `--ctx-size` flag correctly and that your `n_batch` is high enough to handle the prompt in as few passes as possible.

By following this guide, you move from being a "user" of AI to a "researcher" of AI. You are no longer guessing why the model feels slow; you are measuring the hardware's limits, the software's overhead, and the model's inherent capabilities. This is the path to a perfectly tuned home lab.