【踩坑】解决运行一段时间GPU计算后忽然变得很慢

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn]

如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~


目录

发现问题

问题分析

修复思路

思路一

思路二

思路二对应代码


这个问题真的找了我好久,但说起来其实也简单,就是GPU温度太高了

问题复现视频演示:【踩坑】GPU运算使温度升高导致计算性能下降_哔哩哔哩_bilibili

发现问题

1、运行监控指令:

nvidia-smi dmon -i 00000000:41:00.0 -s pucvmet --gpm-metrics 10

2、运行你的代码,等到出问题。

3、看图就知道,密集的GPU运算,导致GPU温度达到限制了。高温限制是会影响性能的。

问题分析

本节内容来自:对于GPU显卡来说,多热算太热?

对于GPU来说,温度大致分为以下几个层次:

  • 60°C以下 - 低温,GPU性能基本未发挥。
  • 60-75°C - 正常工作温度,GPU性能发挥良好且寿命长。
  • 75-85°C - 开始偏热,但性能基本无影响,如果长时间在此范围可能缩短服务寿命。
  • 85-95°C - 极限工作温度,性能会受影响。如果长期工作在此温度就可能锁频下降性能。
  • 95°C以上 - 非常热乃至太热,此温度下GPU性能将受很大影响,极易发生故障或损坏元件。

一般来说:

  • 75°C以下算正常,保持这个度数(或更低)的温度应该可以让您安心,因为您的 GPU 正在发挥其最大潜力。
  • 75-85°C需要注意,保持通风以避免长期这样。
  • 85°C以上已经属于比较热了,需要改进散热或降低负荷。
  • 95°C以上就已经属于非常危险的热度域,需要立即采取措施降温。
  • 所以对GPU来说,75°C应该算做热的标准,85°C开始需要特别注意,95°C以上就可能导致不可恢复的损坏。

对GPU来说,长时间工作在85°C以上,会有以下影响:

  • 加速老化速度。高温环境下,GPU内各个组件如芯片封装材料、焊料连接等将会以更快的速度老化和失效。
  • 故障率增加。85°C及以上的高温会促进GPU内部各种微观装配和结构性问题的暴露,从而加大故障发生概率。
  • 缩短可用年限。85°C高温下,GPU将在5-7年内即达到其可用服务寿命极限,比常温使用寿命短1-3年。
  • 锁频降级性能。为保护内部元器件,85°C时GPU极有可能自动下调时钟频率来降温,导致长期性能下降。大多数现代显卡都具有固有的热保护机制,当其内部温度过高时,该机制会导致 GPU 节流。驱动程序采取的第一步是限制性能,以减少过热 GPU 的负载。尽管采取了这些措施,如果温度继续升高,系统将开始强制关闭。这通常可以防止对 GPU 造成任何物理损坏,但如果经常发生过热,永久性硬件损坏将是不可避免的。

        所以总体来说,如果GPU显卡长期工作在85°C以上高温,会明显缩短GPU的平均使用寿命,从1-3年不等,同时也影响其锁定频率和稳定性能输出,建议尽量降低和控制工作温度。

修复思路

思路一

来自对于GPU显卡来说,多热算太热?

        这里是一些建议,可以帮助降低GPU的工作温度:

  • 清除尘垢。定期清洁GPU风扇及散热片上积聚的灰尘,以保持散热效率。
  • 优化固件。检查显卡驱动是否为最新版本,更新可以改善电源管理降温。
  • 散热风扇速度。调整风扇转速提高冷风流量对GPU进行更有效的降温。
  • 流通散热。确保GPU周围有足够通风间隙,有助热空气迅速排出。
  • 改用散热板。更换散热更强的板后型显卡可以有效降温5-10°C。
  • 升级电源。GPU功耗大时需要足够功率输出的电源降温支持。
  • 温控软件。使用温控软件根据温度自动调整GPU时钟、风扇速度等。
  • 水冷模式。水冷传热效率高,能最大限度降低GPU温度。
  • 温度监测。实时了解GPU温曲线有助于查找问题热点进行改进。

        以上方法结合使用可以有效帮助控制GPU的工作温度,延长使用寿命。

思路二

        GPU的降温挺快的,不调用GPU运算,它的温度就会开始降低,因此可以考虑适当的降低GPU的连续使用时间。

思路二对应代码

        或者,可以在运行代码前,等待GPU的问题降低到一定的程度再执行。给个自己写的参考代码吧:

