Coverage for simulator/data_loading.py: 99%
131 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
1"""
2Module for loading latency and power consumption data from CSV files.
3"""
5import pandas as pd
7from pathlib import Path
9from sim_types import LatencyData
10from sim_types import PowerData
11from sim_types import GPUType
12from sim_types import LatencyGPUTypeData
13from sim_types import PowerGPUTypeData
14from sim_types import QualityLevel
16from constants import NUM_PIXELS_ORIGINAL_UPSCALER
17from constants import NUM_PIXELS_ORIGINAL_FT
18from constants import NUM_PIXELS_ORIGINAL_HF
19from constants import NUM_PIXELS_ORIGINAL_FLUX
20from constants import NUM_PIXELS_LOW_FT
21from constants import NUM_PIXELS_LOW_HF
22from constants import NUM_PIXELS_LOW_FLUX
23from constants import NUM_PIXELS_LOW_UPSCALER
24from constants import NUM_PIXELS_MEDIUM_FT
25from constants import NUM_PIXELS_MEDIUM_HF
26from constants import NUM_PIXELS_MEDIUM_UPSCALER
27from constants import NUM_PIXELS_MEDIUM_FLUX
28from constants import POWER_GPU_IDLE
29from constants import POWER_GPU_TDP
31_DEFAULT_DATA_DIR = Path("data")
34def load_latency_data(
35 data_dir: str | Path = _DEFAULT_DATA_DIR,
36) -> LatencyData:
37 """
38 Load latency and throughput mapping data from CSV files.
40 Args:
41 data_dir: The directory where the CSV files are stored.
42 Returns:
43 LatencyData: An object containing all loaded latency data.
44 """
45 data_path = Path(data_dir)
47 data = LatencyData(gpus={})
48 for gpu_type in GPUType:
49 data.gpus[gpu_type] = LatencyGPUTypeData(gpu_type=gpu_type)
51 # Flux time -> per image generation
52 csv_flux_path = data_path / f"latency_flux_mapping_{gpu_type.value.lower()}.csv"
53 df_flux = pd.read_csv(csv_flux_path, comment='#')
54 data[gpu_type].flux = dict(zip(
55 df_flux["world_size"],
56 df_flux["avg_steps_time"]))
58 # Hunyuan Framepack per step time -> [36, 72, 108, 144, 324] frames generation
59 csv_hf_path = data_path / f"latency_hf_mapping_{gpu_type.value.lower()}.csv"
60 df_hf = pd.read_csv(csv_hf_path, comment='#')
61 data[gpu_type].hf = dict(zip(
62 df_hf["world_size"],
63 df_hf["avg_steps_time"]))
65 # Hunyuan Framepack VAE time -> per inference iteration
66 # Derived: steps * avg_step_time * vae_pct(vae_time / total_time)
67 data[gpu_type].hf_vae = dict(zip(
68 df_hf["world_size"],
69 df_hf["vae_time"]))
71 # Fantasy Talking per step time -> [9, 21, 41, 61, 77] frames generation
72 csv_ft_path = data_path / f"latency_ft_mapping_{gpu_type.value.lower()}.csv"
73 df_ft = pd.read_csv(csv_ft_path, comment='#')
74 data[gpu_type].ft = dict(zip(
75 df_ft["world_size"],
76 df_ft["avg_steps_time"]))
78 # Fantasy Talking VAE time -> per inference iteration
79 # Derived: steps * avg_step_time * vae_pct(vae_time / total_time)
80 data[gpu_type].ft_vae = dict(zip(
81 df_ft["world_size"],
82 df_ft["vae_time"]))
84 # Upscaler time -> per image frame
85 csv_upscaler_path = data_path / f"latency_upscaler_{gpu_type.value.lower()}.csv"
86 df_upscaler = pd.read_csv(csv_upscaler_path, comment='#')
87 data[gpu_type].upscaler = dict(zip(
88 df_upscaler['world_size'],
89 df_upscaler['avg_steps_time']))
91 # Gemma time -> first scene and per scene
92 csv_gemma_path = data_path / f"latency_gemma_{gpu_type.value.lower()}.csv"
93 df_gemma = pd.read_csv(csv_gemma_path, comment='#')
94 data[gpu_type].gemma_first_scene = dict(zip(
95 df_gemma['tp'],
96 df_gemma['first_scene_time']))
97 data[gpu_type].gemma_per_scene = dict(zip(
98 df_gemma['tp'],
99 df_gemma['per_scene_time']))
101 # Others time -> kokoro and other overheads -> time per scene
102 csv_others_path = data_path / f"latency_others_{gpu_type.value.lower()}.csv"
103 df_others = pd.read_csv(csv_others_path, comment='#')
104 data[gpu_type].others = dict(zip(
105 df_others['world_size'],
106 df_others['time']))
108 return data
111def load_power_data(
112 data_dir: str | Path = _DEFAULT_DATA_DIR
113) -> PowerData:
114 """
115 Load power consumption data from CSV files.
117 Args:
118 data_dir: The directory where the CSV files are stored.
119 Returns:
120 PowerData: An object containing all loaded power consumption data.
121 """
122 data_path = Path(data_dir)
124 data = PowerData(gpus={})
125 for gpu_type in GPUType:
126 data.gpus[gpu_type] = PowerGPUTypeData(gpu_type=gpu_type)
128 # Flux power profile
129 power_flux_file_name = data_path / f'power_flux_mapping_{gpu_type.value.lower()}.csv'
130 power_flux_df = pd.read_csv(power_flux_file_name, comment='#')
131 data[gpu_type].flux = dict(zip(
132 power_flux_df['world_size'],
133 power_flux_df['power_watts']))
135 # Hunyuan Framepack 640x400 power profile
136 power_hf_file_name = data_path / f'power_hf_mapping_{gpu_type.value.lower()}.csv'
137 power_hf_df = pd.read_csv(power_hf_file_name, comment='#')
138 data[gpu_type].hf = dict(zip(
139 power_hf_df['world_size'],
140 power_hf_df['power_watts']))
142 # Hunyuan Framepack 1280x800 power profile
143 power_hf_file_name_high = data_path / f'power_hf_mapping_{gpu_type.value.lower()}_high.csv'
144 power_hf_high_df = pd.read_csv(power_hf_file_name_high, comment='#')
145 data[gpu_type].hf_high = dict(zip(
146 power_hf_high_df['world_size'],
147 power_hf_high_df['power_watts']))
149 # Hunyuan Framepack VAE power profile
150 power_hf_vae_file_name = data_path / f'power_hf_vae_{gpu_type.value.lower()}.csv'
151 power_hf_vae_df = pd.read_csv(power_hf_vae_file_name, comment='#')
152 data[gpu_type].hf_vae = dict(zip(
153 power_hf_vae_df['world_size'],
154 power_hf_vae_df['power_watts']))
156 # Hunyuan Framepack VAE high power profile
157 power_hf_vae_high_file_name = data_path / f'power_hf_vae_{gpu_type.value.lower()}_high.csv'
158 power_hf_vae_high_df = pd.read_csv(power_hf_vae_high_file_name, comment='#')
159 data[gpu_type].hf_vae_high = dict(zip(
160 power_hf_vae_high_df['world_size'],
161 power_hf_vae_high_df['power_watts']))
163 # Fantasy Talking 640x400 power profile
164 power_ft_file_name = data_path / f'power_ft_mapping_{gpu_type.value.lower()}.csv'
165 power_ft_df = pd.read_csv(power_ft_file_name, comment='#')
166 data[gpu_type].ft = dict(zip(
167 power_ft_df['world_size'],
168 power_ft_df['power_watts']))
170 # Fantasy Talking 1280x800 power profile
171 power_ft_high_file_name = data_path / f'power_ft_mapping_{gpu_type.value.lower()}_high.csv'
172 power_ft_high_df = pd.read_csv(power_ft_high_file_name, comment='#')
173 data[gpu_type].ft_high = dict(zip(
174 power_ft_high_df['world_size'],
175 power_ft_high_df['power_watts']))
177 # Fantasy Talking VAE mapping
178 power_ft_vae_file_name = data_path / f'power_ft_vae_mapping_{gpu_type.value.lower()}.csv'
179 power_ft_vae_df = pd.read_csv(power_ft_vae_file_name, comment='#')
180 data[gpu_type].ft_vae = dict(zip(
181 power_ft_vae_df['world_size'],
182 power_ft_vae_df['power_watts']))
184 # Fantasy Talking VAE high mapping
185 power_ft_vae_high_file_name = data_path / f'power_ft_vae_mapping_{gpu_type.value.lower()}_high.csv'
186 power_ft_vae_high_df = pd.read_csv(power_ft_vae_high_file_name, comment='#')
187 data[gpu_type].ft_vae_high = dict(zip(
188 power_ft_vae_high_df['world_size'],
189 power_ft_vae_high_df['power_watts']))
191 # Upscaler power profile
192 power_upscaler_file_name = data_path / f'power_upscaler_{gpu_type.value.lower()}.csv'
193 power_upscaler_df = pd.read_csv(power_upscaler_file_name, comment='#')
194 data[gpu_type].upscaler = dict(zip(
195 power_upscaler_df['world_size'],
196 power_upscaler_df['power_watts']))
198 # Gemma power profile
199 power_gemma_first_scene_file_name = data_path / f'power_gemma_first_scene_{gpu_type.value.lower()}.csv'
200 power_gemma_per_scene_file_name = data_path / f'power_gemma_per_scene_{gpu_type.value.lower()}.csv'
201 power_gemma_first_scene_df = pd.read_csv(power_gemma_first_scene_file_name, comment='#')
202 power_gemma_per_scene_df = pd.read_csv(power_gemma_per_scene_file_name, comment='#')
203 data[gpu_type].gemma_first_scene = dict(zip(
204 power_gemma_first_scene_df['world_size'],
205 power_gemma_first_scene_df['power_watts']
206 ))
207 data[gpu_type].gemma_per_scene = dict(zip(
208 power_gemma_per_scene_df['world_size'],
209 power_gemma_per_scene_df['power_watts']
210 ))
212 # Idle and TDP power profiles
213 for gpu_type in GPUType:
214 data[gpu_type].idle = POWER_GPU_IDLE[gpu_type]
215 data[gpu_type].tdp = POWER_GPU_TDP[gpu_type]
217 return data
220def load_adaptive_quality_data(
221 data_dir: str | Path,
222 level: QualityLevel,
223) -> LatencyData:
224 """Load latency data for adaptive quality."""
225 assert isinstance(level, QualityLevel)
227 latency_data = load_latency_data(data_dir=data_dir)
229 if level == QualityLevel.ORIGINAL or level == QualityLevel.HIGH:
230 return latency_data
232 if level == QualityLevel.MEDIUM:
233 ratio_flux = NUM_PIXELS_MEDIUM_FLUX / NUM_PIXELS_ORIGINAL_FLUX
234 ratio_hf = NUM_PIXELS_MEDIUM_HF / NUM_PIXELS_ORIGINAL_HF
235 ratio_hf_vae = NUM_PIXELS_MEDIUM_HF / NUM_PIXELS_ORIGINAL_HF
236 ratio_ft = NUM_PIXELS_MEDIUM_FT / NUM_PIXELS_ORIGINAL_FT
237 ratio_ft_vae = NUM_PIXELS_MEDIUM_FT / NUM_PIXELS_ORIGINAL_FT
238 ratio_upscaler = NUM_PIXELS_MEDIUM_UPSCALER / NUM_PIXELS_ORIGINAL_UPSCALER
239 for gpu_type in GPUType:
240 latency_data[gpu_type].flux = {
241 k: v * ratio_flux
242 for k, v in latency_data[gpu_type].flux.items()
243 }
244 latency_data[gpu_type].hf = {
245 k: v * ratio_hf
246 for k, v in latency_data[gpu_type].hf.items()
247 }
248 latency_data[gpu_type].hf_vae = {
249 k: v * ratio_hf_vae
250 for k, v in latency_data[gpu_type].hf_vae.items()
251 }
252 latency_data[gpu_type].ft = {
253 k: v * ratio_ft
254 for k, v in latency_data[gpu_type].ft.items()
255 }
256 latency_data[gpu_type].ft_vae = {
257 k: v * ratio_ft_vae
258 for k, v in latency_data[gpu_type].ft_vae.items()
259 }
260 latency_data[gpu_type].upscaler = {
261 k: v * ratio_upscaler
262 for k, v in latency_data[gpu_type].upscaler.items()
263 }
264 return latency_data
266 if level == QualityLevel.LOW:
267 ratio_flux = NUM_PIXELS_LOW_FLUX / NUM_PIXELS_ORIGINAL_FLUX
268 ratio_hf = NUM_PIXELS_LOW_HF / NUM_PIXELS_ORIGINAL_HF
269 ratio_hf_vae = NUM_PIXELS_LOW_HF / NUM_PIXELS_ORIGINAL_HF
270 ratio_ft = NUM_PIXELS_LOW_FT / NUM_PIXELS_ORIGINAL_FT
271 ratio_ft_vae = NUM_PIXELS_LOW_FT / NUM_PIXELS_ORIGINAL_FT
272 ratio_upscaler = NUM_PIXELS_LOW_UPSCALER / NUM_PIXELS_ORIGINAL_UPSCALER
273 for gpu_type in GPUType:
274 latency_data[gpu_type].flux = {
275 k: v * ratio_flux
276 for k, v in latency_data[gpu_type].flux.items()
277 }
278 latency_data[gpu_type].hf = {
279 k: v * ratio_hf
280 for k, v in latency_data[gpu_type].hf.items()
281 }
282 latency_data[gpu_type].hf_vae = {
283 k: v * ratio_hf_vae
284 for k, v in latency_data[gpu_type].hf_vae.items()
285 }
286 latency_data[gpu_type].ft = {
287 k: v * ratio_ft
288 for k, v in latency_data[gpu_type].ft.items()
289 }
290 latency_data[gpu_type].ft_vae = {
291 k: v * ratio_ft_vae
292 for k, v in latency_data[gpu_type].ft_vae.items()
293 }
294 latency_data[gpu_type].upscaler = {
295 k: v * ratio_upscaler
296 for k, v in latency_data[gpu_type].upscaler.items()
297 }
298 return latency_data
300 return latency_data