exonware-xwnode 0.0.1.12__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.
- exonware/__init__.py +14 -0
- exonware/xwnode/__init__.py +127 -0
- exonware/xwnode/base.py +676 -0
- exonware/xwnode/config.py +178 -0
- exonware/xwnode/contracts.py +730 -0
- exonware/xwnode/errors.py +503 -0
- exonware/xwnode/facade.py +460 -0
- exonware/xwnode/strategies/__init__.py +158 -0
- exonware/xwnode/strategies/advisor.py +463 -0
- exonware/xwnode/strategies/edges/__init__.py +32 -0
- exonware/xwnode/strategies/edges/adj_list.py +227 -0
- exonware/xwnode/strategies/edges/adj_matrix.py +391 -0
- exonware/xwnode/strategies/edges/base.py +169 -0
- exonware/xwnode/strategies/flyweight.py +328 -0
- exonware/xwnode/strategies/impls/__init__.py +13 -0
- exonware/xwnode/strategies/impls/_base_edge.py +403 -0
- exonware/xwnode/strategies/impls/_base_node.py +307 -0
- exonware/xwnode/strategies/impls/edge_adj_list.py +353 -0
- exonware/xwnode/strategies/impls/edge_adj_matrix.py +445 -0
- exonware/xwnode/strategies/impls/edge_bidir_wrapper.py +455 -0
- exonware/xwnode/strategies/impls/edge_block_adj_matrix.py +539 -0
- exonware/xwnode/strategies/impls/edge_coo.py +533 -0
- exonware/xwnode/strategies/impls/edge_csc.py +447 -0
- exonware/xwnode/strategies/impls/edge_csr.py +492 -0
- exonware/xwnode/strategies/impls/edge_dynamic_adj_list.py +503 -0
- exonware/xwnode/strategies/impls/edge_flow_network.py +555 -0
- exonware/xwnode/strategies/impls/edge_hyperedge_set.py +516 -0
- exonware/xwnode/strategies/impls/edge_neural_graph.py +650 -0
- exonware/xwnode/strategies/impls/edge_octree.py +574 -0
- exonware/xwnode/strategies/impls/edge_property_store.py +655 -0
- exonware/xwnode/strategies/impls/edge_quadtree.py +519 -0
- exonware/xwnode/strategies/impls/edge_rtree.py +820 -0
- exonware/xwnode/strategies/impls/edge_temporal_edgeset.py +558 -0
- exonware/xwnode/strategies/impls/edge_tree_graph_basic.py +271 -0
- exonware/xwnode/strategies/impls/edge_weighted_graph.py +411 -0
- exonware/xwnode/strategies/manager.py +775 -0
- exonware/xwnode/strategies/metrics.py +538 -0
- exonware/xwnode/strategies/migration.py +432 -0
- exonware/xwnode/strategies/nodes/__init__.py +50 -0
- exonware/xwnode/strategies/nodes/_base_node.py +307 -0
- exonware/xwnode/strategies/nodes/adjacency_list.py +267 -0
- exonware/xwnode/strategies/nodes/aho_corasick.py +345 -0
- exonware/xwnode/strategies/nodes/array_list.py +209 -0
- exonware/xwnode/strategies/nodes/base.py +247 -0
- exonware/xwnode/strategies/nodes/deque.py +200 -0
- exonware/xwnode/strategies/nodes/hash_map.py +135 -0
- exonware/xwnode/strategies/nodes/heap.py +307 -0
- exonware/xwnode/strategies/nodes/linked_list.py +232 -0
- exonware/xwnode/strategies/nodes/node_aho_corasick.py +520 -0
- exonware/xwnode/strategies/nodes/node_array_list.py +175 -0
- exonware/xwnode/strategies/nodes/node_avl_tree.py +371 -0
- exonware/xwnode/strategies/nodes/node_b_plus_tree.py +542 -0
- exonware/xwnode/strategies/nodes/node_bitmap.py +420 -0
- exonware/xwnode/strategies/nodes/node_bitset_dynamic.py +513 -0
- exonware/xwnode/strategies/nodes/node_bloom_filter.py +347 -0
- exonware/xwnode/strategies/nodes/node_btree.py +357 -0
- exonware/xwnode/strategies/nodes/node_count_min_sketch.py +470 -0
- exonware/xwnode/strategies/nodes/node_cow_tree.py +473 -0
- exonware/xwnode/strategies/nodes/node_cuckoo_hash.py +392 -0
- exonware/xwnode/strategies/nodes/node_fenwick_tree.py +301 -0
- exonware/xwnode/strategies/nodes/node_hash_map.py +269 -0
- exonware/xwnode/strategies/nodes/node_heap.py +191 -0
- exonware/xwnode/strategies/nodes/node_hyperloglog.py +407 -0
- exonware/xwnode/strategies/nodes/node_linked_list.py +409 -0
- exonware/xwnode/strategies/nodes/node_lsm_tree.py +400 -0
- exonware/xwnode/strategies/nodes/node_ordered_map.py +390 -0
- exonware/xwnode/strategies/nodes/node_ordered_map_balanced.py +565 -0
- exonware/xwnode/strategies/nodes/node_patricia.py +512 -0
- exonware/xwnode/strategies/nodes/node_persistent_tree.py +378 -0
- exonware/xwnode/strategies/nodes/node_radix_trie.py +452 -0
- exonware/xwnode/strategies/nodes/node_red_black_tree.py +497 -0
- exonware/xwnode/strategies/nodes/node_roaring_bitmap.py +570 -0
- exonware/xwnode/strategies/nodes/node_segment_tree.py +289 -0
- exonware/xwnode/strategies/nodes/node_set_hash.py +354 -0
- exonware/xwnode/strategies/nodes/node_set_tree.py +480 -0
- exonware/xwnode/strategies/nodes/node_skip_list.py +316 -0
- exonware/xwnode/strategies/nodes/node_splay_tree.py +393 -0
- exonware/xwnode/strategies/nodes/node_suffix_array.py +487 -0
- exonware/xwnode/strategies/nodes/node_treap.py +387 -0
- exonware/xwnode/strategies/nodes/node_tree_graph_hybrid.py +1434 -0
- exonware/xwnode/strategies/nodes/node_trie.py +252 -0
- exonware/xwnode/strategies/nodes/node_union_find.py +187 -0
- exonware/xwnode/strategies/nodes/node_xdata_optimized.py +369 -0
- exonware/xwnode/strategies/nodes/priority_queue.py +209 -0
- exonware/xwnode/strategies/nodes/queue.py +161 -0
- exonware/xwnode/strategies/nodes/sparse_matrix.py +206 -0
- exonware/xwnode/strategies/nodes/stack.py +152 -0
- exonware/xwnode/strategies/nodes/trie.py +274 -0
- exonware/xwnode/strategies/nodes/union_find.py +283 -0
- exonware/xwnode/strategies/pattern_detector.py +603 -0
- exonware/xwnode/strategies/performance_monitor.py +487 -0
- exonware/xwnode/strategies/queries/__init__.py +24 -0
- exonware/xwnode/strategies/queries/base.py +236 -0
- exonware/xwnode/strategies/queries/cql.py +201 -0
- exonware/xwnode/strategies/queries/cypher.py +181 -0
- exonware/xwnode/strategies/queries/datalog.py +70 -0
- exonware/xwnode/strategies/queries/elastic_dsl.py +70 -0
- exonware/xwnode/strategies/queries/eql.py +70 -0
- exonware/xwnode/strategies/queries/flux.py +70 -0
- exonware/xwnode/strategies/queries/gql.py +70 -0
- exonware/xwnode/strategies/queries/graphql.py +240 -0
- exonware/xwnode/strategies/queries/gremlin.py +181 -0
- exonware/xwnode/strategies/queries/hiveql.py +214 -0
- exonware/xwnode/strategies/queries/hql.py +70 -0
- exonware/xwnode/strategies/queries/jmespath.py +219 -0
- exonware/xwnode/strategies/queries/jq.py +66 -0
- exonware/xwnode/strategies/queries/json_query.py +66 -0
- exonware/xwnode/strategies/queries/jsoniq.py +248 -0
- exonware/xwnode/strategies/queries/kql.py +70 -0
- exonware/xwnode/strategies/queries/linq.py +238 -0
- exonware/xwnode/strategies/queries/logql.py +70 -0
- exonware/xwnode/strategies/queries/mql.py +68 -0
- exonware/xwnode/strategies/queries/n1ql.py +210 -0
- exonware/xwnode/strategies/queries/partiql.py +70 -0
- exonware/xwnode/strategies/queries/pig.py +215 -0
- exonware/xwnode/strategies/queries/promql.py +70 -0
- exonware/xwnode/strategies/queries/sparql.py +220 -0
- exonware/xwnode/strategies/queries/sql.py +275 -0
- exonware/xwnode/strategies/queries/xml_query.py +66 -0
- exonware/xwnode/strategies/queries/xpath.py +223 -0
- exonware/xwnode/strategies/queries/xquery.py +258 -0
- exonware/xwnode/strategies/queries/xwnode_executor.py +332 -0
- exonware/xwnode/strategies/queries/xwquery_strategy.py +424 -0
- exonware/xwnode/strategies/registry.py +604 -0
- exonware/xwnode/strategies/simple.py +273 -0
- exonware/xwnode/strategies/utils.py +532 -0
- exonware/xwnode/types.py +912 -0
- exonware/xwnode/version.py +78 -0
- exonware_xwnode-0.0.1.12.dist-info/METADATA +169 -0
- exonware_xwnode-0.0.1.12.dist-info/RECORD +132 -0
- exonware_xwnode-0.0.1.12.dist-info/WHEEL +4 -0
- exonware_xwnode-0.0.1.12.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,538 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
#exonware/xwnode/src/exonware/xwnode/strategies/metrics.py
|
3
|
+
"""
|
4
|
+
Strategy Metrics and Statistics
|
5
|
+
|
6
|
+
Comprehensive metrics collection and analysis for strategy performance,
|
7
|
+
memory usage, and optimization recommendations.
|
8
|
+
|
9
|
+
Company: eXonware.com
|
10
|
+
Author: Eng. Muhammad AlShehri
|
11
|
+
Email: connect@exonware.com
|
12
|
+
Version: 0.0.1.12
|
13
|
+
Generation Date: 07-Sep-2025
|
14
|
+
"""
|
15
|
+
|
16
|
+
import time
|
17
|
+
import threading
|
18
|
+
from typing import Any, Dict, List, Optional, Union
|
19
|
+
from dataclasses import dataclass, field
|
20
|
+
from collections import defaultdict, deque
|
21
|
+
from enum import Enum
|
22
|
+
from exonware.xwsystem import get_logger
|
23
|
+
|
24
|
+
logger = get_logger(__name__)
|
25
|
+
|
26
|
+
from ..types import NodeMode, EdgeMode
|
27
|
+
from .flyweight import get_flyweight_stats
|
28
|
+
from .pattern_detector import get_detector
|
29
|
+
from .performance_monitor import get_monitor, get_performance_summary
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
class MetricType(Enum):
|
34
|
+
"""Types of metrics to collect."""
|
35
|
+
PERFORMANCE = "performance"
|
36
|
+
MEMORY = "memory"
|
37
|
+
USAGE = "usage"
|
38
|
+
OPTIMIZATION = "optimization"
|
39
|
+
ERROR = "error"
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class MetricSnapshot:
|
44
|
+
"""Snapshot of metrics at a point in time."""
|
45
|
+
timestamp: float
|
46
|
+
metric_type: MetricType
|
47
|
+
value: float
|
48
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
49
|
+
|
50
|
+
|
51
|
+
@dataclass
|
52
|
+
class StrategyMetrics:
|
53
|
+
"""Comprehensive metrics for a strategy."""
|
54
|
+
strategy_id: str
|
55
|
+
strategy_name: str
|
56
|
+
mode: Union[NodeMode, EdgeMode]
|
57
|
+
total_operations: int = 0
|
58
|
+
total_time: float = 0.0
|
59
|
+
average_time: float = 0.0
|
60
|
+
memory_usage: float = 0.0
|
61
|
+
error_count: int = 0
|
62
|
+
error_rate: float = 0.0
|
63
|
+
optimization_score: float = 0.0
|
64
|
+
last_updated: float = field(default_factory=time.time)
|
65
|
+
snapshots: List[MetricSnapshot] = field(default_factory=list)
|
66
|
+
|
67
|
+
|
68
|
+
class StrategyMetricsCollector:
|
69
|
+
"""
|
70
|
+
Comprehensive metrics collector for strategy performance analysis.
|
71
|
+
"""
|
72
|
+
|
73
|
+
def __init__(self, history_size: int = 1000):
|
74
|
+
"""
|
75
|
+
Initialize metrics collector.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
history_size: Maximum number of metric snapshots to keep
|
79
|
+
"""
|
80
|
+
self._history_size = history_size
|
81
|
+
self._strategy_metrics: Dict[str, StrategyMetrics] = {}
|
82
|
+
self._global_metrics: Dict[str, Any] = {
|
83
|
+
'total_strategies': 0,
|
84
|
+
'total_operations': 0,
|
85
|
+
'total_memory_usage': 0.0,
|
86
|
+
'average_performance': 0.0,
|
87
|
+
'system_uptime': time.time(),
|
88
|
+
'last_collection': time.time()
|
89
|
+
}
|
90
|
+
self._lock = threading.RLock()
|
91
|
+
self._collection_interval = 60.0 # 1 minute
|
92
|
+
self._last_collection = time.time()
|
93
|
+
|
94
|
+
def collect_comprehensive_metrics(self) -> Dict[str, Any]:
|
95
|
+
"""
|
96
|
+
Collect comprehensive metrics from all components.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
Complete metrics dictionary
|
100
|
+
"""
|
101
|
+
with self._lock:
|
102
|
+
current_time = time.time()
|
103
|
+
|
104
|
+
# Collect from all components
|
105
|
+
flyweight_stats = get_flyweight_stats()
|
106
|
+
monitor_summary = get_performance_summary()
|
107
|
+
detector_stats = get_detector().get_stats()
|
108
|
+
|
109
|
+
# Update global metrics
|
110
|
+
self._global_metrics.update({
|
111
|
+
'total_strategies': len(self._strategy_metrics),
|
112
|
+
'total_operations': monitor_summary.get('total_operations', 0),
|
113
|
+
'total_memory_usage': monitor_summary.get('average_operation_time', 0.0),
|
114
|
+
'average_performance': monitor_summary.get('average_operation_time', 0.0),
|
115
|
+
'last_collection': current_time,
|
116
|
+
'collection_interval': current_time - self._last_collection
|
117
|
+
})
|
118
|
+
|
119
|
+
self._last_collection = current_time
|
120
|
+
|
121
|
+
return {
|
122
|
+
'timestamp': current_time,
|
123
|
+
'global_metrics': self._global_metrics.copy(),
|
124
|
+
'flyweight_metrics': flyweight_stats,
|
125
|
+
'performance_metrics': monitor_summary,
|
126
|
+
'detector_metrics': detector_stats,
|
127
|
+
'strategy_metrics': self._get_strategy_metrics_summary(),
|
128
|
+
'optimization_recommendations': self._generate_optimization_recommendations(),
|
129
|
+
'system_health': self._assess_system_health()
|
130
|
+
}
|
131
|
+
|
132
|
+
def record_strategy_metric(
|
133
|
+
self,
|
134
|
+
strategy_id: str,
|
135
|
+
strategy_name: str,
|
136
|
+
mode: Union[NodeMode, EdgeMode],
|
137
|
+
metric_type: MetricType,
|
138
|
+
value: float,
|
139
|
+
**metadata: Any
|
140
|
+
) -> None:
|
141
|
+
"""
|
142
|
+
Record a metric for a specific strategy.
|
143
|
+
|
144
|
+
Args:
|
145
|
+
strategy_id: Unique strategy identifier
|
146
|
+
strategy_name: Human-readable strategy name
|
147
|
+
mode: Strategy mode
|
148
|
+
metric_type: Type of metric
|
149
|
+
value: Metric value
|
150
|
+
**metadata: Additional metadata
|
151
|
+
"""
|
152
|
+
with self._lock:
|
153
|
+
# Get or create strategy metrics
|
154
|
+
if strategy_id not in self._strategy_metrics:
|
155
|
+
self._strategy_metrics[strategy_id] = StrategyMetrics(
|
156
|
+
strategy_id=strategy_id,
|
157
|
+
strategy_name=strategy_name,
|
158
|
+
mode=mode
|
159
|
+
)
|
160
|
+
|
161
|
+
metrics = self._strategy_metrics[strategy_id]
|
162
|
+
|
163
|
+
# Update metrics based on type
|
164
|
+
if metric_type == MetricType.PERFORMANCE:
|
165
|
+
metrics.total_operations += 1
|
166
|
+
metrics.total_time += value
|
167
|
+
metrics.average_time = metrics.total_time / metrics.total_operations
|
168
|
+
elif metric_type == MetricType.MEMORY:
|
169
|
+
metrics.memory_usage = value
|
170
|
+
elif metric_type == MetricType.ERROR:
|
171
|
+
metrics.error_count += 1
|
172
|
+
metrics.error_rate = metrics.error_count / max(metrics.total_operations, 1)
|
173
|
+
|
174
|
+
# Add snapshot
|
175
|
+
snapshot = MetricSnapshot(
|
176
|
+
timestamp=time.time(),
|
177
|
+
metric_type=metric_type,
|
178
|
+
value=value,
|
179
|
+
metadata=metadata
|
180
|
+
)
|
181
|
+
metrics.snapshots.append(snapshot)
|
182
|
+
|
183
|
+
# Trim history
|
184
|
+
if len(metrics.snapshots) > self._history_size:
|
185
|
+
metrics.snapshots = metrics.snapshots[-self._history_size:]
|
186
|
+
|
187
|
+
metrics.last_updated = time.time()
|
188
|
+
|
189
|
+
logger.debug(f"๐ Recorded {metric_type.value} metric for {strategy_name}: {value}")
|
190
|
+
|
191
|
+
def get_strategy_metrics(self, strategy_id: str) -> Optional[StrategyMetrics]:
|
192
|
+
"""
|
193
|
+
Get metrics for a specific strategy.
|
194
|
+
|
195
|
+
Args:
|
196
|
+
strategy_id: Strategy identifier
|
197
|
+
|
198
|
+
Returns:
|
199
|
+
Strategy metrics or None if not found
|
200
|
+
"""
|
201
|
+
with self._lock:
|
202
|
+
return self._strategy_metrics.get(strategy_id)
|
203
|
+
|
204
|
+
def get_top_performing_strategies(self, limit: int = 5) -> List[StrategyMetrics]:
|
205
|
+
"""
|
206
|
+
Get top performing strategies by average operation time.
|
207
|
+
|
208
|
+
Args:
|
209
|
+
limit: Maximum number of strategies to return
|
210
|
+
|
211
|
+
Returns:
|
212
|
+
List of top performing strategies
|
213
|
+
"""
|
214
|
+
with self._lock:
|
215
|
+
strategies = [
|
216
|
+
metrics for metrics in self._strategy_metrics.values()
|
217
|
+
if metrics.total_operations > 0
|
218
|
+
]
|
219
|
+
|
220
|
+
# Sort by average time (lower is better)
|
221
|
+
strategies.sort(key=lambda x: x.average_time)
|
222
|
+
|
223
|
+
return strategies[:limit]
|
224
|
+
|
225
|
+
def get_memory_usage_summary(self) -> Dict[str, Any]:
|
226
|
+
"""
|
227
|
+
Get memory usage summary across all strategies.
|
228
|
+
|
229
|
+
Returns:
|
230
|
+
Memory usage summary
|
231
|
+
"""
|
232
|
+
with self._lock:
|
233
|
+
total_memory = sum(metrics.memory_usage for metrics in self._strategy_metrics.values())
|
234
|
+
strategy_count = len(self._strategy_metrics)
|
235
|
+
|
236
|
+
return {
|
237
|
+
'total_memory_usage': total_memory,
|
238
|
+
'average_memory_per_strategy': total_memory / max(strategy_count, 1),
|
239
|
+
'strategy_count': strategy_count,
|
240
|
+
'memory_by_strategy': {
|
241
|
+
metrics.strategy_name: metrics.memory_usage
|
242
|
+
for metrics in self._strategy_metrics.values()
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
def get_performance_trends(self, strategy_id: str, hours: int = 24) -> Dict[str, Any]:
|
247
|
+
"""
|
248
|
+
Get performance trends for a strategy over time.
|
249
|
+
|
250
|
+
Args:
|
251
|
+
strategy_id: Strategy identifier
|
252
|
+
hours: Number of hours to analyze
|
253
|
+
|
254
|
+
Returns:
|
255
|
+
Performance trends data
|
256
|
+
"""
|
257
|
+
with self._lock:
|
258
|
+
metrics = self._strategy_metrics.get(strategy_id)
|
259
|
+
if not metrics:
|
260
|
+
return {}
|
261
|
+
|
262
|
+
cutoff_time = time.time() - (hours * 3600)
|
263
|
+
recent_snapshots = [
|
264
|
+
snapshot for snapshot in metrics.snapshots
|
265
|
+
if snapshot.timestamp >= cutoff_time
|
266
|
+
]
|
267
|
+
|
268
|
+
if not recent_snapshots:
|
269
|
+
return {}
|
270
|
+
|
271
|
+
# Analyze trends
|
272
|
+
performance_snapshots = [
|
273
|
+
s for s in recent_snapshots if s.metric_type == MetricType.PERFORMANCE
|
274
|
+
]
|
275
|
+
|
276
|
+
if len(performance_snapshots) < 2:
|
277
|
+
return {'trend': 'insufficient_data'}
|
278
|
+
|
279
|
+
# Calculate trend
|
280
|
+
first_half = performance_snapshots[:len(performance_snapshots)//2]
|
281
|
+
second_half = performance_snapshots[len(performance_snapshots)//2:]
|
282
|
+
|
283
|
+
first_avg = sum(s.value for s in first_half) / len(first_half)
|
284
|
+
second_avg = sum(s.value for s in second_half) / len(second_half)
|
285
|
+
|
286
|
+
trend_direction = 'improving' if second_avg < first_avg else 'degrading'
|
287
|
+
trend_magnitude = abs(second_avg - first_avg) / first_avg if first_avg > 0 else 0
|
288
|
+
|
289
|
+
return {
|
290
|
+
'trend': trend_direction,
|
291
|
+
'magnitude': trend_magnitude,
|
292
|
+
'first_half_avg': first_avg,
|
293
|
+
'second_half_avg': second_avg,
|
294
|
+
'data_points': len(performance_snapshots)
|
295
|
+
}
|
296
|
+
|
297
|
+
def _get_strategy_metrics_summary(self) -> Dict[str, Any]:
|
298
|
+
"""Get summary of all strategy metrics."""
|
299
|
+
with self._lock:
|
300
|
+
if not self._strategy_metrics:
|
301
|
+
return {}
|
302
|
+
|
303
|
+
total_operations = sum(m.total_operations for m in self._strategy_metrics.values())
|
304
|
+
total_time = sum(m.total_time for m in self._strategy_metrics.values())
|
305
|
+
total_memory = sum(m.memory_usage for m in self._strategy_metrics.values())
|
306
|
+
|
307
|
+
return {
|
308
|
+
'total_strategies': len(self._strategy_metrics),
|
309
|
+
'total_operations': total_operations,
|
310
|
+
'total_time': total_time,
|
311
|
+
'total_memory': total_memory,
|
312
|
+
'average_operation_time': total_time / max(total_operations, 1),
|
313
|
+
'strategies': {
|
314
|
+
sid: {
|
315
|
+
'name': metrics.strategy_name,
|
316
|
+
'mode': metrics.mode.name,
|
317
|
+
'operations': metrics.total_operations,
|
318
|
+
'avg_time': metrics.average_time,
|
319
|
+
'memory': metrics.memory_usage,
|
320
|
+
'error_rate': metrics.error_rate,
|
321
|
+
'last_updated': metrics.last_updated
|
322
|
+
}
|
323
|
+
for sid, metrics in self._strategy_metrics.items()
|
324
|
+
}
|
325
|
+
}
|
326
|
+
|
327
|
+
def _generate_optimization_recommendations(self) -> List[Dict[str, Any]]:
|
328
|
+
"""Generate optimization recommendations based on metrics."""
|
329
|
+
recommendations = []
|
330
|
+
|
331
|
+
with self._lock:
|
332
|
+
for strategy_id, metrics in self._strategy_metrics.items():
|
333
|
+
# High error rate recommendation
|
334
|
+
if metrics.error_rate > 0.05: # 5%
|
335
|
+
recommendations.append({
|
336
|
+
'strategy_id': strategy_id,
|
337
|
+
'strategy_name': metrics.strategy_name,
|
338
|
+
'type': 'high_error_rate',
|
339
|
+
'severity': 'high',
|
340
|
+
'description': f"High error rate: {metrics.error_rate:.1%}",
|
341
|
+
'recommendation': "Consider switching to a more stable strategy"
|
342
|
+
})
|
343
|
+
|
344
|
+
# Slow performance recommendation
|
345
|
+
if metrics.average_time > 0.01: # 10ms
|
346
|
+
recommendations.append({
|
347
|
+
'strategy_id': strategy_id,
|
348
|
+
'strategy_name': metrics.strategy_name,
|
349
|
+
'type': 'slow_performance',
|
350
|
+
'severity': 'medium',
|
351
|
+
'description': f"Slow average operation time: {metrics.average_time:.3f}s",
|
352
|
+
'recommendation': "Consider optimizing or switching strategies"
|
353
|
+
})
|
354
|
+
|
355
|
+
# High memory usage recommendation
|
356
|
+
if metrics.memory_usage > 100 * 1024 * 1024: # 100MB
|
357
|
+
recommendations.append({
|
358
|
+
'strategy_id': strategy_id,
|
359
|
+
'strategy_name': metrics.strategy_name,
|
360
|
+
'type': 'high_memory_usage',
|
361
|
+
'severity': 'medium',
|
362
|
+
'description': f"High memory usage: {metrics.memory_usage / 1024 / 1024:.1f}MB",
|
363
|
+
'recommendation': "Consider memory-efficient strategy alternatives"
|
364
|
+
})
|
365
|
+
|
366
|
+
return recommendations
|
367
|
+
|
368
|
+
def _assess_system_health(self) -> Dict[str, Any]:
|
369
|
+
"""Assess overall system health based on metrics."""
|
370
|
+
with self._lock:
|
371
|
+
if not self._strategy_metrics:
|
372
|
+
return {'status': 'unknown', 'score': 0.0}
|
373
|
+
|
374
|
+
# Calculate health score (0-100)
|
375
|
+
total_strategies = len(self._strategy_metrics)
|
376
|
+
high_error_strategies = sum(1 for m in self._strategy_metrics.values() if m.error_rate > 0.05)
|
377
|
+
slow_strategies = sum(1 for m in self._strategy_metrics.values() if m.average_time > 0.01)
|
378
|
+
|
379
|
+
error_penalty = (high_error_strategies / total_strategies) * 50
|
380
|
+
performance_penalty = (slow_strategies / total_strategies) * 30
|
381
|
+
|
382
|
+
health_score = max(0, 100 - error_penalty - performance_penalty)
|
383
|
+
|
384
|
+
# Determine status
|
385
|
+
if health_score >= 80:
|
386
|
+
status = 'excellent'
|
387
|
+
elif health_score >= 60:
|
388
|
+
status = 'good'
|
389
|
+
elif health_score >= 40:
|
390
|
+
status = 'fair'
|
391
|
+
else:
|
392
|
+
status = 'poor'
|
393
|
+
|
394
|
+
return {
|
395
|
+
'status': status,
|
396
|
+
'score': health_score,
|
397
|
+
'total_strategies': total_strategies,
|
398
|
+
'high_error_strategies': high_error_strategies,
|
399
|
+
'slow_strategies': slow_strategies,
|
400
|
+
'recommendations_count': len(self._generate_optimization_recommendations())
|
401
|
+
}
|
402
|
+
|
403
|
+
def export_metrics(self, format: str = 'json') -> Union[Dict[str, Any], str]:
|
404
|
+
"""
|
405
|
+
Export metrics in specified format.
|
406
|
+
|
407
|
+
Args:
|
408
|
+
format: Export format ('json' or 'summary')
|
409
|
+
|
410
|
+
Returns:
|
411
|
+
Exported metrics
|
412
|
+
"""
|
413
|
+
metrics = self.collect_comprehensive_metrics()
|
414
|
+
|
415
|
+
if format == 'summary':
|
416
|
+
return self._format_summary(metrics)
|
417
|
+
else:
|
418
|
+
return metrics
|
419
|
+
|
420
|
+
def _format_summary(self, metrics: Dict[str, Any]) -> str:
|
421
|
+
"""Format metrics as a human-readable summary."""
|
422
|
+
global_metrics = metrics.get('global_metrics', {})
|
423
|
+
system_health = metrics.get('system_health', {})
|
424
|
+
recommendations = metrics.get('optimization_recommendations', [])
|
425
|
+
|
426
|
+
summary = f"""
|
427
|
+
๐ XWNode Strategy Metrics Summary
|
428
|
+
{'=' * 50}
|
429
|
+
|
430
|
+
๐ฅ System Health: {system_health.get('status', 'unknown').upper()} ({system_health.get('score', 0):.1f}/100)
|
431
|
+
๐ Total Strategies: {global_metrics.get('total_strategies', 0)}
|
432
|
+
โก Total Operations: {global_metrics.get('total_operations', 0)}
|
433
|
+
๐พ Memory Usage: {global_metrics.get('total_memory_usage', 0):.2f} MB
|
434
|
+
โฑ๏ธ Avg Operation Time: {global_metrics.get('average_performance', 0):.3f}s
|
435
|
+
|
436
|
+
๐ง Optimization Recommendations: {len(recommendations)}
|
437
|
+
"""
|
438
|
+
|
439
|
+
if recommendations:
|
440
|
+
summary += "\n๐ Top Recommendations:\n"
|
441
|
+
for i, rec in enumerate(recommendations[:3], 1):
|
442
|
+
summary += f" {i}. {rec['strategy_name']}: {rec['description']}\n"
|
443
|
+
|
444
|
+
return summary.strip()
|
445
|
+
|
446
|
+
def clear_metrics(self) -> None:
|
447
|
+
"""Clear all collected metrics."""
|
448
|
+
with self._lock:
|
449
|
+
self._strategy_metrics.clear()
|
450
|
+
self._global_metrics = {
|
451
|
+
'total_strategies': 0,
|
452
|
+
'total_operations': 0,
|
453
|
+
'total_memory_usage': 0.0,
|
454
|
+
'average_performance': 0.0,
|
455
|
+
'system_uptime': time.time(),
|
456
|
+
'last_collection': time.time()
|
457
|
+
}
|
458
|
+
logger.info("๐งน Cleared all strategy metrics")
|
459
|
+
|
460
|
+
|
461
|
+
# Global metrics collector instance
|
462
|
+
_metrics_collector: Optional[StrategyMetricsCollector] = None
|
463
|
+
_metrics_lock = threading.Lock()
|
464
|
+
|
465
|
+
|
466
|
+
def get_metrics_collector() -> StrategyMetricsCollector:
|
467
|
+
"""
|
468
|
+
Get the global metrics collector instance.
|
469
|
+
|
470
|
+
Returns:
|
471
|
+
Global StrategyMetricsCollector instance
|
472
|
+
"""
|
473
|
+
global _metrics_collector
|
474
|
+
|
475
|
+
if _metrics_collector is None:
|
476
|
+
with _metrics_lock:
|
477
|
+
if _metrics_collector is None:
|
478
|
+
_metrics_collector = StrategyMetricsCollector()
|
479
|
+
logger.info("๐ Initialized global strategy metrics collector")
|
480
|
+
|
481
|
+
return _metrics_collector
|
482
|
+
|
483
|
+
|
484
|
+
def collect_comprehensive_metrics() -> Dict[str, Any]:
|
485
|
+
"""
|
486
|
+
Collect comprehensive metrics using the global collector.
|
487
|
+
|
488
|
+
Returns:
|
489
|
+
Complete metrics dictionary
|
490
|
+
"""
|
491
|
+
return get_metrics_collector().collect_comprehensive_metrics()
|
492
|
+
|
493
|
+
|
494
|
+
def record_strategy_metric(
|
495
|
+
strategy_id: str,
|
496
|
+
strategy_name: str,
|
497
|
+
mode: Union[NodeMode, EdgeMode],
|
498
|
+
metric_type: MetricType,
|
499
|
+
value: float,
|
500
|
+
**metadata: Any
|
501
|
+
) -> None:
|
502
|
+
"""
|
503
|
+
Record a strategy metric using the global collector.
|
504
|
+
|
505
|
+
Args:
|
506
|
+
strategy_id: Strategy identifier
|
507
|
+
strategy_name: Strategy name
|
508
|
+
mode: Strategy mode
|
509
|
+
metric_type: Metric type
|
510
|
+
value: Metric value
|
511
|
+
**metadata: Additional metadata
|
512
|
+
"""
|
513
|
+
get_metrics_collector().record_strategy_metric(
|
514
|
+
strategy_id, strategy_name, mode, metric_type, value, **metadata
|
515
|
+
)
|
516
|
+
|
517
|
+
|
518
|
+
def get_metrics_summary() -> str:
|
519
|
+
"""
|
520
|
+
Get a formatted metrics summary.
|
521
|
+
|
522
|
+
Returns:
|
523
|
+
Human-readable metrics summary
|
524
|
+
"""
|
525
|
+
return get_metrics_collector().export_metrics('summary')
|
526
|
+
|
527
|
+
|
528
|
+
def export_metrics(format: str = 'json') -> Union[Dict[str, Any], str]:
|
529
|
+
"""
|
530
|
+
Export metrics in specified format.
|
531
|
+
|
532
|
+
Args:
|
533
|
+
format: Export format
|
534
|
+
|
535
|
+
Returns:
|
536
|
+
Exported metrics
|
537
|
+
"""
|
538
|
+
return get_metrics_collector().export_metrics(format)
|