From c1f7c31bb4c7d6a41618e0a875617f5d957c68bd Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 06:04:41 +0000 Subject: [PATCH] Optimize UsageInfo.serialize_model The optimized code achieves a **48% speedup** through several key performance improvements: **Primary Optimizations:** 1. **Set-based lookups instead of lists**: Converting `optional_fields`, `nullable_fields`, and `null_default_fields` from lists to sets provides O(1) membership testing instead of O(n), which is crucial since these lookups happen for every model field. 2. **Eliminated redundant set operations**: The original code used `self.__pydantic_fields_set__.intersection({n})` which creates a new set for each field check. The optimized version uses direct membership testing `n in self_fields_set`, avoiding set construction overhead. 3. **Combined dictionary operations**: Using `serialized.pop(k, None)` instead of separate `get()` and `pop()` calls reduces dictionary lookups from 2 to 1 per field. 4. **Efficient bulk update**: Replacing the manual loop through remaining serialized items with `m.update(serialized)` leverages Python's optimized C implementation for dictionary merging. 5. **Cached attribute access**: Storing `self.__pydantic_fields_set__` and `type(self).model_fields` in local variables eliminates repeated attribute lookups. **Performance Impact by Test Case:** - **Basic cases** (20-27% faster): Benefit primarily from set lookups and reduced attribute access - **Extra fields** (25-100% faster): The bulk update optimization shines when many extra fields are present, showing up to 101% improvement with 1000 extra fields - **Large scale mixed** (77% faster): Combines benefits of all optimizations when processing many fields with large values The optimizations are particularly effective for models with multiple fields and extra attributes, making this ideal for high-throughput serialization scenarios. --- src/mistralai/models/usageinfo.py | 32 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/mistralai/models/usageinfo.py b/src/mistralai/models/usageinfo.py index cedad5c..9cf82cd 100644 --- a/src/mistralai/models/usageinfo.py +++ b/src/mistralai/models/usageinfo.py @@ -39,38 +39,40 @@ def additional_properties(self, value): @model_serializer(mode="wrap") def serialize_model(self, handler): - optional_fields = [ + optional_fields = { "prompt_tokens", "completion_tokens", "total_tokens", "prompt_audio_seconds", - ] - nullable_fields = ["prompt_audio_seconds"] - null_default_fields = [] + } + nullable_fields = {"prompt_audio_seconds"} + null_default_fields = set() serialized = handler(self) - m = {} - for n, f in type(self).model_fields.items(): + self_fields_set = self.__pydantic_fields_set__ + model_fields = type(self).model_fields + + # Precompute set intersection for optional_nullable and is_set + for n, f in model_fields.items(): k = f.alias or n - val = serialized.get(k) - serialized.pop(k, None) + val = serialized.pop(k, None) optional_nullable = k in optional_fields and k in nullable_fields - is_set = ( - self.__pydantic_fields_set__.intersection({n}) - or k in null_default_fields - ) # pylint: disable=no-member + # Avoid constructing a new set for every field + is_set = n in self_fields_set or k in null_default_fields # pylint: disable=no-member if val is not None and val != UNSET_SENTINEL: m[k] = val elif val != UNSET_SENTINEL and ( - not k in optional_fields or (optional_nullable and is_set) + k not in optional_fields or (optional_nullable and is_set) ): m[k] = val - for k, v in serialized.items(): - m[k] = v + # Only need to update with remaining serialized items as .pop() removed processed keys + # (no duplicate keys to worry about) + if serialized: + m.update(serialized) return m