File size: 7,465 Bytes
f0e2e50 db43315 f0e2e50 206fb7a 722a506 206fb7a 722a506 f0e2e50 722a506 206fb7a 722a506 206fb7a 722a506 db43315 206fb7a db43315 206fb7a db43315 206fb7a db43315 |
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 |
"""
Performance optimization utilities for Manim rendering
"""
import re
from typing import Dict, Tuple
class PerformanceOptimizer:
"""Optimize rendering performance and resource usage"""
# Quality settings for different performance levels
QUALITY_SETTINGS = {
"low_quality": {
"flag": "-ql",
"description": "Low Quality (Fast)",
"resolution": "480p",
"fps": 30,
"max_duration": 10,
"max_objects": 20,
"performance_threshold": {
"render_time": 60, # seconds
"memory_usage": 1024 # MB
}
},
"medium_quality": {
"flag": "-qm",
"description": "Medium Quality (Balanced)",
"resolution": "720p",
"fps": 30,
"max_duration": 15,
"max_objects": 30,
"performance_threshold": {
"render_time": 180, # seconds
"memory_usage": 2048 # MB
}
}
}
# Performance thresholds
PERFORMANCE_THRESHOLDS = {
"render_time": 300, # seconds
"memory_usage": 4096, # MB
"cpu_usage": 80 # percentage
}
@classmethod
def estimate_render_time(cls, quality: str, complexity: str = "medium") -> int:
"""Estimate rendering time in seconds"""
base_times = {
"low_quality": 30,
"medium_quality": 60,
"high_quality": 120,
"production_quality": 300
}
complexity_multipliers = {
"simple": 0.5,
"medium": 1.0,
"complex": 2.0,
"very_complex": 3.0
}
base_time = base_times.get(quality, 60)
multiplier = complexity_multipliers.get(complexity, 1.0)
return int(base_time * multiplier)
@classmethod
def analyze_code_complexity(cls, code: str) -> str:
"""Analyze code complexity to estimate render time"""
complexity_indicators = {
"simple": ["Text", "Write", "Create"],
"medium": ["Transform", "FadeIn", "FadeOut", "MoveTo"],
"complex": ["Axes", "plot", "FunctionGraph", "BarChart"],
"very_complex": ["ThreeDScene", "rotate", "complex", "integral"]
}
code_lower = code.lower()
scores = {"simple": 0, "medium": 0, "complex": 0, "very_complex": 0}
for complexity, indicators in complexity_indicators.items():
for indicator in indicators:
scores[complexity] += code_lower.count(indicator.lower())
# Determine overall complexity
max_score = max(scores.values())
if max_score == 0:
return "simple"
return max(scores, key=scores.get)
@classmethod
def get_recommended_quality(cls, prompt_length: int, has_complex_math: bool) -> str:
"""Recommend quality based on prompt complexity"""
if prompt_length < 50 and not has_complex_math:
return "medium_quality"
elif prompt_length < 100:
return "medium_quality"
else:
return "low_quality" # Start with lower quality for complex animations
@classmethod
def optimize_code_for_performance(cls, code: str) -> str:
"""Optimize Manim code for better performance"""
optimized_code = code
# Limit excessive wait times
optimized_code = re.sub(r'self\.wait\((\d+)\)',
lambda m: f'self.wait({min(int(m.group(1)), 3)})',
optimized_code)
# Optimize animation run times
optimized_code = re.sub(r'run_time=(\d+)',
lambda m: f'run_time={min(int(m.group(1)), 5)}',
optimized_code)
# Add performance hints as comments
performance_hints = [
"# Performance optimized: Limited wait times to 3 seconds max",
"# Performance optimized: Limited animation run times to 5 seconds max"
]
if any(hint.split(": ")[1] in optimized_code for hint in performance_hints):
optimized_code = "\n".join(performance_hints) + "\n" + optimized_code
return optimized_code
@classmethod
def get_memory_efficient_settings(cls) -> Dict[str, str]:
"""Get settings for memory-efficient rendering"""
return {
"preview": True,
"disable_caching": True,
"low_quality": True,
"save_last_frame": False,
"write_to_movie": True
}
@classmethod
def calculate_estimated_file_size(cls, quality: str, duration: int = 10) -> Tuple[float, str]:
"""Calculate estimated output file size in MB"""
# Rough estimates based on quality settings
bitrate_estimates = {
"low_quality": 1.0, # MB per minute
"medium_quality": 3.0,
"high_quality": 8.0,
"production_quality": 25.0
}
bitrate = bitrate_estimates.get(quality, 3.0)
size_mb = (bitrate * duration) / 60 # Convert to actual duration
if size_mb < 1:
return size_mb * 1024, "KB"
else:
return size_mb, "MB"
@classmethod
def get_optimization_tips(cls, quality: str, complexity: str) -> list:
"""Get optimization tips based on settings"""
tips = []
if quality in ["high_quality", "production_quality"]:
tips.append("Consider using medium quality for faster rendering during development")
if complexity in ["complex", "very_complex"]:
tips.append("Break complex animations into smaller scenes for easier debugging")
tips.append("Use preview mode (-p flag) to quickly test animations")
tips.append("Close other applications to free up system resources")
tips.append("Ensure sufficient disk space for temporary files")
return tips
def optimize_quality(self, available_memory: float, estimated_render_time: float) -> str:
if available_memory < self.PERFORMANCE_THRESHOLDS["memory_usage"]:
return "low_quality"
if estimated_render_time > self.PERFORMANCE_THRESHOLDS["render_time"]:
return "low_quality"
return "medium_quality"
@staticmethod
def estimate_render_time(quality_level: str) -> int:
"""Estimate render time based on quality level"""
return PerformanceOptimizer.QUALITY_SETTINGS[quality_level]["performance_threshold"]["render_time"]
@staticmethod
def get_quality_settings(quality_level: str) -> dict:
"""Get quality settings for the specified level"""
return PerformanceOptimizer.QUALITY_SETTINGS[quality_level]
@staticmethod
def optimize_for_performance(quality_level: str, scene_complexity: int) -> dict:
"""Optimize settings based on quality level and scene complexity"""
settings = PerformanceOptimizer.QUALITY_SETTINGS[quality_level].copy()
# Adjust settings based on scene complexity
if scene_complexity > settings["max_objects"]:
settings["max_objects"] = min(scene_complexity, settings["max_objects"] * 2)
return settings |