Exhaustive drift-fix simulation V2 — KCC on shared-bottleneck wired path.

python 复制代码
#!/usr/bin/env python3
"""
Exhaustive drift-fix simulation V2 --- KCC on shared-bottleneck wired path.
Models Q-boost, adaptive BW, realistic queue, 12 candidate fixes, 4 scenarios.
"""
import math, random, sys, time
from collections import defaultdict

# Config
T_PROP_US    = 1400
LINK_CAP     = 1000000000  # 1 Gbps
MSS          = 12000  # bits (1500 bytes)
PKTS_SEC     = LINK_CAP // MSS
BUF_PKTS     = 200
NUM_FLOWS    = 11
SIM_SEC      = 5
SEED         = 42

SCALE     = 1024
BASE_R    = 400
J50       = 200
Q_BASE    = 100
R_MAX     = BASE_R * 256
PEST_INIT = 1000
PEST_MAX  = 100000000
PEST_FLOOR = 10
CWND_GAIN = 2
DRIFT_THR = 14
T2_MULT   = 4
T2_SHIFT  = 3
SAT_THR   = 55
SAT_HOLD  = 30
QBOOST_THR = 16 * 1000 * SCALE  # 16ms scaled

JITTER_BASE = 50
JITTER_BURST = 300
JITTER_BURST_P = 0.02

random.seed(SEED)

# ---------- Fix functions ----------
FIXES = []

def reg(name, fn, **kw):
    FIXES.append((name, fn, kw))

def fix_none(f, qd, xe, jit, ecn, t2c, rtt):
    return True
reg("0_BASELINE", fix_none)

def fix_qdelay50(f, qd, xe, jit, ecn, t2c, rtt):
    return qd < xe // 2
reg("1_qdelay<50%", fix_qdelay50)

def fix_jitter12(f, qd, xe, jit, ecn, t2c, rtt):
    return jit < xe // 8
reg("2_jitter<12.5%", fix_jitter12)

def fix_both(f, qd, xe, jit, ecn, t2c, rtt):
    return qd < xe // 2 and jit < xe // 8
reg("3_qdelay<50%+jitter<12.5%", fix_both)

def fix_no_t2(f, qd, xe, jit, ecn, t2c, rtt):
    return False
reg("4_Remove-Tier2", fix_no_t2)

def fix_qdelay_or_jit(f, qd, xe, jit, ecn, t2c, rtt):
    return qd < xe // 2 or jit < xe // 8
reg("5_qdelay<50%_OR_jitter<12.5%", fix_qdelay_or_jit)

def fix_qdelay25(f, qd, xe, jit, ecn, t2c, rtt):
    return qd < xe // 4
reg("6_qdelay<25%", fix_qdelay25)

def fix_qdelay_ecn(f, qd, xe, jit, ecn, t2c, rtt):
    return qd < xe // 2 and not ecn
reg("7_qdelay<50%+ECN", fix_qdelay_ecn)

def fix_qdelay50_t1style(f, qd, xe, jit, ecn, t2c, rtt):
    # Tier-2 fires with qdelay gate; Tier-1 uses jitter gate (already in sim)
    # This just adds qdelay to T2 like the other qdelay gates
    return qd < xe // 2
reg("8_qdelayT2_jitterT1", fix_qdelay50_t1style)

def fix_t2_rate_limit(f, qd, xe, jit, ecn, t2c, rtt):
    return True  # handled via caller time-check
reg("9_rate-limit_200ms", fix_t2_rate_limit)

def fix_ecn(f, qd, xe, jit, ecn, t2c, rtt):
    return not ecn
reg("10_ECN-gate", fix_ecn)

def fix_hybrid(f, qd, xe, jit, ecn, t2c, rtt):
    # Allow T2 if qdelay<25% (strict) OR if jitter>12.5% AND qdelay<50% (noisy+moderate)
    if qd < xe // 4:
        return True
    if jit > xe // 8 and qd < xe // 2:
        return True
    return False
reg("11_hybrid_strict25_or_noisy50", fix_hybrid)

def fix_qdelay25_loose(f, qd, xe, jit, ecn, t2c, rtt):
    # Progressive: qdelay < 25% always; 25-50% only if pos_skip >> 56
    if qd < xe // 4:
        return True
    if qd < xe // 2 and t2c > 3:
        return True
    return False
reg("12_progressive_qdelay", fix_qdelay25_loose)

