skills/creating-dashboards/scripts/optimize-dashboard-performance.py

219 lines
7.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Dashboard Performance Optimizer
Analyzes dashboard configuration and provides optimization recommendations.
Usage:
python scripts/optimize-dashboard-performance.py --config dashboard.json
python scripts/optimize-dashboard-performance.py --widgets 12 --auto-refresh-count 8
"""
import argparse
import json
import sys
from typing import Dict, List, Any
def analyze_widget_count(num_widgets: int) -> List[str]:
"""Analyze widget count and provide recommendations"""
recommendations = []
if num_widgets > 20:
recommendations.append({
"severity": "high",
"issue": f"Too many widgets ({num_widgets})",
"recommendation": "Reduce to <20 widgets or use pagination/tabs",
"impact": "Slow initial render, high memory usage"
})
elif num_widgets > 12:
recommendations.append({
"severity": "medium",
"issue": f"Many widgets ({num_widgets})",
"recommendation": "Consider splitting into multiple dashboard pages",
"impact": "Moderate performance impact"
})
return recommendations
def analyze_refresh_rates(widgets: List[Dict]) -> List[str]:
"""Analyze refresh rates and auto-polling"""
recommendations = []
auto_refresh_widgets = [w for w in widgets if w.get('autoRefresh', False)]
if len(auto_refresh_widgets) > 10:
recommendations.append({
"severity": "high",
"issue": f"{len(auto_refresh_widgets)} widgets with auto-refresh",
"recommendation": "Reduce auto-refreshing widgets to <10. Use manual refresh or SSE.",
"impact": "High backend load, network congestion"
})
# Check refresh intervals
fast_refresh = [w for w in auto_refresh_widgets if w.get('refreshInterval', 30000) < 5000]
if fast_refresh:
recommendations.append({
"severity": "high",
"issue": f"{len(fast_refresh)} widgets refreshing <5 seconds",
"recommendation": "Increase refresh interval to >=5 seconds or use WebSocket/SSE",
"impact": "Excessive API calls, poor UX"
})
return recommendations
def analyze_data_fetching(widgets: List[Dict]) -> List[str]:
"""Analyze data fetching patterns"""
recommendations = []
# Check for N+1 queries
individual_fetches = [w for w in widgets if w.get('fetchMode') == 'individual']
if len(individual_fetches) > 5:
recommendations.append({
"severity": "medium",
"issue": f"{len(individual_fetches)} widgets with individual data fetching",
"recommendation": "Batch data fetching - single API call for all dashboard data",
"impact": "Multiple sequential API calls slow initial load"
})
# Check for heavy queries
heavy_widgets = [w for w in widgets if w.get('dataSize', 0) > 10000]
if heavy_widgets:
recommendations.append({
"severity": "medium",
"issue": f"{len(heavy_widgets)} widgets fetching large datasets (>10K rows)",
"recommendation": "Implement server-side pagination, aggregation, or caching",
"impact": "Large payload sizes, slow rendering"
})
return recommendations
def analyze_chart_complexity(widgets: List[Dict]) -> List[str]:
"""Analyze chart rendering complexity"""
recommendations = []
chart_widgets = [w for w in widgets if w.get('type', '').endswith('chart')]
large_charts = [w for w in chart_widgets if w.get('dataPoints', 0) > 1000]
if large_charts:
recommendations.append({
"severity": "medium",
"issue": f"{len(large_charts)} charts with >1000 data points",
"recommendation": "Downsample data (LTTB algorithm) or use virtualization",
"impact": "Slow chart rendering, laggy interactions"
})
return recommendations
def generate_recommendations(config: Dict[str, Any]) -> List[Dict]:
"""Generate all recommendations"""
all_recommendations = []
widgets = config.get('widgets', [])
num_widgets = len(widgets)
all_recommendations.extend(analyze_widget_count(num_widgets))
all_recommendations.extend(analyze_refresh_rates(widgets))
all_recommendations.extend(analyze_data_fetching(widgets))
all_recommendations.extend(analyze_chart_complexity(widgets))
return all_recommendations
def print_recommendations(recommendations: List[Dict]):
"""Print recommendations to console"""
if not recommendations:
print("✓ No performance issues detected!")
return
print("Dashboard Performance Analysis")
print("=" * 70)
# Group by severity
high = [r for r in recommendations if r['severity'] == 'high']
medium = [r for r in recommendations if r['severity'] == 'medium']
low = [r for r in recommendations if r['severity'] == 'low']
if high:
print(f"\n🔴 HIGH PRIORITY ({len(high)} issues)")
print("-" * 70)
for rec in high:
print(f"\nIssue: {rec['issue']}")
print(f"{rec['recommendation']}")
print(f" Impact: {rec['impact']}")
if medium:
print(f"\n🟡 MEDIUM PRIORITY ({len(medium)} issues)")
print("-" * 70)
for rec in medium:
print(f"\nIssue: {rec['issue']}")
print(f"{rec['recommendation']}")
print(f" Impact: {rec['impact']}")
if low:
print(f"\n🟢 LOW PRIORITY ({len(low)} issues)")
print("-" * 70)
for rec in low:
print(f"\nIssue: {rec['issue']}")
print(f"{rec['recommendation']}")
def main():
parser = argparse.ArgumentParser(description="Optimize dashboard performance")
parser.add_argument(
"--config",
help="Path to dashboard configuration JSON"
)
parser.add_argument(
"--widgets",
type=int,
help="Number of widgets (if not using config file)"
)
parser.add_argument(
"--auto-refresh-count",
type=int,
help="Number of auto-refreshing widgets"
)
args = parser.parse_args()
if args.config:
if not Path(args.config).exists():
print(f"Error: Config file not found: {args.config}", file=sys.stderr)
sys.exit(1)
with open(args.config, 'r') as f:
config = json.load(f)
else:
# Build config from CLI args
config = {
"widgets": [
{"id": f"widget-{i}", "autoRefresh": i < (args.auto_refresh_count or 0)}
for i in range(args.widgets or 0)
]
}
# Generate recommendations
recommendations = generate_recommendations(config)
# Print results
print_recommendations(recommendations)
# Exit with error if high-priority issues found
high_priority = [r for r in recommendations if r['severity'] == 'high']
if high_priority:
print(f"\n{len(high_priority)} high-priority performance issues found")
sys.exit(1)
else:
print("\n✓ Dashboard performance is acceptable")
sys.exit(0)
if __name__ == "__main__":
main()