def check_gpu_temperatures(gpu_ids, temp_threshold=40, timeout=None):
    gpu_ids_list = gpu_ids.split(',')
    start_time = time.time()
    while True:
        temperatures = []
        all_below_threshold = True
        for gpu_id in gpu_ids_list:
            result = subprocess.run(['nvidia-smi', '-i', gpu_id, '--query-gpu=temperature.gpu', '--format=csv,noheader,nounits'], stdout=subprocess.PIPE)
            temp = int(result.stdout.decode('utf-8').strip())
            temperatures.append(f'GPU {gpu_id}: {temp}°')
            if temp > temp_threshold: all_below_threshold = False
        if all_below_threshold: 
            print('>> 当前GPU温度: ' + ' | '.join(temperatures))
            break
        print(f'>> 为防止GPU高温导致性能限制,等待降温中({temp_threshold}°): ' + ' | '.join(temperatures), end='\r')
        if timeout and (time.time() - start_time) > timeout:
            print('\n已达超时,不在等待 GPU 温度下降。')
            break
        time.sleep(1)
    print()

        用法:

gpus = '2,3,4'
check_gpu_temperatures(gpu_ids=gpus , temp_threshold=60, timeout=None)

        效果:

温度监控UI代码

        为了方便监控GPU的温度:

import sys
import subprocess
import threading
import time
import numpy as np
import tkinter as tk
from tkinter import ttk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class RealtimePlot:
    def __init__(self, parent, title, ylabel):
        self.fig = Figure(figsize=(5, 2), dpi=100)  # 设定图像尺寸
        self.ax = self.fig.add_subplot(111)
        self.ax.set_title(title)
        self.ax.set_ylabel(ylabel)
        self.ax.set_xlabel('Time')
        self.xdata = []
        self.ydata = []
        self.line, = self.ax.plot(self.xdata, self.ydata, 'r-')
        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

    def update_plot(self, y):
        self.xdata.append(time.time())
        self.ydata.append(y)
        if len(self.xdata) == 1:  # 防止 transformation singular 错误
            self.ax.set_xlim(self.xdata[0], self.xdata[0] + 1)
        else:
            self.ax.set_xlim(self.xdata[0], self.xdata[-1])
        self.line.set_xdata(self.xdata)
        self.line.set_ydata(self.ydata)
        self.ax.relim()
        self.ax.autoscale_view()
        self.canvas.draw()

    def resize(self, event):
        self.fig.set_size_inches(event.width / self.canvas.get_tk_widget().winfo_fpixels('1i'),
                                 event.height / self.canvas.get_tk_widget().winfo_fpixels('1i'))
        self.canvas.draw()

class GPU_MonitorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("nvidia-smi dmon Realtime Plot")

        self.plots = []
        gpu_ids = ['00000000:3d:00.0', '00000000:3e:00.0', '00000000:1D:00.0', '00000000:1E:00.0', '00000000:41:00.0']

        main_frame = tk.Frame(root)
        main_frame.pack(fill=tk.BOTH, expand=1)

        canvas = tk.Canvas(main_frame)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

        scrollbar_y = tk.Scrollbar(main_frame, orient=tk.VERTICAL, command=canvas.yview)
        scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)

        scrollbar_x = tk.Scrollbar(root, orient=tk.HORIZONTAL, command=canvas.xview)
        scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)

        canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))

        second_frame = tk.Frame(canvas)
        canvas.create_window((0, 0), window=second_frame, anchor="nw")

        plot_width = 500  # 每个图的宽度(以像素为单位)
        plot_height = 200  # 每个图的高度(以像素为单位)

        for i, gpu_id in enumerate(gpu_ids):
            frame = ttk.Frame(second_frame, width=plot_width * 2, height=plot_height)
            frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
            plot_power = RealtimePlot(frame, f"GPU {i} Power Usage", "Power (W)")
            plot_temp = RealtimePlot(frame, f"GPU {i} Temperature", "Temperature (C)")
            self.plots.append((plot_power, plot_temp))
            frame.bind("<Configure>", plot_power.resize)
            frame.bind("<Configure>", plot_temp.resize)

        # 计算窗口初始尺寸
        window_width = plot_width * 2 + 40  # 两个图表并排 + 滚动条和边距
        window_height = plot_height * len(gpu_ids) + 40  # 每个GPU占一行 + 滚动条和边距
        self.root.geometry(f"{window_width}x{window_height}")

        self.start_monitoring(gpu_ids)

    def start_monitoring(self, gpu_ids):
        self.monitor_thread = threading.Thread(target=self.monitor_gpu, args=(gpu_ids,))
        self.monitor_thread.daemon = True
        self.monitor_thread.start()

    def monitor_gpu(self, gpu_ids):
        command = ['nvidia-smi', 'dmon', '-i', ','.join(gpu_ids), '-s', 'pm']
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        skip_header = True  # 用于跳过表头
        for line in process.stdout:
            try:
                if skip_header:
                    if line.startswith('#'):
                        continue  # 跳过表头行
                    skip_header = False

                parts = line.split()
                if len(parts) == 0 or parts[0] == '#':
                    continue  # 跳过表头或空行
                if len(parts) >= 7 and parts[0].isdigit():  # 确保行数据完整
                    gpu_idx = int(parts[0])
                    if gpu_idx < len(gpu_ids):
                        gpu_power = float(parts[1]) if parts[1] != '-' else None
                        gpu_temp = float(parts[2]) if parts[2] != '-' else None

                        print(f"GPU {gpu_idx} power: {gpu_power}, temp: {gpu_temp}")  # Debug info

                        if gpu_power is not None:
                            self.plots[gpu_idx][0].update_plot(gpu_power)
                        if gpu_temp is not None:
                            self.plots[gpu_idx][1].update_plot(gpu_temp)
            except Exception as e:
                print(f"Error parsing line: {line}\n{e}")

