python解析Linux top 系统信息并生成动态图表(pandas和matplotlib)

文章目录

    • 0. 引言
    • 1. 功能
    • 2.使用步骤
    • 3. 程序架构
        • 流程图
        • 结构图
    • 4. 数据解析模块
    • 5. 图表绘制模块
    • 6. 主程序入口
    • 7. 总结
    • 8. 附录完整代码

0. 引言

在性能调优和系统监控中,top 命令是一种重要工具,提供了实时的系统状态信息,如 CPU 使用率、内存使用情况和进程状态。然而,仅凭命令行输出可能无法满足复杂的分析需求。
本文将介绍如何解析 top 命令的输出,并利用 Python 生成动态图表,以更直观地展示系统性能数据。

1. 功能

  • 解析top 输出

    • 解析top -1 -H -b -n 1800 -d 1获取的进程信息,文本数据通过 pandas 库处理,并使用 matplotlib 生成动态图表。
    • 提取每个进程的 PID、用户、CPU 使用率、内存使用率、运行时间和命令信息。
  • 生成动态图表

    • 绘制系统总体内存使用情况的动态曲线(总内存、空闲内存、使用内存、缓存/缓冲区内存)。
    • 绘制指定进程或线程的 CPU 和内存使用情况的动态曲线。

2.使用步骤

  • dump top文本信息
    • 需要系统统计的设备中,使用如下命令获取top信息top -1 -H -b -n 1800 -d 1 > topdump.txt
      参数 -n 1800 指定了 top 命令执行的次数,即执行1800次。而参数 -d 1 则指定了每次执行之间的时间间隔为1秒,意味着 top 命令每隔1秒就会输出一次进程信息。

    • 注意:dump top信息时,请避免做其他操作以降低干扰。

  • 使用以下命令解析 top 输出文件并生成动态图表:

    python top_parser.py --file topdump.txt --process <process_name> --show_threads --save_fig
    
    • 参数说明:
      • --file:指定 top 输出文件的路径。
      • --process:指定要绘制的进程名称。
      • --show_threads:可选参数,显示进程内所有线程的详细信息。
      • --save_fig:可选参数,保存生成的图表为 PNG 图像文件。
  • 如下图是使用python topparser.py --file topdump.txt --process terminator --save_fig生成的:

python topparser.py --file topdump.txt --process terminator --save_fig生成的

3. 程序架构

本程序主要分为以下几个模块:

  • 数据解析模块:负责解析 top 命令的输出文本,并将提取的数据存储到 pandas 的数据帧中。

  • 图表绘制模块:基于解析得到的数据帧,使用 matplotlib 生成动态图表。

  • 主程序入口:处理命令行参数,调用数据解析模块和图表绘制模块完成数据处理和图表生成的流程。

流程图

流程图将展示数据解析模块、图表绘制模块和主程序入口之间的交互过程。以下是流程图的示意:

主程序入口
解析 `top` 输出文件
生成 `pandas` 数据帧
调用图表绘制模块
生成动态图表
显示或保存图表
结束
结构图

结构图将展示程序的整体架构,包括数据解析模块、图表绘制模块和主程序入口的功能组成及其关系。以下是结构图的示意:

主程序入口
解析 `top` 输出文件
图表绘制模块
处理命令行参数
解析 `top` 输出文本
生成 `pandas` 数据帧
绘制内存使用动态曲线
绘制进程线程动态曲线
时间轴处理
内存使用情况处理
进程线程动态曲线处理
绘制动态图表
存储信息

4. 数据解析模块

数据解析模块的主要任务是读取 top 命令的输出文件,识别其格式并提取出需要的性能指标和进程信息。以下是核心代码片段的部分实现:

# 数据解析模块核心代码示例
import pandas as pd
import redef parse_top_output(file_path):columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']data = {col: [] for col in columns}with open(file_path, 'r') as file:lines = file.readlines()timestamp = Noneformat_type = Nonefor line in lines:if line.startswith('top -'):timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)elif 'KiB Mem :' in line or 'GiB Mem :' in line:format_type = 'format1' if 'KiB Mem :' in line else 'format2'mem_info = re.findall(r'[\d\.]+', line)if format_type == 'format1':data['total_mem'].append(int(mem_info[0]))data['free_mem'].append(int(mem_info[1]))data['used_mem'].append(int(mem_info[2]))data['buff_cache_mem'].append(int(mem_info[3]))else:total_mem_gb = float(mem_info[0])data['total_mem'].append(total_mem_gb * 1024 * 1024)data['free_mem'].append(None)data['used_mem'].append(None)data['buff_cache_mem'].append(None)data['timestamp'].append(timestamp)data['pid'].append(None)data['user'].append(None)data['cpu'].append(None)data['mem'].append(None)data['time'].append(None)data['command'].append(None)elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):if format_type == 'format1':proc_info = re.split(r'\s+', line.strip(), maxsplit=11)data['pid'].append(int(proc_info[0]))data['user'].append(proc_info[1])data['cpu'].append(float(proc_info[8]))data['mem'].append(float(proc_info[9]))data['time'].append(proc_info[10])data['command'].append(proc_info[11] if len(proc_info) > 11 else "")elif format_type == 'format2':proc_info = re.split(r'\s+', line.strip(), maxsplit=10)data['pid'].append(int(proc_info[0]))data['user'].append(proc_info[1])try:cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])except ValueError:cpu_value = 0.0mem_value = 0.0data['cpu'].append(cpu_value)data['mem'].append(mem_value)data['time'].append(proc_info[7])data['command'].append(proc_info[9] if len(proc_info) > 9 else "")data['timestamp'].append(timestamp)data['total_mem'].append(None)data['free_mem'].append(None)data['used_mem'].append(None)data['buff_cache_mem'].append(None)else:data['timestamp'].append(timestamp)for key in data:if key not in ['timestamp']:data[key].append(None)df = pd.DataFrame(data)df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()return df

5. 图表绘制模块

图表绘制模块利用 matplotlib 库生成动态图表,以下是绘制内存使用动态曲线和进程线程动态曲线的核心代码片段:

# 图表绘制模块核心代码示例
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator, AutoLocatordef plot_memory_usage(ax, df, process_name=None):if 'relative_time' not in df.columns:print("relative_time column is missing in the dataframe")returnmemory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值for col in memory_cols:ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())ax.set_xlabel('Time (seconds)')ax.set_ylabel('Memory (KiB)')ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)ax.set_title('Memory Usage Over Time')if process_name:ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')ax.legend()ax.grid(True)ax.xaxis.set_major_locator(AutoLocator())ax.yaxis.set_major_locator(MaxNLocator(integer=True))return axdef plot_process_threads(ax, df, processes, show_threads, metric='cpu'):for process in processes:df_process = df[df['command'].str.contains(process, na=False)]if show_threads:unique_pids = df_process['pid'].unique()for pid in unique_pids:df_pid = df_process[df_process['pid'] == pid]ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')else:df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')ax.set_xlabel('Time (seconds)')ax.set_ylabel(f'{metric.upper()} Usage')ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')ax.legend()ax.grid(True)ax.xaxis.set_major_locator(AutoLocator())ax.yaxis.set_major_locator(MaxNLocator(integer=True))return ax

6. 主程序入口

主程序入口负责处理命令行参数,并调用数据解析和图表绘制模块完成数据处理和图表生成的流程。以下是主程序入口的核心代码片段:

# 主程序入口核心代码示例
import argparsedef main(file_path, processes, show_threads, save_fig=False):df = parse_top_output(file_path)plot_all(df, processes, show_threads, save_fig)if __name__ == "__main__":parser = argparse.ArgumentParser(description='Parse and plot top command output.')parser.add_argument('--file', type=str, required=True, help='Path to the top output file')parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')args = parser.parse_args()main(args.file, args.process, args.show_threads, args.save_fig)

7. 总结

通过本文介绍的方法,可以有效解析 top 命令输出并生成动态图表,帮助用户更直观地分析系统性能数据。该方法不仅支持不同格式的 top 输出,还能够灵活配置,满足各种监控需求。

8. 附录完整代码

