mirror of
https://github.com/Horizontal42/netsleuth.git
synced 2026-11-10 21:32:04 +03:00
Merge 7f2ab2605d into 8c99ac78b7
This commit is contained in:
commit
c8c3b48361
3 changed files with 44 additions and 31 deletions
|
|
@ -516,6 +516,7 @@ async def _speed_section(client, settings: Settings, options: Options, idle_rtt_
|
|||
import shutil
|
||||
|
||||
from netsleuth.speed import (
|
||||
BufferbloatMeasureConfig,
|
||||
measure_with_bufferbloat,
|
||||
run_speed_cascade,
|
||||
tier_cloudflare,
|
||||
|
|
@ -559,12 +560,14 @@ async def _speed_section(client, settings: Settings, options: Options, idle_rtt_
|
|||
|
||||
result = await measure_with_bufferbloat(
|
||||
result,
|
||||
idle_rtt_ms=idle_rtt_ms if result.idle_rtt_ms is None else result.idle_rtt_ms,
|
||||
bands=settings.thresholds.bufferbloat_ms,
|
||||
run_download=_saturate_down,
|
||||
run_upload=_saturate_up,
|
||||
probe=_probe,
|
||||
interval=cfg.bufferbloat_probe_interval_seconds,
|
||||
config=BufferbloatMeasureConfig(
|
||||
idle_rtt_ms=idle_rtt_ms if result.idle_rtt_ms is None else result.idle_rtt_ms,
|
||||
bands=settings.thresholds.bufferbloat_ms,
|
||||
run_download=_saturate_down,
|
||||
run_upload=_saturate_up,
|
||||
probe=_probe,
|
||||
interval=cfg.bufferbloat_probe_interval_seconds,
|
||||
),
|
||||
)
|
||||
return ModuleResult(name="speed", status="ok", data=result)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ def bufferbloat_delta(idle_rtt_ms: float | None, loaded_rtts_ms: list[float]) ->
|
|||
import asyncio
|
||||
import time
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from netsleuth.models import SpeedResult, TierAttempt
|
||||
|
||||
|
|
@ -241,6 +242,16 @@ from netsleuth.interpret import grade_bufferbloat
|
|||
from netsleuth.stats import rtt_stats
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BufferbloatMeasureConfig:
|
||||
idle_rtt_ms: float | None
|
||||
bands: BufferbloatBands
|
||||
run_download: Callable[[], Awaitable[None]]
|
||||
run_upload: Callable[[], Awaitable[None]]
|
||||
probe: Callable[[], Awaitable[float | None]]
|
||||
interval: float
|
||||
|
||||
|
||||
async def probe_while(
|
||||
coro: Awaitable[None],
|
||||
probe: Callable[[], Awaitable[float | None]],
|
||||
|
|
@ -259,25 +270,20 @@ async def probe_while(
|
|||
|
||||
async def measure_with_bufferbloat(
|
||||
result: SpeedResult,
|
||||
idle_rtt_ms: float | None,
|
||||
bands: BufferbloatBands,
|
||||
run_download: Callable[[], Awaitable[None]],
|
||||
run_upload: Callable[[], Awaitable[None]],
|
||||
probe: Callable[[], Awaitable[float | None]],
|
||||
interval: float,
|
||||
config: BufferbloatMeasureConfig,
|
||||
) -> SpeedResult:
|
||||
# This is the one place a measurement is allowed to overlap another: the
|
||||
# whole point is to see what latency does while the link is saturated.
|
||||
down_samples = await probe_while(run_download(), probe, interval)
|
||||
up_samples = await probe_while(run_upload(), probe, interval)
|
||||
result.idle_rtt_ms = idle_rtt_ms
|
||||
down_samples = await probe_while(config.run_download(), config.probe, config.interval)
|
||||
up_samples = await probe_while(config.run_upload(), config.probe, config.interval)
|
||||
result.idle_rtt_ms = config.idle_rtt_ms
|
||||
result.loaded_rtt_down_ms = rtt_stats(list(down_samples)).avg_ms
|
||||
result.loaded_rtt_up_ms = rtt_stats(list(up_samples)).avg_ms
|
||||
result.bufferbloat_down_ms = bufferbloat_delta(idle_rtt_ms, down_samples)
|
||||
result.bufferbloat_up_ms = bufferbloat_delta(idle_rtt_ms, up_samples)
|
||||
result.bufferbloat_down_ms = bufferbloat_delta(config.idle_rtt_ms, down_samples)
|
||||
result.bufferbloat_up_ms = bufferbloat_delta(config.idle_rtt_ms, up_samples)
|
||||
worst_delta = max(
|
||||
[d for d in (result.bufferbloat_down_ms, result.bufferbloat_up_ms) if d is not None],
|
||||
default=None,
|
||||
)
|
||||
result.bufferbloat_grade = grade_bufferbloat(worst_delta, bands)
|
||||
result.bufferbloat_grade = grade_bufferbloat(worst_delta, config.bands)
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from netsleuth.models import SpeedResult
|
|||
from netsleuth.speed import NDT7_CONSENT_NOTICE, run_speed_cascade
|
||||
from netsleuth.speed import tier_ookla
|
||||
from netsleuth.config import BufferbloatBands
|
||||
from netsleuth.speed import measure_with_bufferbloat, probe_while
|
||||
from netsleuth.speed import BufferbloatMeasureConfig, measure_with_bufferbloat, probe_while
|
||||
import httpx
|
||||
from pytest_httpx import HTTPXMock
|
||||
from netsleuth.config import Speedtest
|
||||
|
|
@ -371,12 +371,14 @@ async def test_measure_with_bufferbloat_fills_in_both_directions_and_the_grade()
|
|||
|
||||
result = await measure_with_bufferbloat(
|
||||
SpeedResult(method="cloudflare", download_mbps=300.0, upload_mbps=40.0),
|
||||
idle_rtt_ms=12.0,
|
||||
bands=BufferbloatBands(),
|
||||
run_download=run_download,
|
||||
run_upload=run_upload,
|
||||
probe=probe,
|
||||
interval=0.05,
|
||||
config=BufferbloatMeasureConfig(
|
||||
idle_rtt_ms=12.0,
|
||||
bands=BufferbloatBands(),
|
||||
run_download=run_download,
|
||||
run_upload=run_upload,
|
||||
probe=probe,
|
||||
interval=0.05,
|
||||
),
|
||||
)
|
||||
assert result.idle_rtt_ms == 12.0
|
||||
assert result.loaded_rtt_down_ms is not None
|
||||
|
|
@ -396,12 +398,14 @@ async def test_measure_with_bufferbloat_without_an_idle_baseline_grades_unknown(
|
|||
|
||||
result = await measure_with_bufferbloat(
|
||||
SpeedResult(method="cloudflare", download_mbps=300.0),
|
||||
idle_rtt_ms=None,
|
||||
bands=BufferbloatBands(),
|
||||
run_download=work,
|
||||
run_upload=work,
|
||||
probe=probe,
|
||||
interval=0.02,
|
||||
config=BufferbloatMeasureConfig(
|
||||
idle_rtt_ms=None,
|
||||
bands=BufferbloatBands(),
|
||||
run_download=work,
|
||||
run_upload=work,
|
||||
probe=probe,
|
||||
interval=0.02,
|
||||
),
|
||||
)
|
||||
assert result.bufferbloat_down_ms is None
|
||||
assert result.bufferbloat_grade == "?"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue