# PPT 补充 · D1 (np=64) + D2 (PCGUARD 证据) + D3 (覆盖率计算代码)

> 实验机 `ubuntu@cuda-ke`。D4(freetype2 多轮)、D5 见后续文件。

---

## D1 · np=64 实测(libxml2 = gfts-xml_read_fuzzer,120s,与 2/8/32/128/190 同设置)

**一行给你插表**:`mpi np=64 → 16,881 tc/s,edge_cov 6.75%(3432/50880)`
（另:`hybrid np=64 → 1,450 tc/s,edge_cov 10.91%(5553/50880)`）

补上 np=64 后,MPI 扩展全貌:

| np | tc/s | edge_cov |
|---:|---:|---:|
| 2 | 128 | 5.67% |
| 8 | 1,604 | 5.88% |
| 32 | 7,683 | 6.13% |
| **64** | **16,881** | **6.75%** ← 新增 |
| 128 | 15,022 | 6.26% |
| 190 | 13,906 | 6.17% |

**回答评委"32→64 还线性吗、会否超 128"**:
- **吞吐**:32→64 **超线性**(7,683→16,881 = **2.20×**,2 倍进程拿到 >2 倍吞吐);且 **64 是峰值**——
  64→128 反而**掉**(16,881→15,022),128→190 继续掉(→13,906)。
- **边覆盖**:32→64 上升(6.13→6.75%),且 **np=64 超过 np=128(6.75 > 6.26)也超过 np=190(6.17)**。
- **结论**:**甜点在 ≈64**;过了 64,吞吐与覆盖【双双回落】(worker 冗余/争用 + master 调度压力)。
  这正好补上评委说"图不清晰"的那段——64 不但没继续线性涨,反而是拐点,且明确优于 128/190。

---

## D2 · PCGUARD 插桩证据("数 BB 还是边"的定论)  → 见 `img_d2_pcguard.png`

小程序 `bb_demo.c`(4 个 if):

1. **规范 PCGUARD**:`clang -fsanitize-coverage=trace-pc-guard -c bb_demo.c` 后 `objdump -dr`——
   **`main` 里 `__sanitizer_cov_trace_pc_guard` 调用 = 10 个 = 基本块数**(每个 BB 开头埋 1 个 guard)。
2. **AFL++ afl-clang-fast**:同为 trace-pc-guard,但把 guard 自增【内联】(更快);
   `__sancov_guards` 段 = 44 字节 = **11 个 4B guard ⇒ 每 BB 一个,无 hash 碰撞**。
3. **afl-showmap -C**:`A coverage of 9 edges were achieved out of 64 existing (14.06%) with 4 input files`。

**定论(已按 Q6 #4 反汇编核实更正)**:每个插桩位置一个**唯一 guard**;运行时 `__afl_area_ptr[*guard]++`
是**直接用 guard 值索引**(反汇编实证:`%fs`-XOR 站点=0、`__afl_prev_loc` 不参与增量,**没有** `(prev>>1)⊕cur`
异或),分母 = 本目标 guard 数(向上取整 64),**无碰撞**。AFL++ `LLVM-PCGUARD` 会**拆分关键边**,故每 guard
≈ 一条 CFG 边 → 我们报的是**无碰撞的边覆盖**,分母是真实 guard 数(xml=50880),**不是 65536 hash 图,
也不是经典 AFL 的 `(prev>>1)⊕cur`**。〔勘误:此前此处写的"`prev>>1 ^ cur` 边编码"不准确,详见 `Q6_补充.md` #4。〕

---

## D3 · 覆盖率计算代码(评委要看代码)

`benchmark/run_benchmark.py` 里解析 afl-showmap 输出、算边覆盖率的核心几行(`measure_coverage_afl()`）：

```python
# afl-showmap 输出到 stderr;解析 "A coverage of N edges were achieved out of M existing (X%)"
m = re.search(
    r"coverage of (\d+) edges were achieved out of (\d+) existing \(([0-9.]+)%\)",
    stderr)
if m:
    edges_found = int(m.group(1))          # N = 命中的边数
    edges_total = int(m.group(2))          # M = 该目标 guard 数(向上取整 64)
    edge_cov    = float(m.group(3))        # X% = afl-showmap 直接给的百分比
    measure_ok  = True
else:
    # 备用:从 "Captured N tuples (map size M)" 解析
    m2 = re.search(r"Captured (\d+) tuples \(map size (\d+)", stderr)
    if m2:
        edges_found = int(m2.group(1))
        edges_total = int(m2.group(2))
        edge_cov    = edges_found / edges_total * 100.0   # = N / M × 100
        measure_ok  = True
if not measure_ok:
    # 既无 coverage 行也无 Captured 行 → showmap 未正常完成(握手失败/启动崩溃/map 不匹配)
    # 关键:此时【不】把 0.0 当真实数据,而是告警 + 让调用方据 measure_ok 丢弃该点,
    #       避免污染均值/最佳配置选择("真 0 覆盖"与"测量失败"要区分)。
    print(f"[warn] afl-showmap 未产出覆盖率 ...", file=sys.stderr)
```

**要点**:①边覆盖率 = `afl-showmap -C` 直接给的 `X%`(= 命中边数 N / 目标 guard 数 M);
②有个**测量失败 vs 真 0 覆盖**的区分逻辑(`measure_ok`),失败点被丢弃而非当 0——保证均值/选优不被污染。
(代码位置:`benchmark/run_benchmark.py:613–641`。)