import pandas as pd
import matplotlib.pyplot as plt
import re
import argparse
from matplotlib.ticker import MaxNLocator, AutoLocator# 解析top命令输出
def parse_top_output(file_path):columns = ['timestamp', 'total_mem', 'free_mem', 'used_mem', 'buff_cache_mem', 'pid', 'user', 'cpu', 'mem', 'time', 'command']data = {col: [] for col in columns}with open(file_path, 'r') as file:lines = file.readlines()timestamp = Noneformat_type = Nonefor line in lines:if line.startswith('top -'):timestamp = re.search(r'top - (\d+:\d+:\d+)', line).group(1)elif 'KiB Mem :' in line or 'GiB Mem :' in line:format_type = 'format1' if 'KiB Mem :' in line else 'format2'mem_info = re.findall(r'[\d\.]+', line)if format_type == 'format1':data['total_mem'].append(int(mem_info[0]))data['free_mem'].append(int(mem_info[1]))data['used_mem'].append(int(mem_info[2]))data['buff_cache_mem'].append(int(mem_info[3]))else:total_mem_gb = float(mem_info[0])data['total_mem'].append(total_mem_gb * 1024 * 1024)data['free_mem'].append(None)data['used_mem'].append(None)data['buff_cache_mem'].append(None)data['timestamp'].append(timestamp)data['pid'].append(None)data['user'].append(None)data['cpu'].append(None)data['mem'].append(None)data['time'].append(None)data['command'].append(None)elif re.match(r'\s*\d+', line) or re.match(r'\s*\d+\s+\w+', line):if format_type == 'format1':proc_info = re.split(r'\s+', line.strip(), maxsplit=11)data['pid'].append(int(proc_info[0]))data['user'].append(proc_info[1])data['cpu'].append(float(proc_info[8]))data['mem'].append(float(proc_info[9]))data['time'].append(proc_info[10])data['command'].append(proc_info[11] if len(proc_info) > 11 else "")elif format_type == 'format2':proc_info = re.split(r'\s+', line.strip(), maxsplit=10)data['pid'].append(int(proc_info[0]))data['user'].append(proc_info[1])try:cpu_value = float(proc_info[5].strip('%')) if '%' in proc_info[5] else float(proc_info[5])mem_value = float(proc_info[6].strip('%')) if '%' in proc_info[6] else float(proc_info[6])except ValueError:cpu_value = 0.0mem_value = 0.0data['cpu'].append(cpu_value)data['mem'].append(mem_value)data['time'].append(proc_info[7])data['command'].append(proc_info[9] if len(proc_info) > 9 else "")data['timestamp'].append(timestamp)data['total_mem'].append(None)data['free_mem'].append(None)data['used_mem'].append(None)data['buff_cache_mem'].append(None)else:data['timestamp'].append(timestamp)for key in data:if key not in ['timestamp']:data[key].append(None)df = pd.DataFrame(data)df['timestamp'] = pd.to_datetime(df['timestamp'], format='%H:%M:%S')df['relative_time'] = (df['timestamp'] - df['timestamp'].min()).dt.total_seconds()return df# 将时间戳转换为秒数
def convert_timestamp_to_seconds(timestamp):h, m, s = map(int, timestamp.split(':'))return h * 3600 + m * 60 + s# 绘制内存动态曲线
def plot_memory_usage(ax, df, process_name=None):if 'relative_time' not in df.columns:print("relative_time column is missing in the dataframe")returnmemory_cols = ['total_mem', 'free_mem', 'used_mem', 'buff_cache_mem']df_memory = df.dropna(subset=memory_cols).drop_duplicates(subset=['relative_time'])max_memory = df_memory[memory_cols].max().max()  # 获取内存使用的最大值for col in memory_cols:ax.plot(df_memory['relative_time'], df_memory[col], label=col.replace('_', ' ').title())ax.set_xlabel('Time (seconds)')ax.set_ylabel('Memory (KiB)')ax.set_ylim(0, max_memory * 1.1 if max_memory > 0 else 1)ax.set_title('Memory Usage Over Time')if process_name:ax.text(0.5, 0.5, process_name, transform=ax.transAxes, fontsize=20, ha='center', va='center', alpha=0.7, color='black')ax.legend()ax.grid(True)ax.xaxis.set_major_locator(AutoLocator())ax.yaxis.set_major_locator(MaxNLocator(integer=True))return ax# 绘制进程和线程动态曲线
def plot_process_threads(ax, df, processes, show_threads, metric='cpu'):for process in processes:df_process = df[df['command'].str.contains(process, na=False)]if show_threads:unique_pids = df_process['pid'].unique()for pid in unique_pids:df_pid = df_process[df_process['pid'] == pid]ax.plot(df_pid['relative_time'], df_pid[metric], label=f'{process} {metric.upper()} (PID {pid})')else:df_process_grouped = df_process.groupby('relative_time').agg({metric: 'sum'}).reset_index()ax.plot(df_process_grouped['relative_time'], df_process_grouped[metric], label=f'{process} (Total {metric.upper()})')ax.set_xlabel('Time (seconds)')ax.set_ylabel(f'{metric.upper()} Usage')ax.set_title(f'{metric.upper()} Usage of Processes and Threads Over Time')ax.legend()ax.grid(True)ax.xaxis.set_major_locator(AutoLocator())ax.yaxis.set_major_locator(MaxNLocator(integer=True))return ax# 绘制图表
def plot_all(df, processes, show_threads, save_fig=False):for process in processes:fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 12))df_process = df[df['command'].str.contains(process, na=False)]if show_threads:plot_process_threads(axes[0], df_process, [process], show_threads, metric='mem')plot_process_threads(axes[1], df_process, [process], show_threads, metric='cpu')else:plot_memory_usage(axes[0], df, process_name=process)plot_process_threads(axes[1], df, [process], show_threads)plt.tight_layout(pad=3.0)if save_fig:fig.savefig(f'{process}_analysis.png')  # 保存图像plt.show()# 主函数
def main(file_path, processes, show_threads, save_fig=False):df = parse_top_output(file_path)plot_all(df, processes, show_threads, save_fig)# 处理命令行参数
if __name__ == "__main__":parser = argparse.ArgumentParser(description='Parse and plot top command output.')parser.add_argument('--file', type=str, required=True, help='Path to the top output file')parser.add_argument('--process', type=str, nargs='+', required=True, help='List of processes to plot')parser.add_argument('--show_threads', action='store_true', help='Show CPU and memory for all threads within the process')parser.add_argument('--save_fig', action='store_true', help='Save the generated plots as PNG images')args = parser.parse_args()main(args.file, args.process, args.show_threads, args.save_fig)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0/1背包问题总结