# ---------- Simulation ----------
class Flow:
    def __init__(self):
        self.xe = 0
        self.pe = PEST_INIT
        self.psc = 0
        self.nsc = 0
        self.drift_sum = 0
        self.sat_hold = 0
        self.min_rtt_us = 10000000
        self.bw_est = LINK_CAP  # initial estimate
        self.retrans = 0
        self.pkts = 0
        self.last_t2_ms = 0.0
        self.qdelay_ewma = 0.0

def run_sim(name, n_flow, t_prop, shift_at=None, sim_s=60):
    results = {}
    for fix_name, fix_fn, fix_opts in FIXES:
        flows = [Flow() for _ in range(n_flow)]
        rate_ms = fix_opts.get("rate_limit_ms", 0)
        
        q_pkts = 0
        q_ewma = 0.0
        
        rtt_base = t_prop / 1e6
        rds_per_s = int(1.0 / rtt_base)
        total_rds = rds_per_s * sim_s
        
        for ri in range(total_rds):
            st_ms = ri * rtt_base * 1000.0
            st_s  = st_ms / 1000.0
            
            # Baseline shift
            tp = t_prop
            if shift_at is not None and st_s >= shift_at:
                tp = 50000
            
            # Each flow sends
            total_inflight = 0
            total_send = 0
            for fl in flows:
                if fl.xe == 0:
                    fl.xe = tp * SCALE
                    fl.min_rtt_us = tp
                
                # Adaptive BW estimate (simple EWMA of delivery rate)
                target_inflight = int(total_inflight * 0.98 / n_flow)  # share inflight

                xe_us = fl.xe // SCALE
                bdp = int(xe_us / 1e6 * fl.bw_est / MSS)
                bdp = max(bdp, 2)
                cwnd = bdp * CWND_GAIN
                cwnd = min(cwnd, 2000)  # prevent blowup
                total_inflight += cwnd
                total_send += cwnd
            
            # Queue: drain capacity_per_rtt, add inflight
            cap_per_rd = rtt_base * PKTS_SEC
            drained = min(q_pkts + total_send, cap_per_rd)
            q_pkts = max(0, q_pkts + total_send - drained)
            qd_us = (q_pkts / PKTS_SEC) * 1e6
            
            # Loss
            drops = 0
            if q_pkts > BUF_PKTS:
                drops = int(q_pkts - BUF_PKTS)
                q_pkts = BUF_PKTS
            if drops > 0:
                for fl in flows:
                    fl_drop = drops // n_flow
                    fl.retrans += fl_drop
                    total_send += fl_drop
            
            # EWMA qdelay
            alpha = 0.125
            q_ewma = q_ewma * (1 - alpha) + qd_us * alpha
            
            # Per-flow Kalman
            for fi, fl in enumerate(flows):
                fl.min_rtt_us = min(fl.min_rtt_us, tp + int(qd_us))
                
                jit = JITTER_BASE
                if random.random() < JITTER_BURST_P:
                    jit += JITTER_BURST
                jit += int(random.gauss(0, jit * 0.3))
                jit = max(0, min(jit, 10000))
                
                rtt = tp + int(qd_us) + jit
                z = rtt * SCALE
                nu = z - fl.xe
                
                # Adaptive R
                je = max(0, jit - jit // 4)
                if je > 0:
                    ratio = je / J50
                    r = max(BASE_R, min(int(BASE_R*ratio**1.5), R_MAX))
                else:
                    r = BASE_R
                
                p_pred = min(fl.pe + Q_BASE, PEST_MAX)
                K = p_pred / (p_pred + r)
                
                if nu <= 0:
                    fl.xe = min(z, 0xFFFFFFFF)
                    fl.pe = max(r, PEST_FLOOR)
                    fl.psc = 0
                    fl.nsc += 1
                    fl.drift_sum = 0
                else:
                    fl.psc += 1
                    fl.nsc = 0
                    fl.pe = p_pred
                    
                    # Q-boost
                    if abs(nu) > QBOOST_THR:
                        fl.pe = PEST_INIT
                        corr = int(K * nu)
                        nu_x = int(fl.xe + corr)
                        fl.xe = min(nu_x, 0xFFFFFFFF)
                        fl.psc = 0
                        fl.drift_sum = 0
                        continue
                    
                    # Saturation
                    if fl.pe >= PEST_MAX and fl.psc >= SAT_THR:
                        mrs = fl.min_rtt_us * SCALE
                        if fl.xe > mrs:
                            fl.xe = mrs
                            fl.psc = 0
                            fl.drift_sum = 0
                            fl.sat_hold = SAT_HOLD
                    
                    # Tier-2 (with gates)
                    eff_min = DRIFT_THR * T2_MULT
                    if fl.sat_hold > 0:
                        fl.sat_hold -= 1
                        if fl.xe >= fl.min_rtt_us * SCALE:
                            continue
                    
                    if fl.psc >= eff_min:
                        t2c = fl.psc // eff_min
                        xe_us = fl.xe // SCALE
                        ecn_flag = q_pkts > BUF_PKTS * 0.4
                        
                        # Rate limit
                        if rate_ms > 0 and st_ms - fl.last_t2_ms < rate_ms:
                            continue
                        
                        # Gate check
                        if not fix_fn(fl, int(q_ewma), xe_us, jit, ecn_flag, t2c, rtt):
                            continue
                        
                        corr = K * nu
                        dc = int(corr / 8)
                        if dc < 1: dc = 1
                        fl.xe = min(fl.xe + dc, 0xFFFFFFFF)
                        
                        if rate_ms > 0:
                            fl.last_t2_ms = st_ms
                
                fl.pkts += 1
                
                # Update BW estimate (EWMA delivery rate)
                delivered = min(cap_per_rd / n_flow, cwnd)
                fl.bw_est = fl.bw_est * 0.9 + (delivered * MSS / rtt_base) * 0.1
        
        total_rtr = sum(f.retrans for f in flows)
        total_pkt = sum(f.pkts for f in flows) + total_rtr
        loss = total_rtr / max(total_pkt, 1)
        avg_xe = sum(f.xe // SCALE for f in flows) / n_flow
        
        results[fix_name] = {
            "loss": loss, "retrans": total_rtr,
            "avg_xe_us": avg_xe,
            "final_xes": [f.xe // SCALE for f in flows]
        }
    return results

def fmt_table(res, sc):
    print(f"\n{'='*90}")
    print(f"  {sc}")
    print(f"{'='*90}")
    print(f"{'Fix':<38} {'Loss%':>8} {'Retrans':>10} {'AvgXest':>10}")
    print("-" * 72)
    for name, r in sorted(res.items(), key=lambda x: x[1]["loss"]):
        print(f"{name:<38} {r['loss']*100:>7.2f}% {r['retrans']:>10} {r['avg_xe_us']:>9.0f}us")
    return res

# ---- Run ----
print("Scenario A: 11 flows, 1.4ms baseline, persistent queue (matches iperf3)")
ra = run_sim("A", 11, T_PROP_US, shift_at=None)
fmt_table(ra, "A: 11 flows, 1.4ms wired")

print("\nScenario B: 1 flow, clean path")
rb = run_sim("B", 1, T_PROP_US, shift_at=None)
fmt_table(rb, "B: 1 flow, clean 1.4ms")

print("\nScenario C: 1 flow, baseline shift 1.4ms→50ms at t=10s")
rc = run_sim("C", 1, T_PROP_US, shift_at=10)
fmt_table(rc, "C: Baseline shift 1.4ms→50ms (BGP reroute)")

print("\nScenario D: 3 flows, shift at 30s")
rd = run_sim("D", 3, T_PROP_US, shift_at=30)
fmt_table(rd, "D: 3 flows baseline shift 1.4ms→50ms at 30s")

print("\n\n======= RANKING (avg loss across all 4 scenarios) =======")
names = sorted(ra.keys())
for i, n in enumerate(sorted(names, key=lambda n: (ra[n]["loss"]+rb[n]["loss"]+rc[n]["loss"]+rd[n]["loss"])/4)):
    avg = (ra[n]["loss"] + rb[n]["loss"] + rc[n]["loss"] + rd[n]["loss"]) / 4
    print(f"  {i+1:2d}. {n:<38} avg_loss={avg*100:.2f}%")
相关推荐
aiqianji1 小时前
有哪些支持长文的AI生成短篇小说软件?
人工智能·python
Macbethad1 小时前
基于TwinCAT的半导体刻蚀设备SCADA管理程序技术方案
运维·网络·数据库
狗都不学爬虫_1 小时前
AI逆向 - 某定制瑞树6纯算(ck-header-params后缀)
爬虫·python·网络爬虫
三十岁老牛再出发1 小时前
07.08.&07.09.每日总结
c语言·python
齐 飞2 小时前
Python常用语法总结
python
齐 飞2 小时前
LangGraph快速入门-03节点与边
python·langchain
Helen_cai2 小时前
OpenHarmony http 网络请求封装与全局拦截实战(API Version23 + 适配版)
网络·网络协议·http·华为·harmonyos
_Jimmy_2 小时前
Python 多线程使用和场景
python
梦想的初衷~2 小时前
【完整教程】基于Python的无人机多光谱-点云融合生态三维建模:从Metashape重建到碳储量/生物量/LULC预测
python·无人机·三维重建·多光谱·无人机遥感·碳储量·生态建模