Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2025-04-01 - Fast Serialization for Metrics
**Learning:** `dataclasses.asdict()` relies on recursive deep cloning internally, making it extremely slow for high-frequency operations like serializing metrics per request/token. Shallow iterating over `__dataclass_fields__` directly avoids this overhead.
**Action:** Replace `asdict()` with a custom field iteration method (falling back appropriately) in hot paths like metrics classes (`RequestMetrics`, `SpeculateMetrics`).
19 changes: 18 additions & 1 deletion fastdeploy/engine/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from __future__ import annotations

import dataclasses
import json
import time
import traceback
Expand Down Expand Up @@ -897,7 +898,23 @@ def to_dict(self):
"""
Convert the RequestMetrics object to a dictionary.
"""
return {k: v for k, v in asdict(self).items()}
res = {}
for k in self.__dataclass_fields__:
v = getattr(self, k)
if type(v) in (int, float, str, bool, type(None)):
res[k] = v
elif isinstance(v, list):
res[k] = list(v)
elif isinstance(v, dict):
res[k] = dict(v)
elif dataclasses.is_dataclass(v):
if hasattr(v, "to_dict"):
res[k] = v.to_dict()
else:
res[k] = asdict(v)
else:
Comment on lines +901 to +915
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RequestMetrics.to_dict 与 SpeculateMetrics.to_dict 里包含几乎相同的字段遍历/浅拷贝逻辑,后续若需要支持更多类型(例如 list/dict 内嵌 dataclass 的递归转换)时容易出现两处实现不一致。建议抽取一个共享的序列化 helper(例如放在 utils/metrics 里)并在两处复用,以降低维护成本。

Copilot uses AI. Check for mistakes.
res[k] = v
return res

def record_recv_first_token(self):
cur_time = time.time()
Expand Down
23 changes: 23 additions & 0 deletions fastdeploy/worker/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# limitations under the License.
"""

import dataclasses
from dataclasses import dataclass, field
from typing import NamedTuple, Optional

Expand Down Expand Up @@ -164,6 +165,28 @@ class SpeculateMetrics:
"""
accept_ratio_per_head: list[float]

def to_dict(self):
"""
Convert the SpeculateMetrics object to a dictionary.
"""
res = {}
for k in self.__dataclass_fields__:
v = getattr(self, k)
if type(v) in (int, float, str, bool, type(None)):
res[k] = v
elif isinstance(v, list):
res[k] = list(v)
elif isinstance(v, dict):
res[k] = dict(v)
elif dataclasses.is_dataclass(v):
if hasattr(v, "to_dict"):
res[k] = v.to_dict()
else:
res[k] = dataclasses.asdict(v)
else:
Comment on lines +168 to +186
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的 to_dict 与 fastdeploy/engine/request.py 中 RequestMetrics.to_dict 逻辑重复,建议抽取共享的序列化 helper 复用,避免未来扩展类型支持时两处实现产生行为差异。

Copilot uses AI. Check for mistakes.
res[k] = v
return res


@dataclass
class SamplerOutput:
Expand Down
Loading