文章目录 &#x1f347;什么是0/1背包问题&#xff1f;&#x1f348;例题&#x1f349;1.分割等和子集&#x1f349;2.目标和&#x1f349;3.最后一块石头的重量Ⅱ &#x1f34a;总结 博客主页&#xff1a;lyyyyrics &#x1f347;什么是0/1背包问题&#xff1f; 0/1背包问题是…

CFS三层内网渗透——第二层内网打点并拿下第三层内网(三)

目录 八哥cms的后台历史漏洞 配置socks代理 ​以我的kali为例,手动添加 socks配置好了&#xff0c;直接sqlmap跑 ​登录进后台 蚁剑配置socks代理 ​ 测试连接 ​编辑 成功上线 上传正向后门 生成正向后门 上传后门 ​内网信息收集 ​进入目标二内网机器&#xf…

小程序分包加载、独立分包、分包预加载等

一、小程序分包加载 小程序的代码通常是由许多页面、组件以及资源等组成&#xff0c;随着小程序功能的增加&#xff0c;代码量也会逐渐增加&#xff0c; 体积过大就会导致用户打开速度变慢&#xff0c;影响用户的使用体验。分包加载是一种小程序优化技术。将小程序不同功能的代…

【微信小程序开发实战项目】——花店微信小程序实战项目(4)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

Nginx的安装与配置 —— Linux系统

一、Nginx 简介 1.1 什么是 Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务…

Linux系统部署MongoDB开源文档型数据库并实现无公网IP远程访问

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 &#x1f4a1; 推荐 前些天发现了一个巨牛的人工智能学习网站&am…

现代农业利器:土壤检测仪器的应用与未来

在现代农业发展的浪潮中&#xff0c;土壤检测仪器以其精准、高效的特点&#xff0c;成为了农业生产的得力助手。这些看似不起眼的设备&#xff0c;实际上在保障农产品质量、提高农业生产效率方面发挥着举足轻重的作用。 一、土壤检测仪器&#xff1a;现代农业的“眼睛” 土壤检…

记录第一次写脚本

使用csh语言&#xff0c;Linux系统操作的 写和执行csh&#xff08;C Shell&#xff09;脚本不需要额外的软件&#xff0c;只需要一个支持csh的终端环境。 1.检查是否安装了C Shell 在终端terminal运行以下命令 which csh 如果返回路径&#xff0c;比如/bin/csh&#xff0c…

