Ubuntu触发硬件级系统重启

Ubuntu触发硬件级系统重启

  • [1. 挂载系统服务](#1. 挂载系统服务)
  • [2. 编写GPU状态监控](#2. 编写GPU状态监控)
  • [3. 编写重启函数](#3. 编写重启函数)
    • [3.1 启用内核硬件重启许可](#3.1 启用内核硬件重启许可)
    • [3.2 执行硬重启函数](#3.2 执行硬重启函数)
  • [4. 启用监控服务](#4. 启用监控服务)

因为一些至今尚未搞明白的神奇原因,RTX5090的显卡时不时就会在跑AI推理的时候挂掉(GPU lost),导致整个操作系统都在短时间内跟着一起挂掉。

在windows server上,这会导致整个操作系统自动关机重启,但是在Ubuntu上,这会导致显示器画面卡死在:

bash 复制代码
nvidia-modeset:ERROR:GPU:0:ERROR while waiting for GPU progres

使用的操作系统:Ubuntu24.04.3

Nvidia驱动:Driver Version: 580.95.05

到现在也不知道为什么会有这个显卡挂掉的问题【在同一台机器的windows server系统上同样会出现这个问题,而且更换了多个版本的驱动都存在,让我不得不怀疑硬件问题】,如果有人能知道可能的原因请麻烦告知一下。

但不论如何,目前的目的是让Ubuntu系统在显卡挂掉的情况下,能够全自动重启恢复。

经过研究,发现系统级的systemd服务在显示器画面已经爆炸的情况下其实还在正常工作,而进一步的研究发现,通过python的GPUtil.getGPUs()可以获取目前还在正常工作的显卡数量,如果这个数量低于正常水平,那么显而易见说明有显卡此时出现了故障掉线了。

这样解决思路就有了,基于在systemd服务中挂载一个root用户启动的python脚本,如果检测到GPU目前的工作数量低于正常水平(比如我的系统中应该是2张),那么就发出指令触发系统重启。

1. 挂载系统服务

在系统服务路径/etc/systemd/system/下,新建一个服务文件gpu_monitor.service

bash 复制代码
[Unit]
Description=gpu_monitor
After=network.target

[Service]
User=root
WorkingDirectory=/你的工程路径/gpu_monitor
ExecStart=/你的用户路径/anaconda3/envs/common/bin/python -u /你的工程路径/gpu_monitor.py
Restart=always

[Install]
WantedBy=multi-user.target

2. 编写GPU状态监控

编写python代码gpu_monitor.py监控GPU状态:

python 复制代码
import time
import GPUtil
import subprocess

# 正常情况下的GPU数量
NORMAL_GPU_NUM = 2
# 初始休眠,防止显卡无法恢复的情况下无限重启
INIT_SLEEP = 120
# 检测间隔
INTERVAL = 60

def reboot_system():
    pass # 系统重启逻辑

def main():
    gpu_num = len(GPUtil.getGPUs())
    print(f"Detect GPU num:{gpu_num}, init sleep until start monitor...")
    # 初始休眠,防止显卡无法恢复的情况下无限重启
    time.sleep(INIT_SLEEP)
    while True:
        try:
            gpu_num = len(GPUtil.getGPUs())
            if gpu_num < NORMAL_GPU_NUM:
                print(f"GPU lost! GPU num:{gpu_num}")
                reboot_system()
                # 重启命令执行后等待一段时间(防止程序提前退出)
                time.sleep(INTERVAL)
            else:
                print("GPU is ok!")
        except Exception as e:
            print(f"error: {e}")
        finally:
            time.sleep(INTERVAL)

if __name__ == "__main__":
    main()

3. 编写重启函数

对于如何重启恢复,尝试了很多办法,当然,思路都是基于python和root用户去运行重启命令。

但事实证明rebootshutdown这种软重启在log中能够自动恢复操作系统,但实际显示器上的画面依然停留在故障页面,因此,需要使用硬件层面的重启方式。

最后实验证明,需要使用基于sysrq-trigger的硬重启方式,才能完全恢复系统状态。

3.1 启用内核硬件重启许可

运行命令查看当前内核许可执行的权限:

bash 复制代码
cat /proc/sys/kernel/sysrq

发现默认输出为176

Linux 内核中 kernel.sysrq 的值是二进制位掩码(每一位对应一个 SysRq 功能),十进制值是所有开启位的数值之和。把 176 转换成二进制,对应的二进制:10110000

对应的权限中不包含重启(十进制2,二进制位序号1)的权限。

因此,如果需要在原本的基础上添加重启权限,则需要设置为176+2=178。

保险起见,不修改原文件,选择覆盖配置文件的参数配置方式:

bash 复制代码
sudo vim /etc/sysctl.d/99-sysrq-reboot.conf

添加行:

bash 复制代码
kernel.sysrq = 178

刷新配置:

bash 复制代码
sudo sysctl --system

查看当前配置:

bash 复制代码
sudo vim /etc/sysctl.d/99-sysrq-reboot.conf

发现在最下面已经多了kernel.sysrq = 178,这会覆盖前面相同名字的参数,此时内核已经允许执行硬件级别重启操作。

3.2 执行硬重启函数

重启对应的命令是b,即向/proc/sysrq-trigger写入b触发。

因此,对应的python函数代码为:

python 复制代码
def reboot_system():
    try:
        # 同步磁盘(避免数据丢失)
        print("同步磁盘数据到硬盘...")
        subprocess.run(["sync"], timeout=10, check=True)
    except subprocess.CalledProcessError as e:
        print(f"磁盘同步失败:{str(e)}")
    except subprocess.TimeoutExpired:
        print("磁盘同步超时,仍尝试重启...")
    except Exception as e:
        print(f"Sync失败:{str(e)}")

    try:
        # 写入b触发重启(硬件级)
        with open("/proc/sysrq-trigger", "w") as f:
            f.write("b")
        print("SysRq-b 重启指令已发送!系统即将重启...")

    except PermissionError:
        print("错误:无 root 权限写入 SysRq 相关文件!")
    except FileNotFoundError:
        print("错误:内核不支持 SysRq(CONFIG_MAGIC_SYSRQ 未开启)")
    except Exception as e:
        print(f"SysRq 重启失败:{str(e)}")

4. 启用监控服务

添加服务和开机自启动:

bash 复制代码
sudo systemctl daemon-reload
sudo systemctl enable gpu_monitor.service
sudo systemctl start gpu_monitor.service

此时,如果脚本检测到系统的GPU发生lost,就会自动重启计算机了。

相关推荐
dddddppppp1231 分钟前
linux head.s 从第一条指令到start_kernel
linux·运维·服务器
BioRunYiXue2 分钟前
AlphaGenome:DeepMind 新作,基因组学迎来 Alpha 时刻
java·linux·运维·网络·数据库·人工智能·eclipse
十五年专注C++开发3 分钟前
windows和linux使用system启动进程是一样的吗?
linux·c++·windows·system
此刻觐神6 分钟前
IMX6ULL开发板学习-04(Linux磁盘管理相关命令)
linux·运维·学习
wb18913 分钟前
docker-ce容器技术重习
运维·笔记·docker·容器·云计算
jiayong2313 分钟前
第 4 课:怎么把一个大页面拆成多个组件
运维·服务器·前端
qq_85730581916 分钟前
ubuntu 22 源码安装bochs
linux·运维·ubuntu
A-刘晨阳16 分钟前
麒麟v10桌面版2403版本运行程序提示权限不足(KYSEC)
运维·云计算·操作系统·银河麒麟·麒麟桌面系统
Zhu75816 分钟前
【软件更新】在Ubuntu24 LTS中更新openssl到指定版本,例如openssl3.5.6 LTS
linux·ssh·ssl
ALINX技术博客17 分钟前
【黑金云课堂】VMware Ubuntu 开发环境安装教程
linux·fpga开发·fpga