aigroup-econ-mcp 0.4.2__py3-none-any.whl → 1.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- .gitignore +253 -0
- PKG-INFO +710 -0
- README.md +672 -0
- __init__.py +14 -0
- aigroup_econ_mcp-1.4.3.dist-info/METADATA +710 -0
- aigroup_econ_mcp-1.4.3.dist-info/RECORD +92 -0
- aigroup_econ_mcp-1.4.3.dist-info/entry_points.txt +2 -0
- aigroup_econ_mcp-1.4.3.dist-info/licenses/LICENSE +21 -0
- cli.py +28 -0
- econometrics/README.md +18 -0
- econometrics/__init__.py +191 -0
- econometrics/advanced_methods/modern_computing_machine_learning/__init__.py +0 -0
- econometrics/basic_parametric_estimation/__init__.py +31 -0
- econometrics/basic_parametric_estimation/gmm/__init__.py +13 -0
- econometrics/basic_parametric_estimation/gmm/gmm_model.py +256 -0
- econometrics/basic_parametric_estimation/mle/__init__.py +13 -0
- econometrics/basic_parametric_estimation/mle/mle_model.py +241 -0
- econometrics/basic_parametric_estimation/ols/__init__.py +13 -0
- econometrics/basic_parametric_estimation/ols/ols_model.py +141 -0
- econometrics/causal_inference/causal_identification_strategy/__init__.py +0 -0
- econometrics/missing_data/missing_data_measurement_error/__init__.py +0 -0
- econometrics/model_specification_diagnostics_robust_inference/README.md +173 -0
- econometrics/model_specification_diagnostics_robust_inference/__init__.py +78 -0
- econometrics/model_specification_diagnostics_robust_inference/diagnostic_tests/__init__.py +20 -0
- econometrics/model_specification_diagnostics_robust_inference/diagnostic_tests/diagnostic_tests_model.py +149 -0
- econometrics/model_specification_diagnostics_robust_inference/generalized_least_squares/__init__.py +15 -0
- econometrics/model_specification_diagnostics_robust_inference/generalized_least_squares/gls_model.py +130 -0
- econometrics/model_specification_diagnostics_robust_inference/model_selection/__init__.py +18 -0
- econometrics/model_specification_diagnostics_robust_inference/model_selection/model_selection_model.py +286 -0
- econometrics/model_specification_diagnostics_robust_inference/regularization/__init__.py +15 -0
- econometrics/model_specification_diagnostics_robust_inference/regularization/regularization_model.py +177 -0
- econometrics/model_specification_diagnostics_robust_inference/robust_errors/__init__.py +15 -0
- econometrics/model_specification_diagnostics_robust_inference/robust_errors/robust_errors_model.py +122 -0
- econometrics/model_specification_diagnostics_robust_inference/simultaneous_equations/__init__.py +15 -0
- econometrics/model_specification_diagnostics_robust_inference/simultaneous_equations/simultaneous_equations_model.py +246 -0
- econometrics/model_specification_diagnostics_robust_inference/weighted_least_squares/__init__.py +15 -0
- econometrics/model_specification_diagnostics_robust_inference/weighted_least_squares/wls_model.py +127 -0
- econometrics/nonparametric/nonparametric_semiparametric_methods/__init__.py +0 -0
- econometrics/spatial_econometrics/spatial_econometrics_new/__init__.py +0 -0
- econometrics/specific_data_modeling/micro_discrete_limited_data/__init__.py +0 -0
- econometrics/specific_data_modeling/survival_duration_data/__init__.py +0 -0
- econometrics/specific_data_modeling/time_series_panel_data/__init__.py +143 -0
- econometrics/specific_data_modeling/time_series_panel_data/arima_model.py +104 -0
- econometrics/specific_data_modeling/time_series_panel_data/cointegration_vecm.py +334 -0
- econometrics/specific_data_modeling/time_series_panel_data/dynamic_panel_models.py +653 -0
- econometrics/specific_data_modeling/time_series_panel_data/exponential_smoothing.py +176 -0
- econometrics/specific_data_modeling/time_series_panel_data/garch_model.py +198 -0
- econometrics/specific_data_modeling/time_series_panel_data/panel_diagnostics.py +125 -0
- econometrics/specific_data_modeling/time_series_panel_data/panel_var.py +60 -0
- econometrics/specific_data_modeling/time_series_panel_data/structural_break_tests.py +87 -0
- econometrics/specific_data_modeling/time_series_panel_data/time_varying_parameter_models.py +106 -0
- econometrics/specific_data_modeling/time_series_panel_data/unit_root_tests.py +204 -0
- econometrics/specific_data_modeling/time_series_panel_data/var_svar_model.py +372 -0
- econometrics/statistical_inference/statistical_inference_techniques/__init__.py +0 -0
- econometrics/statistics/distribution_decomposition_methods/__init__.py +0 -0
- econometrics/tests/basic_parametric_estimation_tests/__init__.py +3 -0
- econometrics/tests/basic_parametric_estimation_tests/test_gmm.py +128 -0
- econometrics/tests/basic_parametric_estimation_tests/test_mle.py +127 -0
- econometrics/tests/basic_parametric_estimation_tests/test_ols.py +100 -0
- econometrics/tests/model_specification_diagnostics_tests/__init__.py +3 -0
- econometrics/tests/model_specification_diagnostics_tests/test_diagnostic_tests.py +86 -0
- econometrics/tests/model_specification_diagnostics_tests/test_robust_errors.py +89 -0
- econometrics/tests/specific_data_modeling_tests/__init__.py +3 -0
- econometrics/tests/specific_data_modeling_tests/test_arima.py +98 -0
- econometrics/tests/specific_data_modeling_tests/test_dynamic_panel.py +198 -0
- econometrics/tests/specific_data_modeling_tests/test_exponential_smoothing.py +105 -0
- econometrics/tests/specific_data_modeling_tests/test_garch.py +118 -0
- econometrics/tests/specific_data_modeling_tests/test_unit_root.py +156 -0
- econometrics/tests/specific_data_modeling_tests/test_var.py +124 -0
- prompts/__init__.py +0 -0
- prompts/analysis_guides.py +43 -0
- pyproject.toml +78 -0
- resources/MCP_MASTER_GUIDE.md +422 -0
- resources/MCP_TOOLS_DATA_FORMAT_GUIDE.md +185 -0
- resources/__init__.py +0 -0
- server.py +83 -0
- tools/README.md +88 -0
- tools/__init__.py +45 -0
- tools/data_loader.py +213 -0
- tools/decorators.py +38 -0
- tools/econometrics_adapter.py +286 -0
- tools/mcp_tool_groups/__init__.py +1 -0
- tools/mcp_tool_groups/basic_parametric_tools.py +173 -0
- tools/mcp_tool_groups/model_specification_tools.py +402 -0
- tools/mcp_tool_groups/time_series_tools.py +494 -0
- tools/mcp_tools_registry.py +114 -0
- tools/model_specification_adapter.py +369 -0
- tools/output_formatter.py +563 -0
- tools/time_series_panel_data_adapter.py +858 -0
- tools/time_series_panel_data_tools.py +65 -0
- aigroup_econ_mcp/__init__.py +0 -19
- aigroup_econ_mcp/cli.py +0 -82
- aigroup_econ_mcp/config.py +0 -561
- aigroup_econ_mcp/server.py +0 -452
- aigroup_econ_mcp/tools/__init__.py +0 -18
- aigroup_econ_mcp/tools/base.py +0 -470
- aigroup_econ_mcp/tools/cache.py +0 -533
- aigroup_econ_mcp/tools/data_loader.py +0 -171
- aigroup_econ_mcp/tools/file_parser.py +0 -829
- aigroup_econ_mcp/tools/machine_learning.py +0 -60
- aigroup_econ_mcp/tools/ml_ensemble.py +0 -210
- aigroup_econ_mcp/tools/ml_evaluation.py +0 -272
- aigroup_econ_mcp/tools/ml_models.py +0 -54
- aigroup_econ_mcp/tools/ml_regularization.py +0 -172
- aigroup_econ_mcp/tools/monitoring.py +0 -555
- aigroup_econ_mcp/tools/optimized_example.py +0 -229
- aigroup_econ_mcp/tools/panel_data.py +0 -553
- aigroup_econ_mcp/tools/regression.py +0 -214
- aigroup_econ_mcp/tools/statistics.py +0 -154
- aigroup_econ_mcp/tools/time_series.py +0 -667
- aigroup_econ_mcp/tools/timeout.py +0 -283
- aigroup_econ_mcp/tools/tool_handlers.py +0 -378
- aigroup_econ_mcp/tools/tool_registry.py +0 -170
- aigroup_econ_mcp/tools/validation.py +0 -482
- aigroup_econ_mcp-0.4.2.dist-info/METADATA +0 -360
- aigroup_econ_mcp-0.4.2.dist-info/RECORD +0 -29
- aigroup_econ_mcp-0.4.2.dist-info/entry_points.txt +0 -2
- /aigroup_econ_mcp-0.4.2.dist-info/licenses/LICENSE → /LICENSE +0 -0
- {aigroup_econ_mcp-0.4.2.dist-info → aigroup_econ_mcp-1.4.3.dist-info}/WHEEL +0 -0
|
@@ -1,555 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
性能监控模块
|
|
3
|
-
提供性能监控、内存使用跟踪和进度报告功能
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import time
|
|
7
|
-
import psutil
|
|
8
|
-
import threading
|
|
9
|
-
import gc
|
|
10
|
-
from typing import Dict, List, Any, Optional, Callable, Union
|
|
11
|
-
from dataclasses import dataclass, field
|
|
12
|
-
from enum import Enum
|
|
13
|
-
from contextlib import contextmanager
|
|
14
|
-
import warnings
|
|
15
|
-
import sys
|
|
16
|
-
import os
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class PerformanceMetric(Enum):
|
|
20
|
-
"""性能指标类型"""
|
|
21
|
-
EXECUTION_TIME = "execution_time"
|
|
22
|
-
MEMORY_USAGE = "memory_usage"
|
|
23
|
-
CPU_USAGE = "cpu_usage"
|
|
24
|
-
THREAD_COUNT = "thread_count"
|
|
25
|
-
GC_COLLECTIONS = "gc_collections"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class PerformanceStats:
|
|
30
|
-
"""性能统计信息"""
|
|
31
|
-
execution_time: float = 0.0
|
|
32
|
-
peak_memory_mb: float = 0.0
|
|
33
|
-
cpu_percent: float = 0.0
|
|
34
|
-
thread_count: int = 0
|
|
35
|
-
gc_collections: int = 0
|
|
36
|
-
timestamp: float = field(default_factory=time.time)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@dataclass
|
|
40
|
-
class ProgressReport:
|
|
41
|
-
"""进度报告"""
|
|
42
|
-
current_step: int
|
|
43
|
-
total_steps: int
|
|
44
|
-
step_name: str
|
|
45
|
-
progress_percent: float
|
|
46
|
-
elapsed_time: float
|
|
47
|
-
estimated_remaining: float
|
|
48
|
-
status: str
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class PerformanceMonitor:
|
|
52
|
-
"""
|
|
53
|
-
性能监控器
|
|
54
|
-
跟踪函数执行时间、内存使用等性能指标
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
def __init__(self, enabled: bool = True):
|
|
58
|
-
"""
|
|
59
|
-
初始化性能监控器
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
enabled: 是否启用性能监控
|
|
63
|
-
"""
|
|
64
|
-
self.enabled = enabled
|
|
65
|
-
self._stats: Dict[str, PerformanceStats] = {}
|
|
66
|
-
self._process = psutil.Process()
|
|
67
|
-
self._lock = threading.RLock()
|
|
68
|
-
|
|
69
|
-
# 初始内存基准
|
|
70
|
-
self._initial_memory = self._get_memory_usage()
|
|
71
|
-
|
|
72
|
-
def _get_memory_usage(self) -> float:
|
|
73
|
-
"""获取当前内存使用量(MB)"""
|
|
74
|
-
try:
|
|
75
|
-
memory_info = self._process.memory_info()
|
|
76
|
-
return memory_info.rss / 1024 / 1024 # 转换为MB
|
|
77
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
78
|
-
return 0.0
|
|
79
|
-
|
|
80
|
-
def _get_cpu_usage(self) -> float:
|
|
81
|
-
"""获取当前CPU使用率"""
|
|
82
|
-
try:
|
|
83
|
-
return self._process.cpu_percent()
|
|
84
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
85
|
-
return 0.0
|
|
86
|
-
|
|
87
|
-
def _get_thread_count(self) -> int:
|
|
88
|
-
"""获取线程数量"""
|
|
89
|
-
try:
|
|
90
|
-
return self._process.num_threads()
|
|
91
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
92
|
-
return 0
|
|
93
|
-
|
|
94
|
-
def _get_gc_stats(self) -> int:
|
|
95
|
-
"""获取GC收集统计"""
|
|
96
|
-
return sum(gc.get_count())
|
|
97
|
-
|
|
98
|
-
@contextmanager
|
|
99
|
-
def monitor_function(self, function_name: str):
|
|
100
|
-
"""
|
|
101
|
-
监控函数执行的上下文管理器
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
function_name: 函数名称
|
|
105
|
-
|
|
106
|
-
Yields:
|
|
107
|
-
PerformanceStats: 性能统计信息
|
|
108
|
-
"""
|
|
109
|
-
if not self.enabled:
|
|
110
|
-
yield PerformanceStats()
|
|
111
|
-
return
|
|
112
|
-
|
|
113
|
-
# 记录初始状态
|
|
114
|
-
start_time = time.time()
|
|
115
|
-
start_memory = self._get_memory_usage()
|
|
116
|
-
start_cpu = self._get_cpu_usage()
|
|
117
|
-
start_threads = self._get_thread_count()
|
|
118
|
-
start_gc = self._get_gc_stats()
|
|
119
|
-
|
|
120
|
-
peak_memory = start_memory
|
|
121
|
-
|
|
122
|
-
try:
|
|
123
|
-
yield PerformanceStats()
|
|
124
|
-
|
|
125
|
-
finally:
|
|
126
|
-
# 计算性能指标
|
|
127
|
-
end_time = time.time()
|
|
128
|
-
end_memory = self._get_memory_usage()
|
|
129
|
-
end_cpu = self._get_cpu_usage()
|
|
130
|
-
end_threads = self._get_thread_count()
|
|
131
|
-
end_gc = self._get_gc_stats()
|
|
132
|
-
|
|
133
|
-
# 更新峰值内存
|
|
134
|
-
peak_memory = max(peak_memory, end_memory)
|
|
135
|
-
|
|
136
|
-
# 创建统计信息
|
|
137
|
-
stats = PerformanceStats(
|
|
138
|
-
execution_time=end_time - start_time,
|
|
139
|
-
peak_memory_mb=peak_memory - self._initial_memory,
|
|
140
|
-
cpu_percent=end_cpu,
|
|
141
|
-
thread_count=end_threads,
|
|
142
|
-
gc_collections=end_gc - start_gc,
|
|
143
|
-
timestamp=end_time
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
# 保存统计信息
|
|
147
|
-
with self._lock:
|
|
148
|
-
self._stats[function_name] = stats
|
|
149
|
-
|
|
150
|
-
def get_function_stats(self, function_name: str) -> Optional[PerformanceStats]:
|
|
151
|
-
"""
|
|
152
|
-
获取函数性能统计
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
function_name: 函数名称
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
Optional[PerformanceStats]: 性能统计信息
|
|
159
|
-
"""
|
|
160
|
-
return self._stats.get(function_name)
|
|
161
|
-
|
|
162
|
-
def get_all_stats(self) -> Dict[str, PerformanceStats]:
|
|
163
|
-
"""
|
|
164
|
-
获取所有性能统计
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
Dict[str, PerformanceStats]: 所有函数的性能统计
|
|
168
|
-
"""
|
|
169
|
-
return self._stats.copy()
|
|
170
|
-
|
|
171
|
-
def clear_stats(self) -> None:
|
|
172
|
-
"""清空性能统计"""
|
|
173
|
-
with self._lock:
|
|
174
|
-
self._stats.clear()
|
|
175
|
-
|
|
176
|
-
def get_summary(self) -> Dict[str, Any]:
|
|
177
|
-
"""
|
|
178
|
-
获取性能监控摘要
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
Dict[str, Any]: 性能摘要
|
|
182
|
-
"""
|
|
183
|
-
if not self._stats:
|
|
184
|
-
return {}
|
|
185
|
-
|
|
186
|
-
total_time = sum(stats.execution_time for stats in self._stats.values())
|
|
187
|
-
avg_time = total_time / len(self._stats)
|
|
188
|
-
max_time = max(stats.execution_time for stats in self._stats.values())
|
|
189
|
-
min_time = min(stats.execution_time for stats in self._stats.values())
|
|
190
|
-
|
|
191
|
-
total_memory = sum(stats.peak_memory_mb for stats in self._stats.values())
|
|
192
|
-
avg_memory = total_memory / len(self._stats)
|
|
193
|
-
max_memory = max(stats.peak_memory_mb for stats in self._stats.values())
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
"total_functions": len(self._stats),
|
|
197
|
-
"total_execution_time": total_time,
|
|
198
|
-
"average_execution_time": avg_time,
|
|
199
|
-
"max_execution_time": max_time,
|
|
200
|
-
"min_execution_time": min_time,
|
|
201
|
-
"average_memory_usage_mb": avg_memory,
|
|
202
|
-
"max_memory_usage_mb": max_memory,
|
|
203
|
-
"monitored_functions": list(self._stats.keys())
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
class ProgressTracker:
|
|
208
|
-
"""
|
|
209
|
-
进度跟踪器
|
|
210
|
-
提供详细的进度报告和状态更新
|
|
211
|
-
"""
|
|
212
|
-
|
|
213
|
-
def __init__(self, total_steps: int, description: str = ""):
|
|
214
|
-
"""
|
|
215
|
-
初始化进度跟踪器
|
|
216
|
-
|
|
217
|
-
Args:
|
|
218
|
-
total_steps: 总步骤数
|
|
219
|
-
description: 进度描述
|
|
220
|
-
"""
|
|
221
|
-
self.total_steps = total_steps
|
|
222
|
-
self.description = description
|
|
223
|
-
self.current_step = 0
|
|
224
|
-
self.start_time = time.time()
|
|
225
|
-
self._step_times: List[float] = []
|
|
226
|
-
self._step_names: List[str] = []
|
|
227
|
-
self._lock = threading.RLock()
|
|
228
|
-
|
|
229
|
-
def start_step(self, step_name: str = "") -> None:
|
|
230
|
-
"""
|
|
231
|
-
开始新步骤
|
|
232
|
-
|
|
233
|
-
Args:
|
|
234
|
-
step_name: 步骤名称
|
|
235
|
-
"""
|
|
236
|
-
with self._lock:
|
|
237
|
-
self.current_step += 1
|
|
238
|
-
self._step_names.append(step_name)
|
|
239
|
-
self._step_times.append(time.time())
|
|
240
|
-
|
|
241
|
-
def complete_step(self) -> None:
|
|
242
|
-
"""完成当前步骤"""
|
|
243
|
-
with self._lock:
|
|
244
|
-
if self._step_times:
|
|
245
|
-
step_start_time = self._step_times[-1]
|
|
246
|
-
step_duration = time.time() - step_start_time
|
|
247
|
-
self._step_times[-1] = step_duration
|
|
248
|
-
|
|
249
|
-
def get_progress_report(self) -> ProgressReport:
|
|
250
|
-
"""
|
|
251
|
-
获取进度报告
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
ProgressReport: 进度报告
|
|
255
|
-
"""
|
|
256
|
-
with self._lock:
|
|
257
|
-
elapsed_time = time.time() - self.start_time
|
|
258
|
-
|
|
259
|
-
# 计算进度百分比
|
|
260
|
-
progress_percent = (self.current_step / self.total_steps) * 100 if self.total_steps > 0 else 0
|
|
261
|
-
|
|
262
|
-
# 计算预计剩余时间
|
|
263
|
-
if self.current_step > 0:
|
|
264
|
-
avg_time_per_step = elapsed_time / self.current_step
|
|
265
|
-
remaining_steps = self.total_steps - self.current_step
|
|
266
|
-
estimated_remaining = avg_time_per_step * remaining_steps
|
|
267
|
-
else:
|
|
268
|
-
estimated_remaining = 0
|
|
269
|
-
|
|
270
|
-
# 当前步骤名称
|
|
271
|
-
current_step_name = self._step_names[-1] if self._step_names else ""
|
|
272
|
-
|
|
273
|
-
# 状态描述
|
|
274
|
-
if self.current_step == 0:
|
|
275
|
-
status = "等待开始"
|
|
276
|
-
elif self.current_step < self.total_steps:
|
|
277
|
-
status = "进行中"
|
|
278
|
-
else:
|
|
279
|
-
status = "已完成"
|
|
280
|
-
|
|
281
|
-
return ProgressReport(
|
|
282
|
-
current_step=self.current_step,
|
|
283
|
-
total_steps=self.total_steps,
|
|
284
|
-
step_name=current_step_name,
|
|
285
|
-
progress_percent=progress_percent,
|
|
286
|
-
elapsed_time=elapsed_time,
|
|
287
|
-
estimated_remaining=estimated_remaining,
|
|
288
|
-
status=status
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
def print_progress(self) -> None:
|
|
292
|
-
"""打印进度信息"""
|
|
293
|
-
report = self.get_progress_report()
|
|
294
|
-
|
|
295
|
-
progress_bar = self._create_progress_bar(report.progress_percent)
|
|
296
|
-
|
|
297
|
-
print(f"\r{self.description}: {progress_bar} {report.progress_percent:.1f}% "
|
|
298
|
-
f"({report.current_step}/{report.total_steps}) - {report.step_name} "
|
|
299
|
-
f"[已用: {report.elapsed_time:.1f}s, 剩余: {report.estimated_remaining:.1f}s]",
|
|
300
|
-
end="", flush=True)
|
|
301
|
-
|
|
302
|
-
if report.status == "已完成":
|
|
303
|
-
print() # 完成后换行
|
|
304
|
-
|
|
305
|
-
def _create_progress_bar(self, percent: float, length: int = 20) -> str:
|
|
306
|
-
"""
|
|
307
|
-
创建进度条
|
|
308
|
-
|
|
309
|
-
Args:
|
|
310
|
-
percent: 进度百分比
|
|
311
|
-
length: 进度条长度
|
|
312
|
-
|
|
313
|
-
Returns:
|
|
314
|
-
str: 进度条字符串
|
|
315
|
-
"""
|
|
316
|
-
filled_length = int(length * percent / 100)
|
|
317
|
-
bar = '█' * filled_length + '░' * (length - filled_length)
|
|
318
|
-
return f"[{bar}]"
|
|
319
|
-
|
|
320
|
-
def get_step_times(self) -> List[Dict[str, Any]]:
|
|
321
|
-
"""
|
|
322
|
-
获取各步骤执行时间
|
|
323
|
-
|
|
324
|
-
Returns:
|
|
325
|
-
List[Dict[str, Any]]: 步骤时间信息
|
|
326
|
-
"""
|
|
327
|
-
step_info = []
|
|
328
|
-
for i, (step_name, step_time) in enumerate(zip(self._step_names, self._step_times)):
|
|
329
|
-
step_info.append({
|
|
330
|
-
"step": i + 1,
|
|
331
|
-
"name": step_name,
|
|
332
|
-
"duration": step_time,
|
|
333
|
-
"percentage": (step_time / sum(self._step_times)) * 100 if self._step_times else 0
|
|
334
|
-
})
|
|
335
|
-
return step_info
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
class MemoryMonitor:
|
|
339
|
-
"""
|
|
340
|
-
内存监控器
|
|
341
|
-
跟踪内存使用情况和内存泄漏检测
|
|
342
|
-
"""
|
|
343
|
-
|
|
344
|
-
def __init__(self, check_interval: float = 1.0):
|
|
345
|
-
"""
|
|
346
|
-
初始化内存监控器
|
|
347
|
-
|
|
348
|
-
Args:
|
|
349
|
-
check_interval: 检查间隔(秒)
|
|
350
|
-
"""
|
|
351
|
-
self.check_interval = check_interval
|
|
352
|
-
self._process = psutil.Process()
|
|
353
|
-
self._memory_samples: List[float] = []
|
|
354
|
-
self._monitoring = False
|
|
355
|
-
self._monitor_thread: Optional[threading.Thread] = None
|
|
356
|
-
self._stop_event = threading.Event()
|
|
357
|
-
|
|
358
|
-
def start_monitoring(self) -> None:
|
|
359
|
-
"""开始内存监控"""
|
|
360
|
-
if self._monitoring:
|
|
361
|
-
return
|
|
362
|
-
|
|
363
|
-
self._monitoring = True
|
|
364
|
-
self._stop_event.clear()
|
|
365
|
-
self._memory_samples.clear()
|
|
366
|
-
|
|
367
|
-
self._monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
|
|
368
|
-
self._monitor_thread.start()
|
|
369
|
-
|
|
370
|
-
def stop_monitoring(self) -> List[float]:
|
|
371
|
-
"""
|
|
372
|
-
停止内存监控
|
|
373
|
-
|
|
374
|
-
Returns:
|
|
375
|
-
List[float]: 内存使用样本
|
|
376
|
-
"""
|
|
377
|
-
self._monitoring = False
|
|
378
|
-
self._stop_event.set()
|
|
379
|
-
|
|
380
|
-
if self._monitor_thread and self._monitor_thread.is_alive():
|
|
381
|
-
self._monitor_thread.join(timeout=5.0)
|
|
382
|
-
|
|
383
|
-
return self._memory_samples.copy()
|
|
384
|
-
|
|
385
|
-
def _monitor_loop(self) -> None:
|
|
386
|
-
"""内存监控循环"""
|
|
387
|
-
while not self._stop_event.is_set():
|
|
388
|
-
try:
|
|
389
|
-
memory_usage = self._get_memory_usage()
|
|
390
|
-
self._memory_samples.append(memory_usage)
|
|
391
|
-
|
|
392
|
-
# 等待检查间隔
|
|
393
|
-
self._stop_event.wait(self.check_interval)
|
|
394
|
-
|
|
395
|
-
except Exception as e:
|
|
396
|
-
warnings.warn(f"内存监控错误: {e}")
|
|
397
|
-
break
|
|
398
|
-
|
|
399
|
-
def _get_memory_usage(self) -> float:
|
|
400
|
-
"""获取内存使用量(MB)"""
|
|
401
|
-
try:
|
|
402
|
-
memory_info = self._process.memory_info()
|
|
403
|
-
return memory_info.rss / 1024 / 1024 # 转换为MB
|
|
404
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
405
|
-
return 0.0
|
|
406
|
-
|
|
407
|
-
def analyze_memory_usage(self) -> Dict[str, Any]:
|
|
408
|
-
"""
|
|
409
|
-
分析内存使用情况
|
|
410
|
-
|
|
411
|
-
Returns:
|
|
412
|
-
Dict[str, Any]: 内存使用分析
|
|
413
|
-
"""
|
|
414
|
-
if not self._memory_samples:
|
|
415
|
-
return {}
|
|
416
|
-
|
|
417
|
-
samples = self._memory_samples
|
|
418
|
-
initial_memory = samples[0] if samples else 0
|
|
419
|
-
peak_memory = max(samples)
|
|
420
|
-
final_memory = samples[-1] if samples else 0
|
|
421
|
-
memory_increase = final_memory - initial_memory
|
|
422
|
-
|
|
423
|
-
# 检测内存泄漏(持续增长)
|
|
424
|
-
memory_growth_rate = self._calculate_growth_rate(samples)
|
|
425
|
-
|
|
426
|
-
return {
|
|
427
|
-
"initial_memory_mb": initial_memory,
|
|
428
|
-
"peak_memory_mb": peak_memory,
|
|
429
|
-
"final_memory_mb": final_memory,
|
|
430
|
-
"memory_increase_mb": memory_increase,
|
|
431
|
-
"memory_growth_rate": memory_growth_rate,
|
|
432
|
-
"sample_count": len(samples),
|
|
433
|
-
"potential_leak": memory_growth_rate > 0.1 and memory_increase > 10.0 # 10MB增长且增长率>10%
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
def _calculate_growth_rate(self, samples: List[float]) -> float:
|
|
437
|
-
"""计算内存增长率"""
|
|
438
|
-
if len(samples) < 2:
|
|
439
|
-
return 0.0
|
|
440
|
-
|
|
441
|
-
# 使用线性回归计算增长率
|
|
442
|
-
x = list(range(len(samples)))
|
|
443
|
-
y = samples
|
|
444
|
-
|
|
445
|
-
n = len(x)
|
|
446
|
-
sum_x = sum(x)
|
|
447
|
-
sum_y = sum(y)
|
|
448
|
-
sum_xy = sum(x_i * y_i for x_i, y_i in zip(x, y))
|
|
449
|
-
sum_x2 = sum(x_i ** 2 for x_i in x)
|
|
450
|
-
|
|
451
|
-
denominator = n * sum_x2 - sum_x ** 2
|
|
452
|
-
if denominator == 0:
|
|
453
|
-
return 0.0
|
|
454
|
-
|
|
455
|
-
slope = (n * sum_xy - sum_x * sum_y) / denominator
|
|
456
|
-
return slope
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
# 全局监控实例
|
|
460
|
-
global_performance_monitor = PerformanceMonitor()
|
|
461
|
-
global_memory_monitor = MemoryMonitor()
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
# 便捷装饰器和上下文管理器
|
|
465
|
-
def monitor_performance(function_name: str = None):
|
|
466
|
-
"""
|
|
467
|
-
性能监控装饰器
|
|
468
|
-
|
|
469
|
-
Args:
|
|
470
|
-
function_name: 函数名称,如果为None则使用函数名
|
|
471
|
-
|
|
472
|
-
Returns:
|
|
473
|
-
Callable: 装饰器函数
|
|
474
|
-
"""
|
|
475
|
-
def decorator(func):
|
|
476
|
-
name = function_name or func.__name__
|
|
477
|
-
|
|
478
|
-
def wrapper(*args, **kwargs):
|
|
479
|
-
with global_performance_monitor.monitor_function(name):
|
|
480
|
-
return func(*args, **kwargs)
|
|
481
|
-
|
|
482
|
-
# 保留原始函数的元数据
|
|
483
|
-
wrapper.__name__ = func.__name__
|
|
484
|
-
wrapper.__doc__ = func.__doc__
|
|
485
|
-
wrapper.__module__ = func.__module__
|
|
486
|
-
|
|
487
|
-
return wrapper
|
|
488
|
-
|
|
489
|
-
return decorator
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
@contextmanager
|
|
493
|
-
def track_progress(total_steps: int, description: str = ""):
|
|
494
|
-
"""
|
|
495
|
-
进度跟踪上下文管理器
|
|
496
|
-
|
|
497
|
-
Args:
|
|
498
|
-
total_steps: 总步骤数
|
|
499
|
-
description: 进度描述
|
|
500
|
-
|
|
501
|
-
Yields:
|
|
502
|
-
ProgressTracker: 进度跟踪器
|
|
503
|
-
"""
|
|
504
|
-
tracker = ProgressTracker(total_steps, description)
|
|
505
|
-
|
|
506
|
-
try:
|
|
507
|
-
yield tracker
|
|
508
|
-
finally:
|
|
509
|
-
# 确保进度显示完成
|
|
510
|
-
if tracker.current_step < tracker.total_steps:
|
|
511
|
-
tracker.current_step = tracker.total_steps
|
|
512
|
-
tracker.print_progress()
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def enable_memory_monitoring(check_interval: float = 1.0) -> MemoryMonitor:
|
|
516
|
-
"""
|
|
517
|
-
启用内存监控
|
|
518
|
-
|
|
519
|
-
Args:
|
|
520
|
-
check_interval: 检查间隔(秒)
|
|
521
|
-
|
|
522
|
-
Returns:
|
|
523
|
-
MemoryMonitor: 内存监控器实例
|
|
524
|
-
"""
|
|
525
|
-
global_memory_monitor.check_interval = check_interval
|
|
526
|
-
global_memory_monitor.start_monitoring()
|
|
527
|
-
return global_memory_monitor
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
def disable_memory_monitoring() -> Dict[str, Any]:
|
|
531
|
-
"""
|
|
532
|
-
禁用内存监控并返回分析结果
|
|
533
|
-
|
|
534
|
-
Returns:
|
|
535
|
-
Dict[str, Any]: 内存使用分析
|
|
536
|
-
"""
|
|
537
|
-
global_memory_monitor.stop_monitoring()
|
|
538
|
-
return global_memory_monitor.analyze_memory_usage()
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
# 导出主要类和函数
|
|
542
|
-
__all__ = [
|
|
543
|
-
"PerformanceMetric",
|
|
544
|
-
"PerformanceStats",
|
|
545
|
-
"ProgressReport",
|
|
546
|
-
"PerformanceMonitor",
|
|
547
|
-
"ProgressTracker",
|
|
548
|
-
"MemoryMonitor",
|
|
549
|
-
"global_performance_monitor",
|
|
550
|
-
"global_memory_monitor",
|
|
551
|
-
"monitor_performance",
|
|
552
|
-
"track_progress",
|
|
553
|
-
"enable_memory_monitoring",
|
|
554
|
-
"disable_memory_monitoring"
|
|
555
|
-
]
|