-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
Expand file tree
/
Copy pathtrend_tracker.py
More file actions
157 lines (124 loc) · 4.88 KB
/
trend_tracker.py
File metadata and controls
157 lines (124 loc) · 4.88 KB
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
"""TrendTracker - Encapsulated trend tracking for live profiling metrics.
This module provides trend tracking functionality for profiling metrics,
calculating direction indicators (up/down/stable) and managing associated
visual attributes like colors.
"""
import curses
from typing import Dict, Literal, Any
TrendDirection = Literal["up", "down", "stable"]
class TrendTracker:
"""
Tracks metric trends over time and provides visual indicators.
This class encapsulates all logic for:
- Tracking previous values of metrics
- Calculating trend directions (up/down/stable)
- Determining visual attributes (colors) for trends
- Managing enable/disable state
Example:
tracker = TrendTracker(colors_dict)
tracker.update("func1", "nsamples", 10)
trend = tracker.get_trend("func1", "nsamples")
color = tracker.get_color("func1", "nsamples")
"""
# Threshold for determining if a value has changed significantly
CHANGE_THRESHOLD = 0.001
def __init__(self, colors: Dict[str, int], enabled: bool = True):
"""
Initialize the trend tracker.
Args:
colors: Dictionary containing color attributes including
'trend_up', 'trend_down', 'trend_stable'
enabled: Whether trend tracking is initially enabled
"""
self._previous_values: Dict[Any, Dict[str, float]] = {}
self._enabled = enabled
self._colors = colors
@property
def enabled(self) -> bool:
"""Whether trend tracking is enabled."""
return self._enabled
def toggle(self) -> bool:
"""
Toggle trend tracking on/off.
Returns:
New enabled state
"""
self._enabled = not self._enabled
return self._enabled
def set_enabled(self, enabled: bool) -> None:
"""Set trend tracking enabled state."""
self._enabled = enabled
def update(self, key: Any, metric: str, value: float) -> TrendDirection:
"""
Update a metric value and calculate its trend.
Args:
key: Identifier for the entity (e.g., function)
metric: Name of the metric (e.g., 'nsamples', 'tottime')
value: Current value of the metric
Returns:
Trend direction: 'up', 'down', or 'stable'
"""
# Initialize storage for this key if needed
if key not in self._previous_values:
self._previous_values[key] = {}
# Get previous value, defaulting to current if not tracked yet
prev_value = self._previous_values[key].get(metric, value)
# Calculate trend
if value > prev_value + self.CHANGE_THRESHOLD:
trend = "up"
elif value < prev_value - self.CHANGE_THRESHOLD:
trend = "down"
else:
trend = "stable"
# Update previous value for next iteration
self._previous_values[key][metric] = value
return trend
def get_trend(self, key: Any, metric: str) -> TrendDirection:
"""
Get the current trend for a metric without updating.
Args:
key: Identifier for the entity
metric: Name of the metric
Returns:
Trend direction, or 'stable' if not tracked
"""
# This would require storing trends separately, which we don't do
# For now, return stable if not found
return "stable"
def get_color(self, trend: TrendDirection) -> int:
"""
Get the color attribute for a trend direction.
Args:
trend: The trend direction
Returns:
Curses color attribute (or A_NORMAL if disabled)
"""
if not self._enabled:
return curses.A_NORMAL
if trend == "up":
return self._colors.get("trend_up", curses.A_BOLD)
elif trend == "down":
return self._colors.get("trend_down", curses.A_BOLD)
else: # stable
return self._colors.get("trend_stable", curses.A_NORMAL)
def update_metrics(self, key: Any, metrics: Dict[str, float]) -> Dict[str, TrendDirection]:
"""
Update multiple metrics at once and get their trends.
Args:
key: Identifier for the entity
metrics: Dictionary of metric_name -> value
Returns:
Dictionary of metric_name -> trend_direction
"""
trends = {}
for metric, value in metrics.items():
trends[metric] = self.update(key, metric, value)
return trends
def clear(self) -> None:
"""Clear all tracked values (useful on stats reset)."""
self._previous_values.clear()
def __repr__(self) -> str:
"""String representation for debugging."""
status = "enabled" if self._enabled else "disabled"
tracked = len(self._previous_values)
return f"TrendTracker({status}, tracking {tracked} entities)"