if __name__ == '__main__':
    root = tk.Tk()
    app = GPU_MonitorApp(root)
    root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/712335.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JDK8-17新特性

一、JDK8新特性:Lambda表达式 1.Lambda表达式及其使用举例 Lambda是一个匿名函数&#xff0c;我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格&#xff0c;使Java的语言表达能力…

17个有用的CLI命令

作为前端开发工程师&#xff0c;我们需要了解哪些命令&#xff1f;如果您熟悉这些命令&#xff0c;它们将大大提高您的工作效率。 1. tree 你们知道如何列出一个目录的文件结构吗&#xff1f;它在显示文件之间的目录关系方面做得很好 commands ├── a.js ├── b.js ├── …

PyTorch计算机视觉入门:从官方数据集到自定义数据集的获取

一、PyTorch与计算机视觉简介 PyTorch是一个开源的深度学习框架&#xff0c;其动态图的特性非常适合快速实验和模型原型设计。在计算机视觉任务中&#xff0c;如图像分类、目标检测、图像分割等&#xff0c;PyTorch提供了丰富的API和预训练模型&#xff0c;帮助开发者快速搭建…

C++ 不定参数模版

使用不定参数模版遇到一个小问题&#xff0c;做个记录 测试代码如下&#xff1a; template<typename T, typename ...Args> void pushToVectorIfParamIsStr(std::vector<std::string>& vec, T &&value,Args&&... args) {const bool is std:…

大模型中的计算精度——FP32, FP16, bfp16之类的都是什么???

大模型中的计算精度——FP32, FP16, bfp16之类的都是什么&#xff1f;&#xff1f;&#xff1f; 这些精度是用来干嘛的&#xff1f;&#xff1f;混合精度 mixed precision training什么是混合精度&#xff1f;怎么转换呢&#xff1f; 为什么大语言模型通常使用FP32精度训练量化…

调试了一下午,终于把tailwindcss搞进Blazor了

在Vue和Uniapp项目中使用tailwindcss后&#xff0c;实在是太香了&#xff0c;非常符合我这从XAML走过来的老程序员的手感&#xff0c;所以老想着在Blazor项目中引入。看了几个老外大佬的视频&#xff0c;调试了一下午&#xff0c;终于是捣鼓成功了。由于咱们Blazor项目不在node…

【c语言】文件操作,解开你的疑惑

文件操作 为什么使用文件什么是文件文件的分类文件名 二进制文件和文本文件文件的打开与关闭流与标准流流标准流 文件指针文件的打开与关闭 文件的顺序读写文件的随机读写文件读取结束的判定文件缓冲区 为什么使用文件 我们程序运行的数据是运行在内存中的&#xff0c;当成程序…

链表经典题目:环形链表问题(LeetCode141.环形链表、LeetCode142.环形链表Ⅱ)

&#x1f4c7;文章目录 &#x1f4dc; LeetCode141. 环形链表&#x1f536;题目描述&#x1f537;思路分析✔️代码实现 &#x1f4dc; LeetCode142.环形链表Ⅱ&#x1f536;题目描述&#x1f537;思路①✔️代码实现&#x1f537;思路② &#x1f4d2;总结 &#x1f4dc; Leet…

神经网络学习2

张量&#xff08;Tensor&#xff09;是深度学习和科学计算中的基本数据结构&#xff0c;用于表示多维数组。张量可以看作是一个更广义的概念&#xff0c;涵盖了标量、向量、矩阵以及更高维度的数据结构。具体来说&#xff0c;张量的维度可以是以下几种形式&#xff1a; 标量&am…

