jiyuhang 3 месяцев назад
Родитель
Сommit
5b78732b9e

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 32 - 18
main.sh

@@ -13,12 +13,14 @@ RESULT_DIR="results"
 TEST_SCRIPT=""  # 待测试的脚本
 PSUTIL_SCRIPT="monitor_util.py"  # 监测工具脚本
 INTEGRATED_SCRIPT="integrate_results.py"  # 融合工具脚本
+PLOT_SCRIPT="plot.py"  # 画图工具脚本
 CPROFILE_OUTPUT="$RESULT_DIR/cprofile_output.prof"  # cProfile 结果文件
 MEMORY_PROFILE_OUTPUT="$RESULT_DIR/mprofile_output.dat"  # memory_profiler输出文件
 MEMORY_PLOT_OUTPUT="$RESULT_DIR/mprofile_memory_plot.png"  # memory_profiler 绘制的曲线图
 FLAMEGRAPH_OUTPUT="$RESULT_DIR/pyspy_output.svg"  # py-spy 输出文件
 PSUTIL_OUTPUT="$RESULT_DIR/psutil_output.csv"  # psutil 输出文件
 INTEGRATED_REPORT="$RESULT_DIR/performance_analysis_report.json"  # 融合结果文件
+INTEGRATED_PLOT="$RESULT_DIR/performance_analysis_report.png"  # 融合结果图
 
 # 日志函数
 log_info() {
@@ -98,12 +100,11 @@ mk_dir(){
 run_cprofile() {
     show_step "步骤 1: 使用 cProfile 进行性能分析"
     log_info "准备对 $TEST_SCRIPT 进行性能分析..."
-    
-    # 确保使用绝对路径
-    PROFILE_ABS_PATH="$(pwd)/$CPROFILE_OUTPUT"
-    
-    if python -m cProfile -o "$PROFILE_ABS_PATH" "$TEST_SCRIPT"; then
-        log_success "cProfile 分析完成,结果保存至 $PROFILE_ABS_PATH"
+
+    # 将之前的结果删除
+    rm -rf "$CPROFILE_OUTPUT"
+    if python -m cProfile -o "$CPROFILE_OUTPUT" "$TEST_SCRIPT"; then
+        log_success "cProfile 分析完成,结果保存至 $CPROFILE_OUTPUT"
         return 0
     else
         log_error "cProfile 分析失败"
@@ -127,7 +128,8 @@ run_memory_profiler() {
             return 1
         fi
     fi
-
+    # 将之前的结果删除
+    rm -rf "$MEMORY_PROFILE_OUTPUT"
     # 运行内存分析
     if command -v mprof &> /dev/null; then
         if mprof run --output "$MEMORY_PROFILE_OUTPUT" "$TEST_SCRIPT"; then
@@ -168,7 +170,8 @@ run_py_spy() {
         log_error "py-spy 安装失败"
         return 1
     fi
-
+    # 删除之前的结果
+    rm -rf "$FLAMEGRAPH_OUTPUT"
     # 根据操作系统类型选择合适的py-spy参数,需要统计子线程和C拓展
     if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
         # Windows环境下使用--nonblocking选项
@@ -211,7 +214,8 @@ run_psutil() {
       return 1
     fi
   fi
-
+  # 将之前的结果文件删除
+  rm -rf "$PSUTIL_OUTPUT"
   # 在后台运行test_script.py并获取其PID
   log_info "在后台启动 $TEST_SCRIPT ..."
   python "$TEST_SCRIPT" &
@@ -334,37 +338,30 @@ integrate_all_results(){
   show_step "步骤5 整合所有分析结果"
 
   # 检查python脚本是否存在
-
   if [ ! -f "$INTEGRATED_SCRIPT" ]; then
      log_warning "整合脚本 $INTEGRATED_SCRIPT 不存在"
      return 1
   else
     echo "结果整合中..."
-     # 构建命令参数
+    # 构建命令参数
     CMD="python $INTEGRATED_SCRIPT"
-
     if [ -f "$CPROFILE_OUTPUT" ]; then
         CMD="$CMD --cprofile $CPROFILE_OUTPUT"
     fi
-
     if [ -f "$MEMORY_PROFILE_OUTPUT" ]; then
         CMD="$CMD --memory $MEMORY_PROFILE_OUTPUT"
     fi
-
     if [ -f "$FLAMEGRAPH_OUTPUT" ]; then
         CMD="$CMD --flamegraph $FLAMEGRAPH_OUTPUT"
     fi
-
     if [ -f "$PSUTIL_OUTPUT" ]; then
         CMD="$CMD --psutil $PSUTIL_OUTPUT"
     fi
-
     CMD="$CMD --output $INTEGRATED_REPORT"
      # 执行整合脚本
     log_info "执行整合命令: $CMD"
     if eval "$CMD"; then
         log_success "所有分析结果已整合至 $INTEGRATED_REPORT"
-        return 0
     else
         log_error "整合过程出错"
         # 检查pandas是否存在
@@ -379,12 +376,29 @@ integrate_all_results(){
            # 尝试再次执行命令
            if eval "$CMD"; then
               log_success "所有分析结果已整合至 $INTEGRATED_REPORT"
-              return 0
+           else
+             log_error "无法执行整合命令"
+             return 1
            fi
+        else
+           return 1
         fi
+    fi
+    # 绘制融合结果图
+    if [ -f "$PLOT_SCRIPT" ]; then
+      log_info "绘制融合结果图"
+      if python "$PLOT_SCRIPT" --input "$INTEGRATED_REPORT" --output "$INTEGRATED_PLOT"; then
+        log_success "融合结果图已保存至 $INTEGRATED_PLOT"
+      else
+        log_error "无法绘制融合结果图"
         return 1
+      fi
+    else
+       log_warning "未找到绘制脚本 $PLOT_SCRIPT"
+       return 1
     fi
   fi
+  return 0
 }
 
 

+ 11 - 6
monitor_util.py

@@ -146,13 +146,18 @@ class Monitor:
                         time.sleep(interval)
                 except Exception as e:
                     break
-
-
-if __name__ == "__main__":
+def main():
     import argparse
     parser = argparse.ArgumentParser(description='Py进程监视器')
-    parser.add_argument('--pid', '-p', type=int, required=True , help='请输入需要监控的进程id')
-    parser.add_argument('--output', '-o', type=str, required=True , help='请输入需要监控的进程id')
+    parser.add_argument('--pid', '-p', type=int, required=True, help='请输入需要监控的进程id')
+    parser.add_argument('--output', '-o', type=str, required=True, help='请输入需要监控的进程id')
     args = parser.parse_args()
+    # 删除已经存在的结果
+    if os.path.exists(args.output):
+        print(f'删除已经存在的结果:{args.output}')
+        os.remove(args.output)
     m = Monitor(args.pid)
-    m.start(output_file=args.output)
+    m.start(output_file=args.output)
+
+if __name__ == "__main__":
+    main()

+ 361 - 88
plot.py

@@ -1,13 +1,87 @@
 import json
 import argparse
+import os.path
+import platform
+import matplotlib
+# 设置后端以避免GUI相关问题
+matplotlib.use('Agg')
 import matplotlib.pyplot as plt
 import numpy as np
 from datetime import datetime
 from matplotlib.font_manager import FontProperties
+from matplotlib.patches import Rectangle
+import matplotlib.patches as mpatches
 
-# 设置中文字体支持
-plt.rcParams['font.sans-serif'] = ['SimHei', 'FangSong', 'Arial Unicode MS']
-plt.rcParams['axes.unicode_minus'] = False
+# 设置更现代化的matplotlib样式
+try:
+    plt.style.use('seaborn-v0_8-whitegrid')
+except:
+    try:
+        plt.style.use('seaborn-whitegrid')
+    except:
+        pass  # 如果都没有,使用默认样式
+
+# 定义常量
+TOP_FUNCTION_COUNT = 15  # 显示的函数数量
+
+def setup_chinese_font_support():
+    """根据操作系统环境设置中文字体支持"""
+    system = platform.system().lower()
+    
+    if system == 'windows':
+        # Windows系统字体设置
+        plt.rcParams['font.sans-serif'] = ['SimHei', 'FangSong', 'Arial Unicode MS']
+        plt.rcParams['axes.unicode_minus'] = False
+
+    elif system == 'linux':
+        # 检查是否在WSL环境中
+        try:
+            with open('/proc/version', 'r') as f:
+                version_info = f.read().lower()
+                is_wsl = 'microsoft' in version_info or 'wsl' in version_info
+        except:
+            is_wsl = False
+            
+        if is_wsl:
+            # WSL环境下的字体设置
+            # 尝试使用Windows字体目录中的字体
+            possible_fonts = [
+                '/mnt/c/Windows/Fonts/msyh.ttc',     # 微软雅黑
+                '/mnt/c/Windows/Fonts/simsun.ttc',   # 宋体
+                '/mnt/c/Windows/Fonts/simhei.ttf',   # 黑体
+            ]
+            
+            # 查找可用的中文字体
+            available_fonts = []
+            for font_path in possible_fonts:
+                if os.path.exists(font_path):
+                    available_fonts.append(font_path)
+            
+            # 如果找到了Windows字体,使用它
+            if available_fonts:
+                plt.rcParams['font.sans-serif'] = ['Microsoft YaHei', 'SimSun', 'SimHei']
+            else:
+                # 使用系统默认字体
+                plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Bitstream Vera Sans', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'sans-serif']
+        else:
+            # 普通Linux环境
+            plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'DejaVu Sans', 'Bitstream Vera Sans', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'sans-serif']
+        
+        plt.rcParams['axes.unicode_minus'] = False
+    else:
+        # 其他系统使用默认设置
+        plt.rcParams['axes.unicode_minus'] = False
+
+# 在导入后立即设置字体支持
+setup_chinese_font_support()
+
+# 设置全局样式参数
+plt.rcParams['figure.facecolor'] = 'white'
+plt.rcParams['axes.facecolor'] = '#fafafa'
+plt.rcParams['axes.edgecolor'] = '#e0e0e0'
+plt.rcParams['axes.linewidth'] = 0.8
+plt.rcParams['grid.alpha'] = 0.5
+plt.rcParams['grid.color'] = '#e0e0e0'
 
 def read_json(file_path):
     with open(file_path, 'r', encoding='utf-8') as f:
@@ -17,12 +91,13 @@ def read_json(file_path):
 def plot_cprofile_table(ax, cprofile_data):
     """绘制cProfile详细信息表格"""
     if not cprofile_data or 'points' not in cprofile_data:
-        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('函数运行详细信息')
+        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes, 
+                fontsize=12, color='#666666')
+        ax.set_title('函数运行详细信息', fontsize=14, fontweight='bold', pad=20)
         return
     
     # 只取前15个最耗时的函数
-    fun_num = 15
+    fun_num = TOP_FUNCTION_COUNT
     points = cprofile_data['points'][:fun_num]
     
     # 准备表格数据
@@ -45,20 +120,30 @@ def plot_cprofile_table(ax, cprofile_data):
     
     # 创建表格
     columns = ['函数名称', '调用次数', '总时间(s)', '累计时间(s)']
-    table = ax.table(cellText=table_data, colLabels=columns, cellLoc='center', loc='center')
+    table = ax.table(cellText=table_data, colLabels=columns, cellLoc='center', loc='center', 
+                     bbox=[0, 0, 1, 1])
     table.auto_set_font_size(False)
     table.set_fontsize(9)
     table.scale(1, 1.5)
     
     # 设置表格样式
     for i in range(len(columns)):
-        table[(0, i)].set_facecolor('#4CAF50')
+        table[(0, i)].set_facecolor('#4a86e8')
         table[(0, i)].set_text_props(weight='bold', color='white')
+    
+    # 为数据行设置交替颜色
+    for i in range(1, len(table_data)+1):
+        for j in range(len(columns)):
+            if i % 2 == 0:
+                table[(i, j)].set_facecolor('#f2f2f2')
+            else:
+                table[(i, j)].set_facecolor('white')
+    
     # 根据函数数量动态调整标题距离
     # 每个函数行大约需要8个单位的高度,加上基础padding
     pad_value = 8 + len(points) * 3
-    ax.set_title(f'函数运行详细信息 (Top {fun_num} 函数)', fontsize=14, pad=pad_value)
-    # 坐标轴掩藏
+    ax.set_title(f'函数运行详细信息 (Top {fun_num} 函数)', fontsize=14, fontweight='bold', pad=pad_value)
+    # 坐标轴
     ax.set_xticks([])
     ax.set_yticks([])
     ax.spines['top'].set_visible(False)
@@ -70,14 +155,22 @@ def plot_cprofile_table(ax, cprofile_data):
 def plot_cprofile_bar_chart(ax, cprofile_data):
     """绘制cProfile总时间柱状图"""
     if not cprofile_data or 'points' not in cprofile_data:
-        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('函数运行总时间')
+        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('函数运行总时间', fontsize=14, fontweight='bold', pad=20)
         return
     
     # 只取前N个最耗时的函数
-    fun_num = 15
+    fun_num = TOP_FUNCTION_COUNT
     points = cprofile_data['points'][:fun_num]
     
+    # 如果没有数据点,直接返回
+    if not points:
+        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('函数运行总时间', fontsize=14, fontweight='bold', pad=20)
+        return
+    
     # 提取函数名和总时间
     functions = []
     total_times = []
@@ -93,42 +186,59 @@ def plot_cprofile_bar_chart(ax, cprofile_data):
         functions.append(func_name_display)
         total_times.append(point['total_time'])
     
-    # 创建垂直柱状图,使用渐变色彩
-    x_pos = np.arange(len(functions))
-    colors = plt.cm.viridis(np.linspace(0, 1, len(functions)))
-    bars = ax.bar(x_pos, total_times, color=colors)
+    # 创建水平柱状图,使用渐变色彩,更适合长函数名显示
+    y_pos = np.arange(len(functions))
+    colors = plt.cm.plasma(np.linspace(0.1, 0.9, len(functions)))  # 使用plasma色彩映射
+    bars = ax.barh(y_pos, total_times, color=colors, height=0.8, edgecolor='white', linewidth=0.5)
     
     # 设置坐标轴
-    ax.set_xticks(x_pos)
-    ax.set_xticklabels(functions, rotation=30, ha='right', fontsize=9)
-    ax.set_ylabel('总时间 (秒)', fontsize=12)
-    ax.set_title(f'函数运行总时间 (Top {fun_num} 函数)', fontsize=14, pad=20)
+    ax.set_yticks(y_pos)
+    ax.set_yticklabels(functions, fontsize=9)
+    ax.set_xlabel('总时间 (秒)', fontsize=12, fontweight='bold')
+    ax.set_title(f'函数运行总时间 (Top {fun_num} 函数)', fontsize=14, fontweight='bold', pad=20)
     
     # 改善网格线样式
-    ax.grid(axis='y', alpha=0.7, linestyle='--', linewidth=0.5)
+    ax.grid(axis='x', alpha=0.4, linestyle='-', linewidth=0.5)
     ax.set_axisbelow(True)
     
     # 在柱状图上添加数值标签,优化显示效果
-    for bar, time in zip(bars, total_times):
-        height = bar.get_height()
-        ax.text(bar.get_x() + bar.get_width()/2., height,
-                f'{time:.6f}', ha='center', va='bottom', fontsize=8, 
-                rotation=0, weight='bold')
+    for i, (bar, time) in enumerate(zip(bars, total_times)):
+        width = bar.get_width()
+        ax.text(width + max(total_times)*0.01, bar.get_y() + bar.get_height()/2.,
+                f'{time:.6f}', ha='left', va='center', fontsize=8, 
+                fontweight='bold', color='#333333')
+    
+    # 添加颜色条以显示颜色映射含义
+    if total_times:  # 确保有数据才添加颜色条
+        sm = plt.cm.ScalarMappable(cmap=plt.cm.plasma, norm=plt.Normalize(vmin=min(total_times), vmax=max(total_times)))
+        sm.set_array([])
+        cbar = plt.colorbar(sm, ax=ax, shrink=0.8, aspect=20, pad=0.02)
+        cbar.set_label('执行时间 (秒)', fontsize=10, fontweight='bold')
     
     # 添加边框
     for spine in ax.spines.values():
-        spine.set_linewidth(0.5)
+        spine.set_linewidth(0.8)
+        spine.set_color('#cccccc')
+
 
 def plot_memory_data(ax, memory_data):
     """绘制内存使用数据"""
     if not memory_data or 'points' not in memory_data:
-        ax.text(0.5, 0.5, '无内存数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('memory_profiler 内存使用情况')
+        ax.text(0.5, 0.5, '无内存数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('memory_profiler 内存使用情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     timestamps = [point['timestamp'] for point in memory_data['points']]
     memory_values = [point['memory'] for point in memory_data['points']]
     
+    # 检查是否有数据
+    if not timestamps or not memory_values:
+        ax.text(0.5, 0.5, '无内存数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('memory_profiler 内存使用情况', fontsize=14, fontweight='bold', pad=20)
+        return
+    
     # 转换时间戳为相对时间(秒)
     start_time = timestamps[0] if timestamps else 0
     relative_times = [t - start_time for t in timestamps]
@@ -138,30 +248,52 @@ def plot_memory_data(ax, memory_data):
     max_index = memory_values.index(max_memory) if memory_values else 0
     max_time = relative_times[max_index] if relative_times else 0
     
-    # 绘制内存使用情况曲线
-    line, = ax.plot(relative_times, memory_values, marker='o', markersize=3, linewidth=1.5)
+    # 计算平均内存使用量
+    avg_memory = np.mean(memory_values) if memory_values else 0
+    
+    # 绘制内存使用情况曲线,使用更平滑的线条
+    ax.plot(relative_times, memory_values, color='#2e7d32', linewidth=2.5, marker='o', 
+            markersize=5, markerfacecolor='#4caf50', markeredgecolor='white', markeredgewidth=1.5,
+            markevery=slice(0, len(relative_times), max(1, len(relative_times)//20)))  # 控制标记密度
     
     # 在峰值点添加特殊标记
-    ax.plot(max_time, max_memory, marker='o', markersize=8, color='red',
-                          markerfacecolor='none', markeredgewidth=2, label=f'峰值: {max_memory:.2f} MB')
-    
-    ax.set_xlabel('时间 (秒)')
-    ax.set_ylabel('内存使用量 (MB)')
-    ax.set_title(f'进程内存使用情况 (峰值: {max_memory:.2f} MB at {max_time:.1f}s)')
-    ax.grid(True, alpha=0.3)
-    ax.legend()
+    ax.scatter(max_time, max_memory, s=150, color='#d32f2f', marker='o', 
+               edgecolor='white', linewidth=2, zorder=5, label=f'峰值: {max_memory:.2f} MB')
+    
+    # 添加平均线
+    ax.axhline(y=avg_memory, color='#1976d2', linestyle='--', linewidth=1.5, 
+               label=f'平均: {avg_memory:.2f} MB', alpha=0.8)
+    
+    # 添加填充区域以增强视觉效果
+    ax.fill_between(relative_times, memory_values, alpha=0.4, color='#4caf50')
+    
+    # 添加统计信息文本框
+    textstr = f'峰值: {max_memory:.2f} MB\n平均: {avg_memory:.2f} MB'
+    props = dict(boxstyle='round', facecolor='#e3f2fd', alpha=0.8)
+    ax.text(0.03, 0.97, textstr, transform=ax.transAxes, fontsize=10,
+            verticalalignment='top', bbox=props, fontweight='bold')
+    
+    ax.set_xlabel('时间 (秒)', fontsize=12, fontweight='bold')
+    ax.set_ylabel('内存使用量 (MB)', fontsize=12, fontweight='bold')
+    ax.set_title(f'进程内存使用情况 (峰值: {max_memory:.2f} MB at {max_time:.1f}s)', 
+                 fontsize=14, fontweight='bold', pad=20)
+    ax.grid(True, alpha=0.4)
+    ax.legend(loc='upper right', frameon=True, fancybox=True, shadow=True, ncol=1)
+
 
 def plot_psutil_data(ax, psutil_data):
     """绘制psutil系统资源数据"""
     if not psutil_data or 'points' not in psutil_data:
-        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('进程资源使用情况')
+        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程资源使用情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     points = psutil_data['points']
     if not points:
-        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('进程资源使用情况')
+        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程资源使用情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     # 提取数据并转换时间字符串为时间戳
@@ -213,42 +345,98 @@ def plot_psutil_data(ax, psutil_data):
         except ValueError:
             mem_pct_values.append(0)
     
+    # 检查是否有有效数据
+    if not any([rss_values, vms_values, cpu_values, mem_pct_values]):
+        ax.text(0.5, 0.5, '无有效进程资源数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程资源使用情况', fontsize=14, fontweight='bold', pad=20)
+        return
+    
+    # 计算统计数据
+    avg_cpu = np.mean(cpu_values) if cpu_values else 0
+    max_cpu = max(cpu_values) if cpu_values else 0
+    avg_rss = np.mean(rss_values) if rss_values else 0
+    max_rss = max(rss_values) if rss_values else 0
+    
     # 绘制双轴图
     ax2 = ax.twinx()
     
+    lines = []  # 存储线条引用
+    
     # 物理内存使用量(蓝色)
-    line1, = ax.plot(relative_times, rss_values, marker='o', color='blue', label='物理内存(RSS)')
+    if rss_values:
+        line1, = ax.plot(relative_times, rss_values, marker='o', markersize=5, linewidth=2.5, 
+                        color='#1976d2', label='物理内存(RSS)', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        lines.append(line1)
+        # 添加平均线
+        ax.axhline(y=avg_rss, color='#1976d2', linestyle=':', linewidth=1.5, alpha=0.7,
+                   label=f'平均RSS: {avg_rss:.1f} MB')
+    
     # 虚拟内存使用量(绿色)
-    line3, = ax.plot(relative_times, vms_values, marker='^', color='green', label='虚拟内存(VMS)')
-    ax.set_xlabel('时间 (秒)')
-    ax.set_ylabel('内存使用量 (MB)', color='blue')
-    ax.tick_params(axis='y', labelcolor='blue')
+    if vms_values:
+        line3, = ax.plot(relative_times, vms_values, marker='^', markersize=6, linewidth=2.5, 
+                        color='#388e3c', label='虚拟内存(VMS)', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        lines.append(line3)
+    
+    ax.set_xlabel('时间 (秒)', fontsize=12, fontweight='bold')
+    ax.set_ylabel('内存使用量 (MB)', fontsize=12, fontweight='bold', color='#1976d2')
+    ax.tick_params(axis='y', labelcolor='#1976d2')
+    
+    line2 = None
+    line4 = None
     
     # CPU使用率(红色)和内存占用率(紫色)
-    line2, = ax2.plot(relative_times, cpu_values, marker='s', color='red', label='CPU使用率')
-    line4, = ax2.plot(relative_times, mem_pct_values, marker='d', color='purple', label='内存占用率')
-    ax2.set_ylabel('百分比 (%)', color='red')
-    ax2.tick_params(axis='y', labelcolor='red')
+    if cpu_values:
+        line2, = ax2.plot(relative_times, cpu_values, marker='s', markersize=5, linewidth=2.5, 
+                         color='#d32f2f', label='CPU使用率', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        lines.append(line2)
+        # 添加CPU平均线和峰值标记
+        ax2.axhline(y=avg_cpu, color='#d32f2f', linestyle=':', linewidth=1.5, alpha=0.7,
+                    label=f'平均CPU: {avg_cpu:.1f}%')
+        
+        # 寻找CPU峰值点并标记
+        if cpu_values:
+            max_cpu_idx = cpu_values.index(max_cpu)
+            max_cpu_time = relative_times[max_cpu_idx]
+            ax2.scatter(max_cpu_time, max_cpu, s=120, color='#d32f2f', marker='*', 
+                       edgecolor='white', linewidth=1, zorder=5)
     
-    # 合并图例
-    lines = [line1, line3, line2, line4]
-    labels = [l.get_label() for l in lines]
-    ax.legend(lines, labels, loc='upper left')
+    if mem_pct_values:
+        line4, = ax2.plot(relative_times, mem_pct_values, marker='d', markersize=6, linewidth=2.5, 
+                         color='#7b1fa2', label='内存占用率', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        lines.append(line4)
+    
+    ax2.set_ylabel('百分比 (%)', fontsize=12, fontweight='bold', color='#d32f2f')
+    ax2.tick_params(axis='y', labelcolor='#d32f2f')
     
-    ax.set_title('进程资源使用情况')
-    ax.grid(True, alpha=0.3)
+    # 合并图例
+    if lines:
+        labels = [l.get_label() for l in lines]
+        ax.legend(lines, labels, loc='upper left', frameon=True, fancybox=True, shadow=True, ncol=2)
+    
+    # 添加统计信息文本框
+    textstr = f'CPU峰值: {max_cpu:.1f}%\n内存峰值: {max_rss:.1f} MB'
+    props = dict(boxstyle='round', facecolor='#ffebee', alpha=0.8)
+    ax.text(0.03, 0.97, textstr, transform=ax.transAxes, fontsize=10,
+            verticalalignment='top', bbox=props, fontweight='bold')
+    
+    ax.set_title('进程资源使用情况', fontsize=14, fontweight='bold', pad=20)
+    ax.grid(True, alpha=0.4)
+
 
 def plot_network_data(ax, psutil_data):
     """绘制网络使用数据"""
     if not psutil_data or 'points' not in psutil_data:
-        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('系统网络使用情况')
+        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('系统网络使用情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     points = psutil_data['points']
     if not points:
-        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('系统网络使用情况')
+        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('系统网络使用情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     # 提取数据并转换时间字符串为时间戳
@@ -285,27 +473,62 @@ def plot_network_data(ax, psutil_data):
         except ValueError:
             net_send_values.append(0)
     
-    # 绘制网络使用情况
-    ax.plot(relative_times, net_recv_values, marker='o', color='blue', label='网络接收')
-    ax.plot(relative_times, net_send_values, marker='s', color='red', label='网络发送')
+    # 检查是否有有效数据
+    if not net_recv_values and not net_send_values:
+        ax.text(0.5, 0.5, '无有效网络数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('系统网络使用情况', fontsize=14, fontweight='bold', pad=20)
+        return
     
-    ax.set_xlabel('时间 (秒)')
-    ax.set_ylabel('速率 (MB/s)')
-    ax.set_title('系统网络使用情况')
-    ax.grid(True, alpha=0.3)
-    ax.legend()
+    # 计算统计数据
+    avg_recv = np.mean(net_recv_values) if net_recv_values else 0
+    avg_send = np.mean(net_send_values) if net_send_values else 0
+    max_recv = max(net_recv_values) if net_recv_values else 0
+    max_send = max(net_send_values) if net_send_values else 0
+    
+    # 绘制网络使用情况,使用面积图增强视觉效果
+    if net_recv_values:
+        ax.plot(relative_times, net_recv_values, marker='o', markersize=5, linewidth=2.5, 
+                color='#1976d2', label='网络接收', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        ax.fill_between(relative_times, net_recv_values, alpha=0.3, color='#1976d2')
+        # 添加平均线
+        ax.axhline(y=avg_recv, color='#1976d2', linestyle=':', linewidth=1.5, alpha=0.7,
+                   label=f'平均接收: {avg_recv:.2f} MB/s')
+    
+    if net_send_values:
+        ax.plot(relative_times, net_send_values, marker='s', markersize=5, linewidth=2.5, 
+                color='#ff9800', label='网络发送', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        ax.fill_between(relative_times, net_send_values, alpha=0.3, color='#ff9800')
+        # 添加平均线
+        ax.axhline(y=avg_send, color='#ff9800', linestyle=':', linewidth=1.5, alpha=0.7,
+                   label=f'平均发送: {avg_send:.2f} MB/s')
+    
+    # 添加统计信息文本框
+    textstr = f'接收峰值: {max_recv:.2f} MB/s\n发送峰值: {max_send:.2f} MB/s'
+    props = dict(boxstyle='round', facecolor='#e3f2fd', alpha=0.8)
+    ax.text(0.03, 0.97, textstr, transform=ax.transAxes, fontsize=10,
+            verticalalignment='top', bbox=props, fontweight='bold')
+    
+    ax.set_xlabel('时间 (秒)', fontsize=12, fontweight='bold')
+    ax.set_ylabel('速率 (MB/s)', fontsize=12, fontweight='bold')
+    ax.set_title('系统网络使用情况', fontsize=14, fontweight='bold', pad=20)
+    ax.grid(True, alpha=0.4)
+    ax.legend(loc='upper right', frameon=True, fancybox=True, shadow=True, ncol=1)
+
 
 def plot_disk_io_data(ax, psutil_data):
     """绘制进程IO数据"""
     if not psutil_data or 'points' not in psutil_data:
-        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('进程IO情况')
+        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程IO情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     points = psutil_data['points']
     if not points:
-        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes)
-        ax.set_title('进程IO情况')
+        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程IO情况', fontsize=14, fontweight='bold', pad=20)
         return
     
     # 提取数据并转换时间字符串为时间戳
@@ -341,28 +564,70 @@ def plot_disk_io_data(ax, psutil_data):
         except ValueError:
             disk_write_values.append(0)
     
-    # 绘制磁盘IO情况
-    ax.plot(relative_times, disk_read_values, marker='o', color='blue', label='磁盘读取')
-    ax.plot(relative_times, disk_write_values, marker='s', color='red', label='磁盘写入')
+    # 检查是否有有效数据
+    if not disk_read_values and not disk_write_values:
+        ax.text(0.5, 0.5, '无有效IO数据', ha='center', va='center', transform=ax.transAxes,
+                fontsize=12, color='#666666')
+        ax.set_title('进程IO情况', fontsize=14, fontweight='bold', pad=20)
+        return
     
-    ax.set_xlabel('时间 (秒)')
-    ax.set_ylabel('速率 (MB/s)')
-    ax.set_title('进程IO情况')
-    ax.grid(True, alpha=0.3)
-    ax.legend()
+    # 计算统计数据
+    avg_read = np.mean(disk_read_values) if disk_read_values else 0
+    avg_write = np.mean(disk_write_values) if disk_write_values else 0
+    max_read = max(disk_read_values) if disk_read_values else 0
+    max_write = max(disk_write_values) if disk_write_values else 0
+    
+    # 绘制磁盘IO情况,使用不同样式的线条区分读写操作
+    if disk_read_values:
+        ax.plot(relative_times, disk_read_values, marker='o', markersize=5, linewidth=2.5, 
+                color='#7b1fa2', label='磁盘读取', linestyle='-', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        ax.fill_between(relative_times, disk_read_values, alpha=0.3, color='#7b1fa2')
+        # 添加平均线
+        ax.axhline(y=avg_read, color='#7b1fa2', linestyle=':', linewidth=1.5, alpha=0.7,
+                   label=f'平均读取: {avg_read:.2f} MB/s')
+    
+    if disk_write_values:
+        ax.plot(relative_times, disk_write_values, marker='s', markersize=5, linewidth=2.5, 
+                color='#f57c00', label='磁盘写入', linestyle='--', markevery=slice(0, len(relative_times), max(1, len(relative_times)//15)))
+        ax.fill_between(relative_times, disk_write_values, alpha=0.3, color='#f57c00')
+        # 添加平均线
+        ax.axhline(y=avg_write, color='#f57c00', linestyle=':', linewidth=1.5, alpha=0.7,
+                   label=f'平均写入: {avg_write:.2f} MB/s')
+    
+    # 添加统计信息文本框
+    textstr = f'读取峰值: {max_read:.2f} MB/s\n写入峰值: {max_write:.2f} MB/s'
+    props = dict(boxstyle='round', facecolor='#f3e5f5', alpha=0.8)
+    ax.text(0.03, 0.97, textstr, transform=ax.transAxes, fontsize=10,
+            verticalalignment='top', bbox=props, fontweight='bold')
+    
+    ax.set_xlabel('时间 (秒)', fontsize=12, fontweight='bold')
+    ax.set_ylabel('速率 (MB/s)', fontsize=12, fontweight='bold')
+    ax.set_title('进程IO情况', fontsize=14, fontweight='bold', pad=20)
+    ax.grid(True, alpha=0.4)
+    ax.legend(loc='upper right', frameon=True, fancybox=True, shadow=True, ncol=1)
 
 def main():
     parser = argparse.ArgumentParser(description='绘制性能分析结果图')
+    # parser.add_argument('--input','-i', required=True)
+    # parser.add_argument('--output', '-o',required=True)
     parser.add_argument('--input','-i', default='./results/performance_analysis_report.json')
     parser.add_argument('--output', '-o', default='./results/performance_analysis_report.png')
     args = parser.parse_args()
-
+    if not os.path.exists(args.input):
+        raise ValueError(f'输入文件不存在:{args.input}')
     # 读取json数据
     data = read_json(args.input)
     
     # 创建更大的图表
     fig = plt.figure(figsize=(20, 18))
-    fig.suptitle('Python 性能分析报告', fontsize=20, fontweight='bold')
+    fig.suptitle('Python 性能分析报告', fontsize=24, fontweight='bold', y=0.95)
+    
+    # 设置图表背景色
+    fig.patch.set_facecolor('white')
+    
+    # 添加水印效果
+    fig.text(0.5, 0.5, 'Python Performance Report', fontsize=40, color='gray', 
+             ha='center', va='center', alpha=0.05, rotation=45)
     
     # 创建子图
     # cProfile 表格
@@ -387,11 +652,19 @@ def main():
     plot_disk_io_data(ax6, data.get('analysis_results', {}).get('psutil', {}))
     
     # 调整布局
-    plt.tight_layout()
+    plt.tight_layout(rect=[0, 0.01, 1, 0.93])  # 减少底部边距以减少空白区域
+    
+    # 添加页脚信息
+    fig.text(0.95, 0.005, f'生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}', 
+             fontsize=10, ha='right', va='bottom', color='#666666')
+    fig.text(0.05, 0.005, 'Python性能分析工具', fontsize=10, ha='left', va='bottom', color='#666666')
     
     # 保存图像
-    plt.savefig(args.output, dpi=300, bbox_inches='tight')
+    plt.savefig(args.output, dpi=300, bbox_inches='tight', facecolor='white', 
+                edgecolor='none', orientation='landscape')
     print(f"性能分析图表已保存至: {args.output}")
+    plt.close()  # 关闭图形以释放内存
+    # plt.show()  # 可选:显示图表
 
 if __name__ == '__main__':
-    main()
+    main()

+ 416 - 0
plot_bk.py

@@ -0,0 +1,416 @@
+import json
+import argparse
+import os.path
+import platform
+import matplotlib
+import matplotlib.pyplot as plt
+import numpy as np
+from datetime import datetime
+from matplotlib.font_manager import FontProperties
+
+def setup_chinese_font_support():
+    """根据操作系统环境设置中文字体支持"""
+    system = platform.system().lower()
+    
+    if system == 'windows':
+        # Windows系统字体设置
+        plt.rcParams['font.sans-serif'] = ['SimHei', 'FangSong', 'Arial Unicode MS']
+
+    elif system == 'linux':
+        # 检查是否在WSL环境中
+        plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'Microsoft YaHei', 'SimSun']
+    plt.rcParams['axes.unicode_minus'] = False
+
+
+# 在导入后立即设置字体支持
+setup_chinese_font_support()
+
+def read_json(file_path):
+    with open(file_path, 'r', encoding='utf-8') as f:
+        data = json.load(f)
+    return data
+
+def plot_cprofile_table(ax, cprofile_data):
+    """绘制cProfile详细信息表格"""
+    if not cprofile_data or 'points' not in cprofile_data:
+        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('函数运行详细信息')
+        return
+    
+    # 只取前15个最耗时的函数
+    fun_num = 15
+    points = cprofile_data['points'][:fun_num]
+    
+    # 准备表格数据
+    table_data = []
+    for point in points:
+        # 简化函数名显示
+        func_name = point['function'][1:-1]
+        func_name = func_name.split(',')[-1].strip()
+        func_name = func_name[1:-1]
+
+        # 限制函数名长度,但保留足够空间显示完整信息
+        func_name_display = func_name[:35] + '...' if len(func_name) > 35 else func_name
+        # 将数据点添加到表格
+        table_data.append([
+            func_name_display,
+            point['call_count'],
+            f"{point['total_time']:.6f}",
+            f"{point['cumulative_time']:.6f}"
+        ])
+    
+    # 创建表格
+    columns = ['函数名称', '调用次数', '总时间(s)', '累计时间(s)']
+    table = ax.table(cellText=table_data, colLabels=columns, cellLoc='center', loc='center')
+    table.auto_set_font_size(False)
+    table.set_fontsize(9)
+    table.scale(1, 1.5)
+    
+    # 设置表格样式
+    for i in range(len(columns)):
+        table[(0, i)].set_facecolor('#4CAF50')
+        table[(0, i)].set_text_props(weight='bold', color='white')
+    # 根据函数数量动态调整标题距离
+    # 每个函数行大约需要8个单位的高度,加上基础padding
+    pad_value = 8 + len(points) * 3
+    ax.set_title(f'函数运行详细信息 (Top {fun_num} 函数)', fontsize=14, pad=pad_value)
+    # 坐标轴掩藏
+    ax.set_xticks([])
+    ax.set_yticks([])
+    ax.spines['top'].set_visible(False)
+    ax.spines['right'].set_visible(False)
+    ax.spines['bottom'].set_visible(False)
+    ax.spines['left'].set_visible(False)
+
+
+def plot_cprofile_bar_chart(ax, cprofile_data):
+    """绘制cProfile总时间柱状图"""
+    if not cprofile_data or 'points' not in cprofile_data:
+        ax.text(0.5, 0.5, '无cProfile数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('函数运行总时间')
+        return
+    
+    # 只取前N个最耗时的函数
+    fun_num = 15
+    points = cprofile_data['points'][:fun_num]
+    
+    # 提取函数名和总时间
+    functions = []
+    total_times = []
+    
+    for point in points:
+        # 简化函数名显示
+        func_name = point['function'][1:-1]
+        func_name = func_name.split(',')[-1].strip()
+        func_name = func_name[1:-1]
+        
+        # 限制函数名长度
+        func_name_display = func_name[:35] + '...' if len(func_name) > 35 else func_name
+        functions.append(func_name_display)
+        total_times.append(point['total_time'])
+    
+    # 创建垂直柱状图,使用渐变色彩
+    x_pos = np.arange(len(functions))
+    colors = plt.cm.viridis(np.linspace(0, 1, len(functions)))
+    bars = ax.bar(x_pos, total_times, color=colors)
+    
+    # 设置坐标轴
+    ax.set_xticks(x_pos)
+    ax.set_xticklabels(functions, rotation=30, ha='right', fontsize=9)
+    ax.set_ylabel('总时间 (秒)', fontsize=12)
+    ax.set_title(f'函数运行总时间 (Top {fun_num} 函数)', fontsize=14, pad=20)
+    
+    # 改善网格线样式
+    ax.grid(axis='y', alpha=0.7, linestyle='--', linewidth=0.5)
+    ax.set_axisbelow(True)
+    
+    # 在柱状图上添加数值标签,优化显示效果
+    for bar, time in zip(bars, total_times):
+        height = bar.get_height()
+        ax.text(bar.get_x() + bar.get_width()/2., height,
+                f'{time:.6f}', ha='center', va='bottom', fontsize=8, 
+                rotation=0, weight='bold')
+    
+    # 添加边框
+    for spine in ax.spines.values():
+        spine.set_linewidth(0.5)
+
+def plot_memory_data(ax, memory_data):
+    """绘制内存使用数据"""
+    if not memory_data or 'points' not in memory_data:
+        ax.text(0.5, 0.5, '无内存数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('memory_profiler 内存使用情况')
+        return
+    
+    timestamps = [point['timestamp'] for point in memory_data['points']]
+    memory_values = [point['memory'] for point in memory_data['points']]
+    
+    # 转换时间戳为相对时间(秒)
+    start_time = timestamps[0] if timestamps else 0
+    relative_times = [t - start_time for t in timestamps]
+    
+    # 查找内存峰值及其位置
+    max_memory = max(memory_values) if memory_values else 0
+    max_index = memory_values.index(max_memory) if memory_values else 0
+    max_time = relative_times[max_index] if relative_times else 0
+    
+    # 绘制内存使用情况曲线
+    line, = ax.plot(relative_times, memory_values, marker='o', markersize=3, linewidth=1.5)
+    
+    # 在峰值点添加特殊标记
+    ax.plot(max_time, max_memory, marker='o', markersize=8, color='red',
+                          markerfacecolor='none', markeredgewidth=2, label=f'峰值: {max_memory:.2f} MB')
+    
+    ax.set_xlabel('时间 (秒)')
+    ax.set_ylabel('内存使用量 (MB)')
+    ax.set_title(f'进程内存使用情况 (峰值: {max_memory:.2f} MB at {max_time:.1f}s)')
+    ax.grid(True, alpha=0.3)
+    ax.legend()
+
+def plot_psutil_data(ax, psutil_data):
+    """绘制psutil系统资源数据"""
+    if not psutil_data or 'points' not in psutil_data:
+        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('进程资源使用情况')
+        return
+    
+    points = psutil_data['points']
+    if not points:
+        ax.text(0.5, 0.5, '无进程资源数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('进程资源使用情况')
+        return
+    
+    # 提取数据并转换时间字符串为时间戳
+    timestamps = []
+    rss_values = []
+    vms_values = []
+    cpu_values = []
+    mem_pct_values = []
+    
+    for point in points:
+        # 解析时间字符串并转换为时间戳
+        try:
+            dt = datetime.strptime(point['now_time'], '%Y-%m-%d %H:%M:%S')
+            timestamps.append(dt.timestamp())
+        except ValueError:
+            # 如果解析失败,使用索引作为后备
+            timestamps.append(len(timestamps))
+            
+    # 转换时间戳为相对时间(秒)
+    start_time = timestamps[0] if timestamps else 0
+    relative_times = [t - start_time for t in timestamps]
+    
+    for point in points:
+        # 解析RSS内存值
+        rss_str = point['rss'].replace('MB', '')
+        try:
+            rss_values.append(float(rss_str))
+        except ValueError:
+            rss_values.append(0)
+            
+        # 解析VMS内存值
+        vms_str = point['vms'].replace('MB', '')
+        try:
+            vms_values.append(float(vms_str))
+        except ValueError:
+            vms_values.append(0)
+        
+        # 解析CPU百分比
+        cpu_str = point['cpu_pct'].replace('%', '')
+        try:
+            cpu_values.append(float(cpu_str))
+        except ValueError:
+            cpu_values.append(0)
+            
+        # 解析内存占用率
+        mem_pct_str = point['mem_pct'].replace('%', '')
+        try:
+            mem_pct_values.append(float(mem_pct_str))
+        except ValueError:
+            mem_pct_values.append(0)
+    
+    # 绘制双轴图
+    ax2 = ax.twinx()
+    
+    # 物理内存使用量(蓝色)
+    line1, = ax.plot(relative_times, rss_values, marker='o', color='blue', label='物理内存(RSS)')
+    # 虚拟内存使用量(绿色)
+    line3, = ax.plot(relative_times, vms_values, marker='^', color='green', label='虚拟内存(VMS)')
+    ax.set_xlabel('时间 (秒)')
+    ax.set_ylabel('内存使用量 (MB)', color='blue')
+    ax.tick_params(axis='y', labelcolor='blue')
+    
+    # CPU使用率(红色)和内存占用率(紫色)
+    line2, = ax2.plot(relative_times, cpu_values, marker='s', color='red', label='CPU使用率')
+    line4, = ax2.plot(relative_times, mem_pct_values, marker='d', color='purple', label='内存占用率')
+    ax2.set_ylabel('百分比 (%)', color='red')
+    ax2.tick_params(axis='y', labelcolor='red')
+    
+    # 合并图例
+    lines = [line1, line3, line2, line4]
+    labels = [l.get_label() for l in lines]
+    ax.legend(lines, labels, loc='upper left')
+    
+    ax.set_title('进程资源使用情况')
+    ax.grid(True, alpha=0.3)
+
+def plot_network_data(ax, psutil_data):
+    """绘制网络使用数据"""
+    if not psutil_data or 'points' not in psutil_data:
+        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('系统网络使用情况')
+        return
+    
+    points = psutil_data['points']
+    if not points:
+        ax.text(0.5, 0.5, '无网络数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('系统网络使用情况')
+        return
+    
+    # 提取数据并转换时间字符串为时间戳
+    from datetime import datetime
+    timestamps = []
+    net_recv_values = []
+    net_send_values = []
+    
+    for point in points:
+        # 解析时间字符串并转换为时间戳
+        try:
+            dt = datetime.strptime(point['now_time'], '%Y-%m-%d %H:%M:%S')
+            timestamps.append(dt.timestamp())
+        except ValueError:
+            # 如果解析失败,使用索引作为后备
+            timestamps.append(len(timestamps))
+    
+    # 转换为相对时间(秒)
+    start_time = timestamps[0] if timestamps else 0
+    relative_times = [t - start_time for t in timestamps]
+    
+    for point in points:
+        # 解析网络接收值
+        net_recv_str = point['sys_net_recv'].replace('MB/s', '').replace('MB', '').replace(' ', '')
+        try:
+            net_recv_values.append(float(net_recv_str))
+        except ValueError:
+            net_recv_values.append(0)
+            
+        # 解析网络发送值
+        net_send_str = point['sys_net_send'].replace('MB/s', '').replace('MB', '').replace(' ', '')
+        try:
+            net_send_values.append(float(net_send_str))
+        except ValueError:
+            net_send_values.append(0)
+    
+    # 绘制网络使用情况
+    ax.plot(relative_times, net_recv_values, marker='o', color='blue', label='网络接收')
+    ax.plot(relative_times, net_send_values, marker='s', color='red', label='网络发送')
+    
+    ax.set_xlabel('时间 (秒)')
+    ax.set_ylabel('速率 (MB/s)')
+    ax.set_title('系统网络使用情况')
+    ax.grid(True, alpha=0.3)
+    ax.legend()
+
+def plot_disk_io_data(ax, psutil_data):
+    """绘制进程IO数据"""
+    if not psutil_data or 'points' not in psutil_data:
+        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('进程IO情况')
+        return
+    
+    points = psutil_data['points']
+    if not points:
+        ax.text(0.5, 0.5, '无进程IO数据', ha='center', va='center', transform=ax.transAxes)
+        ax.set_title('进程IO情况')
+        return
+    
+    # 提取数据并转换时间字符串为时间戳
+    timestamps = []
+    disk_read_values = []
+    disk_write_values = []
+    
+    for point in points:
+        # 解析时间字符串并转换为时间戳
+        try:
+            dt = datetime.strptime(point['now_time'], '%Y-%m-%d %H:%M:%S')
+            timestamps.append(dt.timestamp())
+        except ValueError:
+            # 如果解析失败,使用索引作为后备
+            timestamps.append(len(timestamps))
+    
+    # 转换为相对时间(秒)
+    start_time = timestamps[0] if timestamps else 0
+    relative_times = [t - start_time for t in timestamps]
+    
+    for point in points:
+        # 解析磁盘读取值
+        disk_read_str = point['disk_read'].replace('MB/s', '').replace('MB', '').replace(' ', '')
+        try:
+            disk_read_values.append(float(disk_read_str))
+        except ValueError:
+            disk_read_values.append(0)
+            
+        # 解析磁盘写入值
+        disk_write_str = point['disk_write'].replace('MB/s', '').replace('MB', '').replace(' ', '')
+        try:
+            disk_write_values.append(float(disk_write_str))
+        except ValueError:
+            disk_write_values.append(0)
+    
+    # 绘制磁盘IO情况
+    ax.plot(relative_times, disk_read_values, marker='o', color='blue', label='磁盘读取')
+    ax.plot(relative_times, disk_write_values, marker='s', color='red', label='磁盘写入')
+    
+    ax.set_xlabel('时间 (秒)')
+    ax.set_ylabel('速率 (MB/s)')
+    ax.set_title('进程IO情况')
+    ax.grid(True, alpha=0.3)
+    ax.legend()
+
+def main():
+    parser = argparse.ArgumentParser(description='绘制性能分析结果图')
+    # parser.add_argument('--input','-i', required=True)
+    # parser.add_argument('--output', '-o',required=True)
+    parser.add_argument('--input','-i', default='./results/performance_analysis_report.json')
+    parser.add_argument('--output', '-o', default='./results/performance_analysis_report.png')
+    args = parser.parse_args()
+    if not os.path.exists(args.input):
+        raise ValueError(f'输入文件不存在:{args.input}')
+    # 读取json数据
+    data = read_json(args.input)
+    
+    # 创建更大的图表
+    fig = plt.figure(figsize=(20, 18))
+    fig.suptitle('Python 性能分析报告', fontsize=20, fontweight='bold')
+    
+    # 创建子图
+    # cProfile 表格
+    ax1 = plt.subplot2grid((4, 2), (0, 0), colspan=1)
+    # cProfile 柱状图
+    ax2 = plt.subplot2grid((4, 2), (0, 1), colspan=1)
+    # 内存使用情况
+    ax3 = plt.subplot2grid((4, 2), (1, 0), colspan=1)
+    # 系统资源监控
+    ax4 = plt.subplot2grid((4, 2), (1, 1), colspan=1)
+    # 网络使用情况
+    ax5 = plt.subplot2grid((4, 2), (2, 0), colspan=1)
+    # 磁盘读写情况
+    ax6 = plt.subplot2grid((4, 2), (2, 1), colspan=1)
+    
+    # 绘制各个子图
+    plot_cprofile_table(ax1, data.get('analysis_results', {}).get('cprofile', {}))
+    plot_cprofile_bar_chart(ax2, data.get('analysis_results', {}).get('cprofile', {}))
+    plot_memory_data(ax3, data.get('analysis_results', {}).get('memory_profile', {}))
+    plot_psutil_data(ax4, data.get('analysis_results', {}).get('psutil', {}))
+    plot_network_data(ax5, data.get('analysis_results', {}).get('psutil', {}))
+    plot_disk_io_data(ax6, data.get('analysis_results', {}).get('psutil', {}))
+    
+    # 调整布局
+    plt.tight_layout()
+    
+    # 保存图像
+    plt.savefig(args.output, dpi=300, bbox_inches='tight')
+    print(f"性能分析图表已保存至: {args.output}")
+
+if __name__ == '__main__':
+    main()

BIN
results/cprofile_output.prof


BIN
results/mprofile_memory_plot.png


+ 94 - 94
results/mprofile_output.dat

@@ -1,95 +1,95 @@
 CMDLINE /home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12 ./test/test_script.py
-MEM 7.500000 1765796405.9547
-MEM 22.343750 1765796406.0553
-MEM 22.343750 1765796406.1556
-MEM 22.343750 1765796406.2561
-MEM 22.343750 1765796406.3565
-MEM 22.343750 1765796406.4569
-MEM 22.343750 1765796406.5572
-MEM 22.343750 1765796406.6576
-MEM 22.343750 1765796406.7579
-MEM 22.343750 1765796406.8583
-MEM 22.343750 1765796406.9587
-MEM 22.343750 1765796407.0591
-MEM 22.343750 1765796407.1595
-MEM 22.343750 1765796407.2598
-MEM 22.343750 1765796407.3602
-MEM 22.343750 1765796407.4605
-MEM 22.343750 1765796407.5611
-MEM 22.343750 1765796407.6618
-MEM 22.343750 1765796407.7622
-MEM 22.343750 1765796407.8626
-MEM 22.343750 1765796407.9630
-MEM 22.343750 1765796408.0634
-MEM 22.343750 1765796408.1638
-MEM 22.343750 1765796408.2641
-MEM 22.343750 1765796408.3645
-MEM 22.343750 1765796408.4648
-MEM 22.343750 1765796408.5650
-MEM 22.343750 1765796408.6652
-MEM 22.343750 1765796408.7657
-MEM 22.343750 1765796408.8659
-MEM 22.343750 1765796408.9663
-MEM 22.500000 1765796409.0665
-MEM 22.500000 1765796409.1669
-MEM 22.500000 1765796409.2672
-MEM 22.500000 1765796409.3675
-MEM 22.500000 1765796409.4679
-MEM 22.500000 1765796409.5682
-MEM 22.500000 1765796409.6686
-MEM 22.500000 1765796409.7689
-MEM 22.500000 1765796409.8692
-MEM 22.500000 1765796409.9696
-MEM 22.500000 1765796410.0698
-MEM 22.500000 1765796410.1703
-MEM 22.500000 1765796410.2707
-MEM 22.500000 1765796410.3709
-MEM 22.500000 1765796410.4712
-MEM 22.500000 1765796410.5715
-MEM 22.500000 1765796410.6718
-MEM 22.500000 1765796410.7721
-MEM 22.500000 1765796410.8724
-MEM 22.500000 1765796410.9728
-MEM 22.500000 1765796411.0746
-MEM 22.500000 1765796411.1749
-MEM 22.500000 1765796411.2752
-MEM 22.500000 1765796411.3754
-MEM 22.500000 1765796411.4758
-MEM 22.500000 1765796411.5742
-MEM 22.500000 1765796411.6745
-MEM 22.500000 1765796411.7748
-MEM 22.500000 1765796411.8751
-MEM 22.500000 1765796411.9754
-MEM 22.500000 1765796412.0758
-MEM 22.500000 1765796412.1762
-MEM 22.500000 1765796412.2764
-MEM 22.500000 1765796412.3768
-MEM 22.500000 1765796412.4772
-MEM 22.500000 1765796412.5774
-MEM 22.500000 1765796412.6778
-MEM 22.500000 1765796412.7780
-MEM 22.500000 1765796412.8784
-MEM 22.500000 1765796412.9788
-MEM 22.500000 1765796413.0791
-MEM 34.375000 1765796413.1794
-MEM 88.125000 1765796413.2798
-MEM 24.722656 1765796413.3800
-MEM 24.722656 1765796413.4803
-MEM 24.722656 1765796413.5806
-MEM 24.722656 1765796413.6809
-MEM 24.722656 1765796413.7812
-MEM 24.722656 1765796413.8815
-MEM 24.722656 1765796413.9819
-MEM 24.722656 1765796414.0822
-MEM 24.722656 1765796414.1826
-MEM 24.722656 1765796414.2830
-MEM 24.722656 1765796414.3834
-MEM 24.722656 1765796414.4838
-MEM 24.722656 1765796414.5841
-MEM 24.722656 1765796414.6844
-MEM 24.722656 1765796414.7847
-MEM 24.722656 1765796414.8852
-MEM 24.722656 1765796414.9856
-MEM 24.722656 1765796415.0859
-MEM 24.722656 1765796415.1863
-MEM 24.722656 1765796415.2867
+MEM 5.625000 1765857235.4117
+MEM 22.187500 1765857235.5120
+MEM 22.187500 1765857235.6123
+MEM 22.187500 1765857235.7126
+MEM 22.187500 1765857235.8130
+MEM 22.187500 1765857235.9137
+MEM 22.187500 1765857236.0142
+MEM 22.187500 1765857236.1151
+MEM 22.187500 1765857236.2158
+MEM 22.187500 1765857236.3165
+MEM 22.187500 1765857236.4170
+MEM 22.187500 1765857236.5177
+MEM 22.187500 1765857236.6183
+MEM 22.187500 1765857236.7188
+MEM 22.187500 1765857236.8192
+MEM 22.187500 1765857236.9195
+MEM 22.187500 1765857237.0197
+MEM 22.187500 1765857237.1199
+MEM 22.187500 1765857237.2202
+MEM 22.187500 1765857237.3206
+MEM 22.187500 1765857237.4211
+MEM 22.187500 1765857237.5216
+MEM 22.187500 1765857237.6221
+MEM 22.187500 1765857237.7228
+MEM 22.187500 1765857237.8232
+MEM 22.187500 1765857237.9239
+MEM 22.187500 1765857238.0244
+MEM 22.187500 1765857238.1251
+MEM 22.187500 1765857238.2257
+MEM 22.187500 1765857238.3260
+MEM 22.187500 1765857238.4267
+MEM 22.343750 1765857238.5271
+MEM 22.343750 1765857238.6280
+MEM 22.343750 1765857238.7283
+MEM 22.343750 1765857238.8290
+MEM 22.343750 1765857238.9296
+MEM 22.343750 1765857239.0305
+MEM 22.343750 1765857239.1311
+MEM 22.343750 1765857239.2319
+MEM 22.343750 1765857239.3325
+MEM 22.343750 1765857239.4329
+MEM 22.343750 1765857239.5336
+MEM 22.343750 1765857239.6343
+MEM 22.343750 1765857239.7346
+MEM 22.343750 1765857239.8351
+MEM 22.343750 1765857239.9354
+MEM 22.343750 1765857240.0358
+MEM 22.343750 1765857240.1362
+MEM 22.343750 1765857240.2369
+MEM 22.343750 1765857240.3375
+MEM 22.343750 1765857240.4382
+MEM 22.343750 1765857240.5404
+MEM 22.343750 1765857240.6411
+MEM 22.343750 1765857240.7416
+MEM 22.343750 1765857240.8422
+MEM 22.343750 1765857240.9432
+MEM 22.343750 1765857241.0439
+MEM 22.343750 1765857241.1443
+MEM 22.343750 1765857241.2447
+MEM 22.343750 1765857241.3450
+MEM 22.343750 1765857241.4455
+MEM 22.343750 1765857241.5457
+MEM 22.343750 1765857241.6460
+MEM 22.343750 1765857241.7465
+MEM 22.343750 1765857241.8471
+MEM 22.343750 1765857241.9475
+MEM 22.343750 1765857242.0479
+MEM 22.343750 1765857242.1487
+MEM 22.343750 1765857242.2491
+MEM 22.343750 1765857242.3494
+MEM 22.343750 1765857242.4498
+MEM 22.343750 1765857242.5501
+MEM 38.437500 1765857242.6504
+MEM 80.937500 1765857242.7507
+MEM 24.566406 1765857242.8511
+MEM 24.566406 1765857242.9514
+MEM 24.566406 1765857243.0519
+MEM 24.566406 1765857243.1524
+MEM 24.566406 1765857243.2531
+MEM 24.566406 1765857243.3536
+MEM 24.566406 1765857243.4538
+MEM 24.566406 1765857243.5545
+MEM 24.566406 1765857243.6548
+MEM 24.566406 1765857243.7556
+MEM 24.566406 1765857243.8560
+MEM 24.566406 1765857243.9562
+MEM 24.566406 1765857244.0567
+MEM 24.566406 1765857244.1570
+MEM 24.566406 1765857244.2574
+MEM 24.566406 1765857244.3578
+MEM 24.566406 1765857244.4580
+MEM 24.566406 1765857244.5583
+MEM 24.566406 1765857244.6587
+MEM 24.566406 1765857244.7590

+ 248 - 248
results/performance_analysis_report.json

@@ -1,5 +1,5 @@
 {
-  "timestamp": "2025-12-15T19:00:29.845166",
+  "timestamp": "2025-12-16T11:54:19.408464",
   "analysis_results": {
     "cprofile": {
       "type": "cprofile",
@@ -7,122 +7,122 @@
         {
           "function": "('~', 0, '<built-in method builtins.exec>')",
           "call_count": 1,
-          "total_time": 6.289e-06,
-          "cumulative_time": 9.569391957
+          "total_time": 3.6450000000000003e-06,
+          "cumulative_time": 9.506689994
         },
         {
           "function": "('./test/test_script.py', 1, '<module>')",
           "call_count": 1,
-          "total_time": 7.466e-06,
-          "cumulative_time": 9.569385668
+          "total_time": 6.446000000000001e-06,
+          "cumulative_time": 9.506686349
         },
         {
           "function": "('./test/test_script.py', 28, 'main')",
           "call_count": 1,
-          "total_time": 0.012500885000000002,
-          "cumulative_time": 9.562481916000001
+          "total_time": 0.011689909,
+          "cumulative_time": 9.50393816
         },
         {
           "function": "('~', 0, '<built-in method time.sleep>')",
           "call_count": 5,
-          "total_time": 9.127744553000001,
-          "cumulative_time": 9.127744553000001
+          "total_time": 9.100956633000001,
+          "cumulative_time": 9.100956633000001
         },
         {
           "function": "('./test/test_script.py', 9, 'cpu_intensive_task')",
           "call_count": 1,
-          "total_time": 0.11295076000000001,
-          "cumulative_time": 0.231741562
+          "total_time": 0.10780107500000001,
+          "cumulative_time": 0.22203787700000002
         },
         {
           "function": "('./test/test_script.py', 21, 'memory_intensive_task')",
           "call_count": 1,
-          "total_time": 0.18289659200000002,
-          "cumulative_time": 0.19026621300000002
+          "total_time": 0.162487875,
+          "cumulative_time": 0.16903995600000002
         },
         {
           "function": "('./test/test_script.py', 16, 'io_simulation_task')",
           "call_count": 1,
-          "total_time": 4.0370000000000005e-06,
-          "cumulative_time": 0.10028563300000001
+          "total_time": 4.744000000000001e-06,
+          "cumulative_time": 0.10017874600000001
         },
         {
           "function": "('~', 0, '<built-in method math.sin>')",
           "call_count": 1000000,
-          "total_time": 0.067158061,
-          "cumulative_time": 0.067158061
+          "total_time": 0.065166231,
+          "cumulative_time": 0.065166231
         },
         {
           "function": "('~', 0, '<built-in method math.sqrt>')",
           "call_count": 1000000,
-          "total_time": 0.051632741,
-          "cumulative_time": 0.051632741
+          "total_time": 0.049070571,
+          "cumulative_time": 0.049070571
         },
         {
           "function": "('~', 0, \"<method 'append' of 'list' objects>\")",
           "call_count": 100002,
-          "total_time": 0.007368922000000001,
-          "cumulative_time": 0.007368922000000001
+          "total_time": 0.006551307,
+          "cumulative_time": 0.006551307
         },
         {
           "function": "('<frozen importlib._bootstrap>', 1349, '_find_and_load')",
           "call_count": 1,
-          "total_time": 3.8218000000000006e-05,
-          "cumulative_time": 0.006896286000000001
+          "total_time": 1.1114e-05,
+          "cumulative_time": 0.002741743
         },
         {
           "function": "('<frozen importlib._bootstrap>', 1304, '_find_and_load_unlocked')",
           "call_count": 1,
-          "total_time": 5.9380000000000006e-06,
-          "cumulative_time": 0.006777475000000001
+          "total_time": 4.531e-06,
+          "cumulative_time": 0.002691966
         },
         {
           "function": "('<frozen importlib._bootstrap>', 1240, '_find_spec')",
           "call_count": 1,
-          "total_time": 1.1858e-05,
-          "cumulative_time": 0.0064816380000000005
+          "total_time": 9.16e-06,
+          "cumulative_time": 0.002065955
         },
         {
           "function": "('<frozen importlib._bootstrap_external>', 1524, 'find_spec')",
           "call_count": 1,
-          "total_time": 2.1620000000000002e-06,
-          "cumulative_time": 0.006444345000000001
+          "total_time": 1.7250000000000002e-06,
+          "cumulative_time": 0.0020456800000000002
         },
         {
           "function": "('<frozen importlib._bootstrap_external>', 1495, '_get_spec')",
           "call_count": 1,
-          "total_time": 1.0066e-05,
-          "cumulative_time": 0.006442183000000001
-        },
-        {
-          "function": "('<frozen importlib._bootstrap_external>', 1597, 'find_spec')",
-          "call_count": 4,
-          "total_time": 2.9501e-05,
-          "cumulative_time": 0.004336908
+          "total_time": 7.861e-06,
+          "cumulative_time": 0.002043955
         },
         {
           "function": "('<frozen importlib._bootstrap_external>', 140, '_path_stat')",
           "call_count": 7,
-          "total_time": 4.175e-06,
-          "cumulative_time": 0.0033615090000000004
+          "total_time": 2.9300000000000003e-06,
+          "cumulative_time": 0.0011750080000000002
         },
         {
           "function": "('~', 0, '<built-in method posix.stat>')",
           "call_count": 7,
-          "total_time": 0.003357334,
-          "cumulative_time": 0.003357334
+          "total_time": 0.001172078,
+          "cumulative_time": 0.001172078
         },
         {
-          "function": "('<frozen importlib._bootstrap_external>', 1648, '_fill_cache')",
-          "call_count": 1,
-          "total_time": 6.159000000000001e-06,
-          "cumulative_time": 0.002959761
+          "function": "('<frozen importlib._bootstrap_external>', 1597, 'find_spec')",
+          "call_count": 4,
+          "total_time": 2.3951e-05,
+          "cumulative_time": 0.0011410810000000002
         },
         {
-          "function": "('~', 0, '<built-in method posix.listdir>')",
+          "function": "('<frozen importlib._bootstrap_external>', 1473, '_path_importer_cache')",
+          "call_count": 5,
+          "total_time": 3.165e-06,
+          "cumulative_time": 0.000894405
+        },
+        {
+          "function": "('<frozen importlib._bootstrap_external>', 1460, '_path_hooks')",
           "call_count": 1,
-          "total_time": 0.002952239,
-          "cumulative_time": 0.002952239
+          "total_time": 5.964e-06,
+          "cumulative_time": 0.0008912400000000001
         }
       ],
       "num": 20
@@ -131,398 +131,398 @@
       "type": "memory_profile",
       "points": [
         {
-          "timestamp": 1765796405.9547,
-          "memory": 7.5
+          "timestamp": 1765857235.4117,
+          "memory": 5.625
         },
         {
-          "timestamp": 1765796406.0553,
-          "memory": 22.34375
+          "timestamp": 1765857235.512,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.1556,
-          "memory": 22.34375
+          "timestamp": 1765857235.6123,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.2561,
-          "memory": 22.34375
+          "timestamp": 1765857235.7126,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.3565,
-          "memory": 22.34375
+          "timestamp": 1765857235.813,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.4569,
-          "memory": 22.34375
+          "timestamp": 1765857235.9137,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.5572,
-          "memory": 22.34375
+          "timestamp": 1765857236.0142,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.6576,
-          "memory": 22.34375
+          "timestamp": 1765857236.1151,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.7579,
-          "memory": 22.34375
+          "timestamp": 1765857236.2158,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.8583,
-          "memory": 22.34375
+          "timestamp": 1765857236.3165,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796406.9587,
-          "memory": 22.34375
+          "timestamp": 1765857236.417,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.0591,
-          "memory": 22.34375
+          "timestamp": 1765857236.5177,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.1595,
-          "memory": 22.34375
+          "timestamp": 1765857236.6183,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.2598,
-          "memory": 22.34375
+          "timestamp": 1765857236.7188,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.3602,
-          "memory": 22.34375
+          "timestamp": 1765857236.8192,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.4605,
-          "memory": 22.34375
+          "timestamp": 1765857236.9195,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.5611,
-          "memory": 22.34375
+          "timestamp": 1765857237.0197,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.6618,
-          "memory": 22.34375
+          "timestamp": 1765857237.1199,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.7622,
-          "memory": 22.34375
+          "timestamp": 1765857237.2202,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.8626,
-          "memory": 22.34375
+          "timestamp": 1765857237.3206,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796407.963,
-          "memory": 22.34375
+          "timestamp": 1765857237.4211,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.0634,
-          "memory": 22.34375
+          "timestamp": 1765857237.5216,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.1638,
-          "memory": 22.34375
+          "timestamp": 1765857237.6221,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.2641,
-          "memory": 22.34375
+          "timestamp": 1765857237.7228,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.3645,
-          "memory": 22.34375
+          "timestamp": 1765857237.8232,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.4648,
-          "memory": 22.34375
+          "timestamp": 1765857237.9239,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.565,
-          "memory": 22.34375
+          "timestamp": 1765857238.0244,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.6652,
-          "memory": 22.34375
+          "timestamp": 1765857238.1251,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.7657,
-          "memory": 22.34375
+          "timestamp": 1765857238.2257,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.8659,
-          "memory": 22.34375
+          "timestamp": 1765857238.326,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796408.9663,
-          "memory": 22.34375
+          "timestamp": 1765857238.4267,
+          "memory": 22.1875
         },
         {
-          "timestamp": 1765796409.0665,
-          "memory": 22.5
+          "timestamp": 1765857238.5271,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.1669,
-          "memory": 22.5
+          "timestamp": 1765857238.628,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.2672,
-          "memory": 22.5
+          "timestamp": 1765857238.7283,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.3675,
-          "memory": 22.5
+          "timestamp": 1765857238.829,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.4679,
-          "memory": 22.5
+          "timestamp": 1765857238.9296,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.5682,
-          "memory": 22.5
+          "timestamp": 1765857239.0305,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.6686,
-          "memory": 22.5
+          "timestamp": 1765857239.1311,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.7689,
-          "memory": 22.5
+          "timestamp": 1765857239.2319,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.8692,
-          "memory": 22.5
+          "timestamp": 1765857239.3325,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796409.9696,
-          "memory": 22.5
+          "timestamp": 1765857239.4329,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.0698,
-          "memory": 22.5
+          "timestamp": 1765857239.5336,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.1703,
-          "memory": 22.5
+          "timestamp": 1765857239.6343,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.2707,
-          "memory": 22.5
+          "timestamp": 1765857239.7346,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.3709,
-          "memory": 22.5
+          "timestamp": 1765857239.8351,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.4712,
-          "memory": 22.5
+          "timestamp": 1765857239.9354,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.5715,
-          "memory": 22.5
+          "timestamp": 1765857240.0358,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.6718,
-          "memory": 22.5
+          "timestamp": 1765857240.1362,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.7721,
-          "memory": 22.5
+          "timestamp": 1765857240.2369,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.8724,
-          "memory": 22.5
+          "timestamp": 1765857240.3375,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796410.9728,
-          "memory": 22.5
+          "timestamp": 1765857240.4382,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.0746,
-          "memory": 22.5
+          "timestamp": 1765857240.5404,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.1749,
-          "memory": 22.5
+          "timestamp": 1765857240.6411,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.2752,
-          "memory": 22.5
+          "timestamp": 1765857240.7416,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.3754,
-          "memory": 22.5
+          "timestamp": 1765857240.8422,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.4758,
-          "memory": 22.5
+          "timestamp": 1765857240.9432,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.5742,
-          "memory": 22.5
+          "timestamp": 1765857241.0439,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.6745,
-          "memory": 22.5
+          "timestamp": 1765857241.1443,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.7748,
-          "memory": 22.5
+          "timestamp": 1765857241.2447,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.8751,
-          "memory": 22.5
+          "timestamp": 1765857241.345,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796411.9754,
-          "memory": 22.5
+          "timestamp": 1765857241.4455,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.0758,
-          "memory": 22.5
+          "timestamp": 1765857241.5457,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.1762,
-          "memory": 22.5
+          "timestamp": 1765857241.646,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.2764,
-          "memory": 22.5
+          "timestamp": 1765857241.7465,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.3768,
-          "memory": 22.5
+          "timestamp": 1765857241.8471,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.4772,
-          "memory": 22.5
+          "timestamp": 1765857241.9475,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.5774,
-          "memory": 22.5
+          "timestamp": 1765857242.0479,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.6778,
-          "memory": 22.5
+          "timestamp": 1765857242.1487,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.778,
-          "memory": 22.5
+          "timestamp": 1765857242.2491,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.8784,
-          "memory": 22.5
+          "timestamp": 1765857242.3494,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796412.9788,
-          "memory": 22.5
+          "timestamp": 1765857242.4498,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796413.0791,
-          "memory": 22.5
+          "timestamp": 1765857242.5501,
+          "memory": 22.34375
         },
         {
-          "timestamp": 1765796413.1794,
-          "memory": 34.375
+          "timestamp": 1765857242.6504,
+          "memory": 38.4375
         },
         {
-          "timestamp": 1765796413.2798,
-          "memory": 88.125
+          "timestamp": 1765857242.7507,
+          "memory": 80.9375
         },
         {
-          "timestamp": 1765796413.38,
-          "memory": 24.722656
+          "timestamp": 1765857242.8511,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.4803,
-          "memory": 24.722656
+          "timestamp": 1765857242.9514,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.5806,
-          "memory": 24.722656
+          "timestamp": 1765857243.0519,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.6809,
-          "memory": 24.722656
+          "timestamp": 1765857243.1524,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.7812,
-          "memory": 24.722656
+          "timestamp": 1765857243.2531,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.8815,
-          "memory": 24.722656
+          "timestamp": 1765857243.3536,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796413.9819,
-          "memory": 24.722656
+          "timestamp": 1765857243.4538,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.0822,
-          "memory": 24.722656
+          "timestamp": 1765857243.5545,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.1826,
-          "memory": 24.722656
+          "timestamp": 1765857243.6548,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.283,
-          "memory": 24.722656
+          "timestamp": 1765857243.7556,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.3834,
-          "memory": 24.722656
+          "timestamp": 1765857243.856,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.4838,
-          "memory": 24.722656
+          "timestamp": 1765857243.9562,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.5841,
-          "memory": 24.722656
+          "timestamp": 1765857244.0567,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.6844,
-          "memory": 24.722656
+          "timestamp": 1765857244.157,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.7847,
-          "memory": 24.722656
+          "timestamp": 1765857244.2574,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.8852,
-          "memory": 24.722656
+          "timestamp": 1765857244.3578,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796414.9856,
-          "memory": 24.722656
+          "timestamp": 1765857244.458,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796415.0859,
-          "memory": 24.722656
+          "timestamp": 1765857244.5583,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796415.1863,
-          "memory": 24.722656
+          "timestamp": 1765857244.6587,
+          "memory": 24.566406
         },
         {
-          "timestamp": 1765796415.2867,
-          "memory": 24.722656
+          "timestamp": 1765857244.759,
+          "memory": 24.566406
         }
       ],
       "num": 94,
-      "peak_memory": 88.125
+      "peak_memory": 80.9375
     },
     "pyspy_flamegraph": {
       "type": "pyspy_flamegraph",
-      "file_size_bytes": 24019,
+      "file_size_bytes": 24670,
       "status": "generated"
     },
     "psutil": {
       "type": "psutil",
       "points": [
         {
-          "pid": 126890,
-          "now_time": "2025-12-15 19:00:17",
+          "pid": 34846,
+          "now_time": "2025-12-16 11:54:07",
           "cpu_pct": "0.00%",
-          "rss": "8.59MB",
+          "rss": "8.44MB",
           "vms": "15.98MB",
           "mem_pct": "0.11%",
           "disk_read": "0.00 MB/s",
@@ -531,8 +531,8 @@
           "sys_net_send": "0.00 MB/s"
         },
         {
-          "pid": 126890,
-          "now_time": "2025-12-15 19:00:19",
+          "pid": 34846,
+          "now_time": "2025-12-16 11:54:09",
           "cpu_pct": "0.00%",
           "rss": "8.75MB",
           "vms": "15.98MB",
@@ -543,8 +543,8 @@
           "sys_net_send": "0.00 MB/s"
         },
         {
-          "pid": 126890,
-          "now_time": "2025-12-15 19:00:21",
+          "pid": 34846,
+          "now_time": "2025-12-16 11:54:11",
           "cpu_pct": "0.00%",
           "rss": "8.75MB",
           "vms": "15.98MB",
@@ -555,10 +555,10 @@
           "sys_net_send": "0.00 MB/s"
         },
         {
-          "pid": 126890,
-          "now_time": "2025-12-15 19:00:24",
+          "pid": 34846,
+          "now_time": "2025-12-16 11:54:13",
           "cpu_pct": "0.00%",
-          "rss": "94.83MB",
+          "rss": "94.81MB",
           "vms": "101.82MB",
           "mem_pct": "1.21%",
           "disk_read": "0.00 MB/s",

BIN
results/performance_analysis_report.png


+ 4 - 4
results/psutil_output.csv

@@ -1,5 +1,5 @@
 pid,now_time,cpu_pct,rss,vms,mem_pct,disk_read,disk_write,sys_net_recv,sys_net_send,name,status,pwd,exe,start_time
-126890,2025-12-15 19:00:17,0.00%,8.59MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-15 19:00:15
-126890,2025-12-15 19:00:19,0.00%,8.75MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-15 19:00:15
-126890,2025-12-15 19:00:21,0.00%,8.75MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-15 19:00:15
-126890,2025-12-15 19:00:24,0.00%,94.83MB,101.82MB,1.21%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-15 19:00:15
+34846,2025-12-16 11:54:07,0.00%,8.44MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-16 11:54:04
+34846,2025-12-16 11:54:09,0.00%,8.75MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-16 11:54:04
+34846,2025-12-16 11:54:11,0.00%,8.75MB,15.98MB,0.11%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-16 11:54:04
+34846,2025-12-16 11:54:13,0.00%,94.81MB,101.82MB,1.21%,0.00 MB/s,0.00 MB/s,0.00 MB/s,0.00 MB/s,python,sleeping,/mnt/d/code/listen_py,/home/jiyuhang/miniconda3/envs/testpy1/bin/python3.12,2025-12-16 11:54:04

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
results/pyspy_output.svg


Некоторые файлы не были показаны из-за большого количества измененных файлов