SpringBoot 启动流程六

SpringBoot启动流程六 这句话是创建一个上下文对象 就是最终返回的那个上下文 我们这个creatApplicationContext方法 是调用的这个方法 传入一个类型 我们通过打断点的方式 就可以看到context里面的东西 加载容器对象 当我们把依赖改成starter-web时 这个容器对象会进行…

STM32-HAL-FATFS(文件系统)(没做完,stm32f103zet6(有大佬的可以在评论区说一下次板子为什么挂载失败了))

1STM32Cube配置 1-1配置时钟 1-2配置调试端口 1-3配置uart 1-4配置SDIO&#xff08;注意参数&#xff09;&#xff08;其中他的初始化的异常函数给注释&#xff0c;SD卡文件写了&#xff09; 配置了还要打开中断和DMA可在我的其他文章中看一样的 1-5配置FatFs (只改了图选中…

QT c++函数模板与类模板的使用

QT c类模板的使用 #pragma once#include <QtWidgets/QMainWindow> #include "ui_QtWidgetsApplication5.h"class QtWidgetsApplication5 : public QMainWindow {Q_OBJECTpublic:QtWidgetsApplication5(QWidget *parent nullptr);~QtWidgetsApplication5();te…

Arthas实战(4)- 线程死锁问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段线程死锁的代码&#xff1a; GetMapping("/threadLock") public void threadLock() {Thread thread1 new Thread(() -> {synchronized (resource1) {System.out.println(Thread.currentThread().g…

Solution

(解决方案)可行性研究报告暨设计方案-zengwenfeng.doc 基本上都要300-500多页&#xff0c;大型【纯软件】&#xff0c;县级0-200万&#xff0c;市级项目500-1500万不等&#xff0c;省部级1000-10000万不等都有。本例为过往已完成项目案例目录结构。搞方案都要准备1-3个月呢。所…

房屋租赁管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;中介管理&#xff0c;房屋信息管理&#xff0c;房屋类型管理&#xff0c;租房订单管理&#xff0c;租房信息管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房屋信息&a…

极狐GitLab 将亮相2024空天信息大会暨数字地球生态峰会,携手中科星图赋能空天行业开发者

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

Django文档简化版——Django快速入门——创建一个基本的投票应用程序

Django快速入门——创建一个基本的投票应用程序 准备工作1、创建虚拟环境2、安装django 1、请求和响应&#xff08;1&#xff09;创建项目&#xff08;2&#xff09;用于开发的简易服务器&#xff08;3&#xff09;创建投票应用&#xff08;4&#xff09;编写第一个视图1、编写…

Qualcomm QCA206x EasyMesh For Ubuntu

1. 引言 关于EasyMesh概念我们这里就不再过多的赘述&#xff0c;此篇文档的目的是&#xff0c;让广大初学者&#xff0c;有一个很方便的平台进行EasyMesh的学习和测试。 2. X86 Ubuntu平台 2.1 硬件环境准备 备注&#xff1a;QCA206x WiFi module推荐使用移远的FC64E/FC66E。…

Mysql笔记-v2【7月5日更新】

零、 help、\h、? 调出帮助 mysql> \hFor information about MySQL products and services, visit:http://www.mysql.com/ For developer information, including the MySQL Reference Manual, visit:http://dev.mysql.com/ To buy MySQL Enterprise support, training, …

详解yolov5的网络结构

转载自文章 网络结构图&#xff08;简易版和详细版&#xff09; 此图是博主的老师&#xff0c;杜老师的图 网络框架介绍 前言&#xff1a; YOLOv5是一种基于轻量级卷积神经网络&#xff08;CNN&#xff09;的目标检测算法&#xff0c;整体可以分为三个部分&#xff0c; ba…

第十节:学习ConfigurationProperties类来配置pojo实体类参数(自学Spring boot 3.x的第二天)

大家好&#xff0c;我是网创有方 。这节记录下如何使用ConfigurationProperties来实现自动注入配置值。。实现将配置文件里的application.properties的参数赋值给实体类并且打印出来。 第一步&#xff1a;新建一个实体类WechatConfig package cn.wcyf.wcai.config;import org…