pandada / gpu_utils /gpu_stress.py
hulehule's picture
Upload folder gpu_utils
d289835 verified
Raw History Blame Contribute Delete
18.3 kB
'''
运行:
python gpu_utils/gpu_stress.py --target_utilization 0.8 --duration 4 --num_gpus 8
'''
import torch
import torch.nn as nn
import torch.nn.functional as F
import time
import threading
import argparse
import numpy as np
from typing import List, Dict
import psutil
import os
from concurrent.futures import ThreadPoolExecutor
import multiprocessing as mp
class H100StressTest:
def __init__(self, target_utilization: float = 0.5, num_gpus: int = None):
self.target_utilization = target_utilization
self.running = False
self.stats = {
'operations': 0,
'start_time': None,
'peak_memory': 0,
'avg_utilization': 0
}
# 检查GPU可用性并确定使用的GPU数量
if torch.cuda.is_available():
available_gpus = torch.cuda.device_count()
if num_gpus is None:
self.num_gpus = available_gpus
else:
self.num_gpus = min(num_gpus, available_gpus)
self.devices = [torch.device(f"cuda:{i}") for i in range(self.num_gpus)]
print(f"检测到 {available_gpus} 个GPU,使用 {self.num_gpus} 个GPU")
for i in range(self.num_gpus):
print(f"GPU {i}: {torch.cuda.get_device_name(i)}")
print(f"GPU {i} 内存: {torch.cuda.get_device_properties(i).total_memory / 1024**3:.1f} GB")
print(f"GPU {i} 计算能力: {torch.cuda.get_device_properties(i).major}.{torch.cuda.get_device_properties(i).minor}")
else:
raise RuntimeError("CUDA不可用,无法进行GPU压力测试")
def create_large_transformer_model(self, hidden_size: int = 4096, num_layers: int = 8, device: torch.device = None) -> nn.Module:
"""创建大型Transformer模型以充分利用H100"""
class LargeTransformer(nn.Module):
def __init__(self, hidden_size, num_layers):
super().__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
# 多层Transformer编码器
encoder_layer = nn.TransformerEncoderLayer(
d_model=hidden_size,
nhead=16, # 多头注意力
dim_feedforward=hidden_size * 4, # 前馈网络
dropout=0.1,
batch_first=True,
norm_first=True
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
# 额外的线性层
self.input_projection = nn.Linear(hidden_size, hidden_size)
self.output_projection = nn.Linear(hidden_size, hidden_size)
self.layer_norm = nn.LayerNorm(hidden_size)
def forward(self, x):
x = self.input_projection(x)
x = self.transformer(x)
x = self.layer_norm(x)
x = self.output_projection(x)
return x
if device is None:
device = self.devices[0]
model = LargeTransformer(hidden_size, num_layers).to(device)
return model.half() # 使用半精度以节省内存并提高性能
def create_convolutional_model(self, device: torch.device = None) -> nn.Module:
"""创建卷积神经网络模型"""
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 64, 3, padding=1)
self.conv2 = nn.Conv2d(64, 128, 3, padding=1)
self.conv3 = nn.Conv2d(128, 256, 3, padding=1)
self.conv4 = nn.Conv2d(256, 512, 3, padding=1)
self.conv5 = nn.Conv2d(512, 1024, 3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.adaptive_pool = nn.AdaptiveAvgPool2d((1, 1))
self.fc1 = nn.Linear(1024, 2048)
self.fc2 = nn.Linear(2048, 4096)
self.fc3 = nn.Linear(4096, 2048)
self.fc4 = nn.Linear(2048, 1024)
self.dropout = nn.Dropout(0.1)
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.pool(x)
x = F.relu(self.conv2(x))
x = self.pool(x)
x = F.relu(self.conv3(x))
x = self.pool(x)
x = F.relu(self.conv4(x))
x = self.pool(x)
x = F.relu(self.conv5(x))
x = self.adaptive_pool(x)
x = x.view(x.size(0), -1)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = F.relu(self.fc2(x))
x = self.dropout(x)
x = F.relu(self.fc3(x))
x = self.dropout(x)
x = self.fc4(x)
return x
if device is None:
device = self.devices[0]
model = ConvNet().to(device)
return model.half()
def matrix_operations_intensive(self, size: int = 8192, duration: float = 10.0, device: torch.device = None):
"""高强度矩阵运算"""
if device is None:
device = self.devices[0]
# 创建大矩阵
a = torch.randn(size, size, device=device, dtype=torch.float16)
b = torch.randn(size, size, device=device, dtype=torch.float16)
c = torch.randn(size, size, device=device, dtype=torch.float16)
start_time = time.time()
operations = 0
while time.time() - start_time < duration:
# 矩阵乘法链
result = torch.mm(a, b)
result = torch.mm(result, c)
result = torch.mm(result, a.transpose(0, 1))
# 矩阵求逆(小矩阵)
if size <= 2048:
try:
inv_result = torch.inverse(result[:min(1024, size), :min(1024, size)])
result = torch.mm(result, inv_result)
except:
pass
# 矩阵加法
result = result + b
result = result + c
# 矩阵转置
result = result.transpose(0, 1)
operations += 1
# 每100次操作同步一次
if operations % 100 == 0:
torch.cuda.synchronize(device)
return operations
def transformer_training_loop(self, model, optimizer, criterion, batch_size: int = 16, seq_length: int = 2048, device: torch.device = None):
"""Transformer训练循环"""
if device is None:
device = self.devices[0]
hidden_size = model.hidden_size
# 创建输入数据
x = torch.randn(batch_size, seq_length, hidden_size, device=device, dtype=torch.float16)
y = torch.randn(batch_size, seq_length, hidden_size, device=device, dtype=torch.float16)
# 前向传播
outputs = model(x)
loss = criterion(outputs, y)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
return loss.item()
def conv_training_loop(self, model, optimizer, criterion, batch_size: int = 32, device: torch.device = None):
"""卷积网络训练循环"""
if device is None:
device = self.devices[0]
# 创建输入数据
x = torch.randn(batch_size, 3, 224, 224, device=device, dtype=torch.float16)
y = torch.randn(batch_size, 1024, device=device, dtype=torch.float16)
# 前向传播
outputs = model(x)
loss = criterion(outputs, y)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
return loss.item()
def monitor_gpu_stats(self):
"""监控所有GPU统计信息"""
while self.running:
try:
total_allocated = 0
total_cached = 0
gpu_stats = []
# 获取所有GPU的内存使用情况
for i in range(self.num_gpus):
allocated = torch.cuda.memory_allocated(i) / 1024**3
cached = torch.cuda.memory_reserved(i) / 1024**3
total_allocated += allocated
total_cached += cached
gpu_stats.append((allocated, cached))
# 更新峰值内存
if total_allocated > self.stats['peak_memory']:
self.stats['peak_memory'] = total_allocated
# 每10秒打印一次状态
if self.stats['start_time'] and int(time.time() - self.stats['start_time']) % 10 == 0:
elapsed = time.time() - self.stats['start_time']
ops_per_sec = self.stats['operations'] / elapsed if elapsed > 0 else 0
print(f"[{elapsed:.0f}s] 操作数: {self.stats['operations']}, "
f"操作/秒: {ops_per_sec:.1f}")
print(f"总GPU内存: {total_allocated:.2f}GB/{total_cached:.2f}GB, "
f"峰值内存: {self.stats['peak_memory']:.2f}GB")
# 显示每个GPU的详细状态
for i, (allocated, cached) in enumerate(gpu_stats):
print(f" GPU {i}: {allocated:.2f}GB/{cached:.2f}GB")
time.sleep(1)
except Exception as e:
print(f"监控错误: {e}")
time.sleep(5)
def gpu_worker(self, gpu_id: int, duration_seconds: int, shared_stats: dict, stats_lock: threading.Lock):
"""单个GPU的工作线程"""
device = self.devices[gpu_id]
print(f"GPU {gpu_id} 开始工作...")
# 为每个GPU创建独立的模型
transformer_model = self.create_large_transformer_model(
hidden_size=4096, num_layers=12, device=device
)
transformer_optimizer = torch.optim.AdamW(
transformer_model.parameters(), lr=1e-4, weight_decay=0.01
)
transformer_criterion = nn.MSELoss()
conv_model = self.create_convolutional_model(device=device)
conv_optimizer = torch.optim.AdamW(
conv_model.parameters(), lr=1e-4, weight_decay=0.01
)
conv_criterion = nn.MSELoss()
# 预热GPU
for _ in range(5):
self.matrix_operations_intensive(size=4096, duration=1.0, device=device)
start_time = time.time()
local_operations = 0
cycle_count = 0
try:
while time.time() - start_time < duration_seconds:
cycle_count += 1
current_time = time.time() - start_time
# 每30秒轮换不同类型的操作
if int(current_time) % 30 < 10:
# 矩阵运算
ops = self.matrix_operations_intensive(size=8192, duration=8, device=device)
local_operations += ops
elif int(current_time) % 30 < 20:
# Transformer训练
for _ in range(5):
loss = self.transformer_training_loop(
transformer_model, transformer_optimizer, transformer_criterion,
batch_size=8, seq_length=2048, device=device
)
local_operations += 1
else:
# 卷积网络训练
for _ in range(10):
loss = self.conv_training_loop(
conv_model, conv_optimizer, conv_criterion,
batch_size=16, device=device
)
local_operations += 1
# 每100个周期清理一次缓存
if cycle_count % 100 == 0:
torch.cuda.empty_cache()
# 短暂休息以控制利用率
time.sleep(0.1)
except Exception as e:
print(f"GPU {gpu_id} 发生错误: {e}")
finally:
# 更新共享统计信息
with stats_lock:
shared_stats['operations'] += local_operations
print(f"GPU {gpu_id} 完成工作,操作数: {local_operations}")
def run_intensive_stress_test(self, duration_hours: float = 2.0):
"""运行多GPU高强度压力测试"""
duration_seconds = int(duration_hours * 3600)
print(f"开始多GPU高强度压力测试")
print(f"使用GPU数量: {self.num_gpus}")
print(f"目标利用率: {self.target_utilization*100:.1f}%")
print(f"持续时间: {duration_hours:.1f}小时 ({duration_seconds}秒)")
# 启动监控线程
self.running = True
self.stats['start_time'] = time.time()
monitor_thread = threading.Thread(target=self.monitor_gpu_stats)
monitor_thread.daemon = True
monitor_thread.start()
# 创建共享统计信息和锁
shared_stats = {'operations': 0}
stats_lock = threading.Lock()
# 使用线程池并行运行所有GPU
with ThreadPoolExecutor(max_workers=self.num_gpus) as executor:
# 为每个GPU提交任务
futures = []
for gpu_id in range(self.num_gpus):
future = executor.submit(
self.gpu_worker, gpu_id, duration_seconds, shared_stats, stats_lock
)
futures.append(future)
try:
# 等待所有任务完成
for future in futures:
future.result()
except KeyboardInterrupt:
print("\n用户中断测试")
# 取消所有未完成的任务
for future in futures:
future.cancel()
self.running = False
elapsed = time.time() - self.stats['start_time']
print(f"\n多GPU压力测试完成!")
print(f"总运行时间: {elapsed:.1f}秒 ({elapsed/3600:.2f}小时)")
print(f"总操作数: {shared_stats['operations']}")
print(f"平均操作/秒: {shared_stats['operations']/elapsed:.1f}")
print(f"峰值GPU内存使用: {self.stats['peak_memory']:.2f}GB")
def get_gpu_info(self):
"""获取所有GPU的详细信息"""
if torch.cuda.is_available():
print("=== 多GPU 详细信息 ===")
print(f"GPU数量: {torch.cuda.device_count()}")
print(f"使用GPU数量: {self.num_gpus}")
total_memory = 0
for i in range(self.num_gpus):
print(f"\n--- GPU {i} ---")
print(f"GPU名称: {torch.cuda.get_device_name(i)}")
props = torch.cuda.get_device_properties(i)
gpu_memory = props.total_memory / 1024**3
total_memory += gpu_memory
print(f"总内存: {gpu_memory:.1f} GB")
print(f"多处理器数量: {props.multi_processor_count}")
print(f"计算能力: {props.major}.{props.minor}")
# 安全获取可能不存在的属性
try:
print(f"最大线程数/块: {props.max_threads_per_block}")
except AttributeError:
print("最大线程数/块: 信息不可用")
try:
print(f"最大网格尺寸: {props.max_grid_size}")
except AttributeError:
print("最大网格尺寸: 信息不可用")
try:
print(f"共享内存/块: {props.shared_memory_per_block / 1024:.0f} KB")
except AttributeError:
print("共享内存/块: 信息不可用")
# 获取当前内存使用情况
allocated = torch.cuda.memory_allocated(i) / 1024**3
cached = torch.cuda.memory_reserved(i) / 1024**3
print(f"已分配内存: {allocated:.2f} GB")
print(f"缓存内存: {cached:.2f} GB")
print(f"可用内存: {gpu_memory - cached:.2f} GB")
print(f"\n总GPU内存: {total_memory:.1f} GB")
else:
print("CUDA不可用")
def main():
parser = argparse.ArgumentParser(description='多GPU高强度压力测试工具')
parser.add_argument('--duration', type=float, default=2.0,
help='测试持续时间(小时)')
parser.add_argument('--target_utilization', type=float, default=0.5,
help='目标GPU利用率(0-1)')
parser.add_argument('--num_gpus', type=int, default=None,
help='使用的GPU数量(默认使用所有可用GPU)')
parser.add_argument('--info_only', action='store_true',
help='只显示GPU信息,不进行测试')
args = parser.parse_args()
try:
# 创建压力测试实例
stress_test = H100StressTest(
target_utilization=args.target_utilization,
num_gpus=args.num_gpus
)
# 显示GPU信息
stress_test.get_gpu_info()
if args.info_only:
return
# 运行压力测试
stress_test.run_intensive_stress_test(duration_hours=args.duration)
except Exception as e:
print(f"错误: {e}")
return 1
if __name__ == "__main__":
exit(main())