File size: 8,651 Bytes
b6ae7b8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | #!/usr/bin/env python3
"""
Benchmarks for Stack 2.9 - Memory Usage Tests
Memory profiling benchmarks.
"""
import pytest
import sys
import gc
from pathlib import Path
from unittest.mock import MagicMock, patch
# Add stack_cli to path
sys.path.insert(0, str(Path(__file__).parent.parent / "stack_cli"))
from stack_cli.agent import StackAgent, create_agent
class TestMemoryUsage:
"""Test memory usage patterns."""
def test_agent_memory_baseline(self):
"""Test baseline agent memory usage."""
with patch('stack_cli.context.create_context_manager'):
agent = StackAgent()
# Should not use excessive memory
import sys
agent_size = sys.getsizeof(agent)
# Baseline should be reasonable
assert agent_size < 10000
def test_conversation_history_memory(self):
"""Test conversation history memory usage."""
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.tools.get_tool') as mock_get_tool:
mock_tool = MagicMock(return_value={"success": True})
mock_get_tool.return_value = mock_tool
agent = StackAgent()
# Add many conversations
for i in range(100):
agent.process(f"query {i}")
# History should be accessible
assert len(agent.conversation_history) <= 200 # May truncate
def test_session_memory_growth(self):
"""Test session memory growth."""
with patch('stack_cli.context.create_context_manager'):
agent = StackAgent()
session = agent.context_manager.session
# Add many operations
for i in range(100):
session.add_message("user", f"message {i}" * 10)
session.add_tool_usage("read", {"success": True})
summary = session.get_summary()
# Summary should be generated correctly
assert summary["messages_count"] == 100
assert summary["tools_used_count"] == 100
class TestContextMemory:
"""Test context memory usage."""
def test_context_manager_memory(self):
"""Test context manager memory footprint."""
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.context.Path') as mock_path:
with patch.object(Path, 'exists', return_value=False):
from stack_cli.context import ContextManager
cm = ContextManager("/tmp/test")
import sys
cm_size = sys.getsizeof(cm)
# Should be reasonable
assert cm_size < 5000
def test_projects_dict_memory(self):
"""Test projects dictionary memory."""
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.context.Path') as mock_path:
with patch.object(Path, 'exists', return_value=False):
from stack_cli.context import ContextManager
cm = ContextManager("/tmp")
# Should have empty projects dict initially
assert len(cm.projects) == 0
class TestToolMemory:
"""Test tool-related memory usage."""
def test_tools_dict_memory(self):
"""Test TOOLS dictionary size."""
from stack_cli.tools import TOOLS
import sys
tools_size = sys.getsizeof(TOOLS)
# Should be reasonable for dict
assert tools_size < 10000
def test_tool_schemas_memory(self):
"""Test tool schemas memory."""
from stack_cli.tools import get_tool_schemas
schemas = get_tool_schemas()
import sys
schemas_size = sys.getsizeof(schemas)
# Should be reasonable
assert schemas_size < 10000
class TestGarbageCollection:
"""Test garbage collection."""
def test_gc_after_agent_creation(self):
"""Test GC after agent creation."""
gc.collect()
with patch('stack_cli.context.create_context_manager'):
agent = StackAgent()
# Force gc
gc.collect()
# Agent should still work
assert agent is not None
def test_gc_after_queries(self):
"""Test GC after many queries."""
gc.collect()
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.tools.get_tool') as mock_get_tool:
mock_tool = MagicMock(return_value={"success": True})
mock_get_tool.return_value = mock_tool
agent = StackAgent()
for i in range(50):
agent.process(f"query {i}")
gc.collect()
# Should still work
assert len(agent.conversation_history) > 0
class TestMemoryLeaks:
"""Test for potential memory leaks."""
def test_no_leak_in_loop(self):
"""Test no memory leak in processing loop."""
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.tools.get_tool') as mock_get_tool:
mock_tool = MagicMock(return_value={"success": True})
mock_get_tool.return_value = mock_tool
agent = StackAgent()
initial_history_len = len(agent.conversation_history)
# Process many queries
for i in range(200):
agent.process(f"query {i}")
final_history_len = len(agent.conversation_history)
# Should not grow indefinitely (may truncate)
assert final_history_len <= initial_history_len + 200
def test_session_cleanup(self):
"""Test session cleanup."""
with patch('stack_cli.context.create_context_manager'):
agent = StackAgent()
session = agent.context_manager.session
# Add data
for i in range(20):
session.add_message("user", f"msg {i}")
# Clear should work
session.messages.clear()
assert len(session.messages) == 0
class TestMemoryEfficiency:
"""Test memory efficiency."""
def test_response_size(self):
"""Test response object size."""
with patch('stack_cli.context.create_context_manager'):
from stack_cli.agent import AgentResponse
import sys
response = AgentResponse(
content="test content",
tool_calls=[],
confidence=0.9
)
size = sys.getsizeof(response)
# Should be reasonable
assert size < 1000
def test_tool_call_size(self):
"""Test tool call object size."""
from stack_cli.agent import ToolCall
import sys
call = ToolCall(
tool_name="read",
arguments={"path": "test.py"},
result={"success": True}
)
size = sys.getsizeof(call)
# Should be small
assert size < 500
class TestResourceCleanup:
"""Test resource cleanup."""
def test_context_cleanup(self):
"""Test context cleanup."""
with patch('stack_cli.context.create_context_manager'):
with patch('stack_cli.context.Path') as mock_path:
with patch.object(Path, 'exists', return_value=False):
from stack_cli.context import ContextManager
cm = ContextManager("/tmp")
# Should have cleanup method or be disposable
assert cm is not None
def test_agent_disposal(self):
"""Test agent can be disposed."""
with patch('stack_cli.context.create_context_manager'):
agent = StackAgent()
# Should be able to reference agent
assert agent is not None
# Should be able to create new one
agent2 = StackAgent()
assert agent2 is not None
if __name__ == "__main__":
pytest.main([__file__, "-v"])
|