Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 12, 2025

📄 827% (8.27x) speedup for _AppConfig.asdict in marimo/_ast/app_config.py

⏱️ Runtime : 5.81 milliseconds 627 microseconds (best of 250 runs)

📝 Explanation and details

The optimization replaces the expensive asdict(self) call with direct attribute access through getattr(self, k) while iterating over self.__dataclass_fields__.

Key Performance Changes:

  • Eliminates intermediate dictionary creation: The original code calls dataclasses.asdict(self) which creates a complete dictionary of all fields, then filters it. The optimized version directly accesses only the needed attributes.
  • Reduces memory allocations: Instead of creating a full dictionary and then filtering it, the optimized code builds only the final result dictionary.
  • Avoids unnecessary field processing: dataclasses.asdict() performs additional work like handling nested dataclasses and type conversions that aren't needed here.

Why This Works:
The line profiler shows the optimization dramatically reduces time spent in the dictionary comprehension (from 89.6% to 3.6% of total time). The asdict(self).items() call in the original code is expensive because it processes all dataclass fields, even those that will be filtered out.

Test Results Impact:
The annotated tests show consistent 5-6x speedups across all scenarios:

  • Simple default configs: ~500-600% faster
  • Configs with private fields: ~550% faster
  • Configs with many private fields: ~500% faster

This optimization is particularly effective for dataclasses with many fields or when called frequently, as it eliminates the overhead of the full dataclass serialization process while maintaining identical functionality.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 26 Passed
🌀 Generated Regression Tests 12 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
⚙️ Existing Unit Tests and Runtime
Test File::Test Function Original ⏱️ Optimized ⏱️ Speedup
_ast/test_app.py::TestApp.test_app_config_auto_download 8.54μs 2.13μs 300%✅
_ast/test_app.py::TestApp.test_app_config_extra_args_ignored 16.2μs 3.16μs 414%✅
_ast/test_app.py::test_app_config 13.9μs 2.27μs 512%✅
_ast/test_app.py::test_app_config_extra_args_ignored 14.9μs 2.49μs 499%✅
_ast/test_app_config.py::test_app_config_asdict 15.5μs 2.30μs 571%✅
🌀 Generated Regression Tests and Runtime

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

imports

import pytest
from marimo._ast.app_config import _AppConfig

---- Mocking dependencies for a self-contained test ----

These are minimal mocks to allow the test to run without external dependencies.

Simulate valid types for the config fields

WidthType = str # could be "compact", "full", etc.
ExportType = str # could be "html", "md", etc.
SqlOutputType = str # could be "auto", "table", etc.
from marimo._ast.app_config import _AppConfig

-------------------- UNIT TESTS --------------------

1. Basic Test Cases

def test_default_config_asdict():
"""Test asdict() on default configuration."""
cfg = _AppConfig()
codeflash_output = cfg.asdict(); d = codeflash_output # 13.6μs -> 2.23μs (509% faster)

def test_auto_download_empty_and_nonempty():
"""Test asdict() with empty and non-empty auto_download lists."""
# Empty list (default)
cfg = _AppConfig()
codeflash_output = cfg.asdict(); d = codeflash_output # 13.3μs -> 2.15μs (519% faster)
# Non-empty list
cfg2 = _AppConfig(auto_download=["md"])
codeflash_output = cfg2.asdict(); d2 = codeflash_output # 8.88μs -> 1.22μs (626% faster)

def test_asdict_return_type_and_keys():
"""Test that asdict returns a dict with correct keys and types."""
cfg = _AppConfig()
codeflash_output = cfg.asdict(); d = codeflash_output # 16.3μs -> 2.56μs (535% faster)
expected_keys = [
"width", "app_title", "layout_file", "css_file", "html_head_file", "auto_download", "sql_output"
]

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

#------------------------------------------------
from dataclasses import asdict, dataclass, field
from typing import Any, Optional

imports

import pytest
from marimo._ast.app_config import _AppConfig

Dummy enum types to simulate the real ones for testing

class ExportType(str):
HTML = "html"
MARKDOWN = "markdown"
PDF = "pdf"

class SqlOutputType(str):
AUTO = "auto"
TABLE = "table"
RAW = "raw"

class WidthType(str):
COMPACT = "compact"
FULL = "full"
CUSTOM = "custom"
from marimo._ast.app_config import _AppConfig

unit tests

----------- Basic Test Cases -----------

def test_asdict_default_values():
"""Test asdict with all default values."""
cfg = _AppConfig()
codeflash_output = cfg.asdict(); d = codeflash_output # 14.5μs -> 2.37μs (511% faster)

def test_asdict_ignores_private_fields():
"""Test that asdict does not include private fields (starting with '_')."""
# Dynamically add a private field to the instance
cfg = _AppConfig()
cfg._experimental = 123
# asdict() should not include '_experimental'
codeflash_output = cfg.asdict(); d = codeflash_output # 12.7μs -> 1.93μs (557% faster)

def test_asdict_large_number_of_fields_with_private():
"""Test asdict ignores many private fields even if present."""
cfg = _AppConfig()
# Add many private fields
for i in range(100):
setattr(cfg, f"_private{i}", i)
codeflash_output = cfg.asdict(); d = codeflash_output # 14.3μs -> 2.39μs (497% faster)
# None of the private fields should be present
for i in range(100):
pass

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-_AppConfig.asdict-mhvkqyeo and push.

Codeflash Static Badge

The optimization replaces the expensive `asdict(self)` call with direct attribute access through `getattr(self, k)` while iterating over `self.__dataclass_fields__`.

**Key Performance Changes:**
- **Eliminates intermediate dictionary creation**: The original code calls `dataclasses.asdict(self)` which creates a complete dictionary of all fields, then filters it. The optimized version directly accesses only the needed attributes.
- **Reduces memory allocations**: Instead of creating a full dictionary and then filtering it, the optimized code builds only the final result dictionary.
- **Avoids unnecessary field processing**: `dataclasses.asdict()` performs additional work like handling nested dataclasses and type conversions that aren't needed here.

**Why This Works:**
The line profiler shows the optimization dramatically reduces time spent in the dictionary comprehension (from 89.6% to 3.6% of total time). The `asdict(self).items()` call in the original code is expensive because it processes all dataclass fields, even those that will be filtered out.

**Test Results Impact:**
The annotated tests show consistent 5-6x speedups across all scenarios:
- Simple default configs: ~500-600% faster
- Configs with private fields: ~550% faster  
- Configs with many private fields: ~500% faster

This optimization is particularly effective for dataclasses with many fields or when called frequently, as it eliminates the overhead of the full dataclass serialization process while maintaining identical functionality.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 12, 2025 05:43
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant