♻️ refactor: restructure Observer as base class with InferenceObserver
- Refactor Observer into base class with common enable/disable/reset interface - Create InferenceObserver subclass for TTFT/TPOT metrics - Fix TTFT calculation timing: compute after prefill completes instead of at decode start (fixes max_tokens=1 returning TTFT=0) - Integrate InferenceObserver into bench.py and bench_offload.py for accurate internal timing metrics vs external wall-clock time - Add get_summary() and print_summary() methods for structured output Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -10,7 +10,7 @@ from nanovllm.sampling_params import SamplingParams
|
||||
from nanovllm.engine.sequence import Sequence
|
||||
from nanovllm.engine.scheduler import Scheduler
|
||||
from nanovllm.engine.model_runner import ModelRunner
|
||||
from nanovllm.utils.observer import Observer
|
||||
from nanovllm.utils.observer import InferenceObserver
|
||||
|
||||
|
||||
class LLMEngine:
|
||||
@@ -58,15 +58,18 @@ class LLMEngine:
|
||||
print(f"[DEBUG LLMEngine.step] Mode={mode}, active_sequences={len(seqs)}")
|
||||
|
||||
if not is_prefill:
|
||||
# The end of the prefill mode. Get TTFT.
|
||||
if Observer.ttft_start != 0:
|
||||
Observer.ttft = perf_counter_ns() - Observer.ttft_start
|
||||
Observer.reset_ttft()
|
||||
# The start of the decode mode. Get TPOT.
|
||||
if Observer.tpot_start != 0:
|
||||
Observer.tpot = perf_counter_ns() - Observer.tpot_start
|
||||
Observer.tpot_start = perf_counter_ns()
|
||||
# Decode mode: calculate TPOT from previous decode step
|
||||
if InferenceObserver.tpot_start != 0:
|
||||
InferenceObserver.tpot = perf_counter_ns() - InferenceObserver.tpot_start
|
||||
InferenceObserver.tpot_start = perf_counter_ns()
|
||||
|
||||
token_ids = self.model_runner.call("run", seqs, is_prefill)
|
||||
|
||||
if is_prefill:
|
||||
# Calculate TTFT after prefill completes (including chunked prefill)
|
||||
if InferenceObserver.ttft_start != 0:
|
||||
InferenceObserver.ttft = perf_counter_ns() - InferenceObserver.ttft_start
|
||||
InferenceObserver.reset_ttft()
|
||||
self.scheduler.postprocess(seqs, token_ids)
|
||||
outputs = [(seq.seq_id, seq.completion_token_ids) for seq in seqs if seq.is_finished]
|
||||
|
||||
@@ -91,7 +94,7 @@ class LLMEngine:
|
||||
log_level = os.environ.get('NANOVLLM_LOG_LEVEL', 'INFO')
|
||||
debug_enabled = log_level.upper() == 'DEBUG'
|
||||
|
||||
Observer.complete_reset()
|
||||
InferenceObserver.complete_reset()
|
||||
if use_tqdm:
|
||||
pbar = tqdm(total=len(prompts), desc="Generating", dynamic_ncols=True)
|
||||
if not isinstance(sampling_params, list):
|
||||
@@ -128,8 +131,8 @@ class LLMEngine:
|
||||
pbar.set_postfix({
|
||||
"Prefill": f"{int(prefill_throughput)}tok/s",
|
||||
"Decode": f"{int(decode_throughput)}tok/s",
|
||||
"ttft": f"{float(Observer.ttft) / 1e6}ms",
|
||||
"tpot": f"{float(Observer.tpot) / 1e6}ms",
|
||||
"ttft": f"{float(InferenceObserver.ttft) / 1e6}ms",
|
||||
"tpot": f"{float(InferenceObserver.tpot) / 1e6}ms",
|
||||
})
|
||||
for seq_id, token_ids in output:
|
||||
outputs[seq_id] = token_ids
|
||||
|
||||
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from nanovllm.config import Config
|
||||
from nanovllm.engine.sequence import Sequence, SequenceStatus
|
||||
from nanovllm.utils.observer import Observer
|
||||
from nanovllm.utils.observer import InferenceObserver
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from nanovllm.kvcache import KVCacheManager
|
||||
@@ -32,8 +32,8 @@ class Scheduler:
|
||||
num_seqs = 0
|
||||
num_batched_tokens = 0
|
||||
while self.waiting and num_seqs < self.max_num_seqs:
|
||||
if Observer.ttft_start == 0:
|
||||
Observer.ttft_start = perf_counter_ns()
|
||||
if InferenceObserver.ttft_start == 0:
|
||||
InferenceObserver.ttft_start = perf_counter_ns()
|
||||
seq = self.waiting[0]
|
||||
|
||||
# Check if sequence is too large
|
||||
|
||||
Reference in New Issue
Block a user