RabbitMQ实践——利用一致性Hash交换器做负载均衡

大纲 开启一致性Hash交换器创建交换器创建绑定关系测试参考资料 在《RabbitMQ实践——交换器&#xff08;Exchange&#xff09;和绑定&#xff08;Banding&#xff09;》中&#xff0c;我们熟悉了Direct、Fanout、Topic和Header这4种系统默认支持的交换器。这些交换器基本可以满…

Django REST framework关联序列化器详解:掌握复杂关系的序列化与反序列化艺术

系列文章目录 Django入门全攻略&#xff1a;从零搭建你的第一个Web项目Django ORM入门指南&#xff1a;从概念到实践&#xff0c;掌握模型创建、迁移与视图操作Django ORM实战&#xff1a;模型字段与元选项配置&#xff0c;以及链式过滤与QF查询详解Django ORM深度游&#xff…

军事武器3D数字化交互展示创作平台大大降低成本

军事力量和装备是一个国家国防安全的重要支柱&#xff0c;这在全球范围内得到广泛认同&#xff0c;为了让入伍的新兵能快速熟悉和掌握武器装备操作流程&#xff0c;基于创新型的华锐3D云展平台工具&#xff0c;搭建的3D军事武器展示搭建编辑器&#xff0c;让部队的军事武器展示…

Golang——gRPC gateway网关

前言 etcd3 API全面升级为gRPC后&#xff0c;同时要提供REST API服务&#xff0c;维护两个版本的服务显然不大合理&#xff0c;所以gRPC-gateway诞生了。通过protobuf的自定义option实现了一个网关。服务端同时开启gRPC和HTTP服务&#xff0c;HTTP服务接收客户端请求后转换为gr…

Javaweb8 数据库Mybatis+JDBC

Mybatis Dao层&#xff0c;用于简化JDBC开发 1步中的实体类 int类型一般用Integer &#xff1a;如果用int类型 默认值为0,会影响数据的判断,用Integer默认值是null,不会给数据的判断造成干扰 2.在application .properties里配置数据库的链接信息-四要素 #驱动类名称 #URL #用…

Elasticsearch 认证模拟题 - 21

一、题目 写一个查询&#xff0c;要求查询 kibana_sample_data_ecommerce 索引&#xff0c;且 day_of_week、customer_gender、currency、type 这 4 个字段中至少两个以上。 1.1 考点 Boolean 1.2 答案 GET kibana_sample_data_ecommerce/_search {"query": {&q…

C-冒泡排序的循环条件应该怎么写

目录 一、冒泡排序的原理 二、代码实现 三、代码解读 1. 第一层循环条件怎么来的 2.第二层循环条件怎么来的 四、优化代码 我发现&#xff0c;好像还是有一部分同志&#xff0c;没有很清楚冒泡排序的两层循环条件为什么这么写&#xff1f; 感到有些模糊&#xff0c;但又可…

光照药物稳定性试验箱百科

概念与作用 - 药品稳定性试验箱&#xff1a;一种精密设备&#xff0c;用于模拟药品在不同环境条件下的存储情况。 - 环境模拟&#xff1a;通过控制温度、湿度等参数&#xff0c;复制各种实际储存条件&#xff0c;以测试药品稳定性。 - 保障药品质量&#xff1a;通过试验&…

Mybatis做批量操作

动态标签foreach&#xff0c;做过批量操作&#xff0c;但是foreach只能处理记录数不多的批量操作&#xff0c;数据量大了后&#xff0c;先不说效率&#xff0c;能不能成功操作都是问题&#xff0c;所以这里讲一讲Mybatis正确的批量操作方法&#xff1a; 在获取opensession对象…

conda安装pytorch使用清华源

原命令&#xff0c;例&#xff1a; # CUDA 11.3 conda install pytorch1.11.0 torchvision0.12.0 torchaudio0.11.0 cudatoolkit11.3 -c pytorch使用清华源&#xff0c;例&#xff1a; # CUDA 11.3 conda install pytorch1.11.0 torchvision0.12.0 torchaudio0.11.0 cudatool…

Win11 问题集

文章目录 一、Win11 选择其他应用打开无反应1、新建 1.reg 文件2、新建 2.reg 文件3、运行 reg 文件 二、Win11 账户怎么改名 一、Win11 选择其他应用打开无反应 Win11选择打开方式卡死怎么办? 选择打开方式没有反应的解决办法 1、新建 1.reg 文件 1.reg Windows Registry…