# process_activity_heatmap **Repository Path**: song827345896/process_activity_heatmap ## Basic Information - **Project Name**: process_activity_heatmap - **Description**: process_activity_heatmap - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-21 - **Last Updated**: 2026-04-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Process Activity Heatmap (进程活跃热力图) 基于"内存切片时刻"的进程活跃度分析与可视化平台。以内存快照时间戳为基准切片,计算每个时间点的进程活跃度(Running 或 IPC 命中则为 1,否则按距离上次活跃结束时间指数衰减),并筛选"活跃度 vs oom_score_adj 不匹配"的异常候选进程。 ## 核心特性 - **内存切片分析**: 以内存快照时间戳为基准切片,计算每个时间点的进程活跃度 - **活跃度衰减模型**: 基于指数衰减(`e^(-Δt/τ)`)计算进程非活跃状态下的活跃度分数 - **异常检测**: 通过活跃度与 OOM 评分的不匹配识别异常进程 - **高活跃高 OOM** (`high_activity_high_oom`):可能需要优化的热点进程 - **低活跃低 OOM** (`low_activity_low_oom`):可能存在僵尸或低效进程 - **热力图可视化**: ECharts 驱动的时间切片热力图,支持缩放、点击交互和数据钻取 - **多维数据源**: 支持 IPC、调度、内存、OOM kill 等数据导入和分析 - **统一时间戳**: 自动对齐 TraceStreamer 各数据源的时间戳(支持 ns/us/ms 启发式识别),输出统一的墙钟时间 - **完整进程名**: 前端优先显示完整进程名(`proc_name_full`),16 字节截断名作为回退 - **Web 界面**: React + TypeScript 构建的现代化 SPA,支持前端导入 CSV 采集包 ## 项目结构 ``` process_activity_heatmap/ ├── analyzer/ # 数据分析模块 │ └── slice_activity_analyzer.py # 内存切片活跃度分析器(核心算法) ├── database/ # 数据库层 │ ├── db.py # SQLite 数据库连接和查询(含自动迁移) │ ├── models.py # 数据模型定义 │ └── schema.sql # 表结构 DDL(启动时自动执行) ├── backend/ # FastAPI 后端 │ ├── main.py # 应用入口和 CORS 配置 │ ├── schemas.py # Pydantic 数据模型 │ └── routers/ │ └── v2_heatmap.py # V2 热力图 API 路由 ├── frontend/ # React + TypeScript 前端 (Vite) │ ├── src/ │ │ ├── pages/ # 页面组件 │ │ │ ├── Dashboard.tsx # 热力图主页(切片视图、概览、明细) │ │ │ ├── Abnormal.tsx # 异常切片视图 │ │ │ ├── Baseline.tsx # 切片基线视图 │ │ │ ├── ProcessDetail.tsx # 进程时间线详情 │ │ │ └── Help.tsx # 使用说明 │ │ ├── components/ │ │ │ ├── Layout.tsx # 主布局(顶部导航 + 底部标签栏) │ │ │ └── LazyEChart.tsx # ECharts 懒加载组件 │ │ ├── api/ │ │ │ └── client.ts # API 客户端(Axios) │ │ └── utils/ │ │ └── datetime.ts # 日期时间工具函数 │ └── package.json ├── scripts/ # 数据提取和导入脚本 │ ├── extract_trace_common.py # 公共工具(时间戳转换、进程名规范化、DB 查询) │ ├── extract_ipc_info.py # 从华为 TraceStreamer DB 提取 IPC │ ├── extract_sched_info.py # 提取调度 Running 区间 │ ├── extract_mem_info.py # 提取内存快照(支持 ps 快照补全 PID) │ ├── extract_kill_helper_info.py # 提取 OOM kill 信息 │ ├── import_csv_bundle.py # CSV 批量导入 + 分析(CLI) │ └── e2e_synthetic_csv_demo.py # 合成 CSV E2E 演示 ├── config/ │ └── settings.py # 应用设置(Pydantic Settings) ├── docker/ # Docker 部署配置 │ ├── Dockerfile # 后端镜像(Python 3.11) │ ├── Dockerfile.frontend # 前端镜像(Node 20 + Nginx) │ └── docker-compose.yml # 服务编排 └── data/ # 数据存储目录(自动创建) ``` ## 数据流(最短闭环) 1. **提取**: 用 `scripts/extract_*.py` 从华为 TraceStreamer DB / JSON 提取 CSV 2. **导入**: 通过前端界面上传 CSV 打包文件,或用 CLI `scripts/import_csv_bundle.py` 导入 3. **分析**: 导入时自动运行 `analyzer/slice_activity_analyzer.py` 计算活跃度与异常 4. **展示**: 启动后端/前端,在 Web 界面按时间窗口查看热力图、异常切片和进程详情 ## 快速开始 ### 1) 安装依赖 ```bash # Python 后端 pip install -r requirements.txt # Node.js 前端 cd frontend && npm install && cd .. ``` ### 2) 采集(生成 CSV) 从华为 TraceStreamer 数据源提取 CSV 文件: ```bash # IPC 事件 python3 scripts/extract_ipc_info.py /path/to/*.db --output ipc_info.csv # 调度 Running 区间(注意:需要 db_file 文件名包含时间戳) python3 scripts/extract_sched_info.py /path/to/*.db --output sched_info.csv # 内存快照(从 dynamicMem_*.json) python3 scripts/extract_mem_info.py /path/to/dynamicMem_*.json --output mem_info.csv # 可选:结合多时间点的 ps 输出,为 mem_info.csv 补全 pid / process(16字节截断)/ process_full(完整名) # ps 文件支持多个快照,每个快照以 "timstamp:" 行分隔 python3 scripts/extract_mem_info.py /path/to/dynamicMem_*.json --ps-file scripts/ps.txt --output mem_info.csv # OOM kill 事件(可选) python3 scripts/extract_kill_helper_info.py /path/to/*.db --output kill_helper_info.csv ``` **注意**: - `sched_info.csv` 需要 `db_file` 字段格式为 `record_trace_YYYYMMDDHHMMSS@...db` 以还原真实时间 - `mem_info.csv` 的 `process` 为 16 字节 UTF-8 截断名,完整名放在 `process_full`;`pid` 允许为空,但为空时会按"同一秒"从 `sched/mem` best-effort 反查 - 提取脚本统一输出 `ts`、`dur`、`actual_ts`、`timestamp` 等字段名;导入阶段实际消费的是其中的最小必需字段,不依赖所有扩展列 - 进程名通过 `proc_name_16()` 统一做 16 字节截断,同时去除方括号前缀(如 `[com.app]` → `com.app`) ### 3) 导入 + 分析 **方式一:前端界面导入** 打包 CSV 文件为 `bundle.tar.gz`,包含: - `ipc_info.csv`(必需) - `mem_info.csv`(必需) - `sched_info.csv`(必需) - `kill_helper_info.csv` 或 `kill_info.csv`(可选) 启动前后端后,在 Web 界面点击右上角"导入采集包"上传。上传链路会把 `kill_helper_info.csv` 写入 `kill_info`,并在进程详情页展示查杀时间点和 `remaining_memory_kb`。 如需只导入一部分时间窗,可直接调用上传接口并带上 `start_time/end_time`: ```bash curl -F "file=@bundle.tar.gz" \ "http://127.0.0.1:9000/api/collector/import?replace_existing=true&run_analysis=true&start_time=2026-03-27T09:00:00&end_time=2026-03-27T10:00:00" ``` **方式二:命令行导入** ```bash # 当 schema 变更且不考虑历史兼容时,可先重建数据库(会清空数据) python3 scripts/rebuild_database.py --database data/process_heatmap.db --backup python3 scripts/import_csv_bundle.py \ --input-dir /path/to/csv_dir \ --database data/process_heatmap.db \ --replace-existing \ --analyze # 大包可先按时间窗裁剪导入+分析,避免几十小时 / 10GB+ 数据一次性全量入库 python3 scripts/import_csv_bundle.py \ --input-dir /path/to/csv_dir \ --database data/process_heatmap.db \ --replace-existing \ --import-start-time "2026-03-27 09:00:00" \ --import-end-time "2026-03-27 10:00:00" \ --analyze \ --start-time "2026-03-27 09:00:00" \ --end-time "2026-03-27 10:00:00" ``` 说明: - `--import-start-time/--import-end-time` 会在读 CSV 时直接过滤,只把时间窗内的数据写入 SQLite - `sched_info.csv` 按区间重叠过滤;`ipc/mem/kill` 按事件时间过滤 - `--start-time/--end-time` 仍用于分析时间窗;未指定时默认分析当前库里的全部 `memory_info` 大数据建议: - 对几十小时、10GB+ 的 CSV 包,不要先全量导入;按 30 分钟、1 小时或单次采集窗口分段导入更稳妥 - 首次排查建议先导入一个较小时间窗,在前台确认热力图、异常切片、进程详情和查杀点都正常,再扩大范围 - 前台顶部“仅导入指定时间窗”会默认复用最近一次 Heatmap / Abnormal / Baseline / Detail 页面的查询时间范围,适合交互式排查 - 若要做全量归档,建议把“原始 CSV 存档”和“分析用 SQLite”分开,SQLite 只保留当前排查窗口,避免库持续膨胀 ### 4) 启动服务 ```bash # 后端(端口 9000) DATABASE_PATH=data/process_heatmap.db python3 -m uvicorn backend.main:app --reload --host 0.0.0.0 --port 9000 # 前端(端口 5000,另一个终端) cd frontend && npm run dev ``` ### 5) 访问应用 - **前端界面**: http://localhost:5000 - **API 文档**: http://localhost:9000/docs ## 活跃度计算原理 对于每个内存切片时间点,进程活跃度计算逻辑(`analyzer/slice_activity_analyzer.py`): | 状态 | 活跃度分数 | 说明 | |------|-----------|------| | Running 或有 IPC | 1.0 | 进程在切片时刻处于 Running 状态或参与 IPC 通信 | | 非活跃且超过冷阈值 | 0.0 | 距离上次活跃结束时间 ≥ `ACTIVITY_COLD_THRESHOLD_SECONDS`(默认 60s)| | 非活跃但未超时 | `e^(-Δt/τ)` | 指数衰减,τ = `ACTIVITY_DECAY_TAU_SECONDS`(默认 5s) | ### 异常检测算法 1. 对切片内所有进程的 `activity_score` 和 `oom_score_adj` 做 Min-Max 归一化 2. 计算分位数阈值:`activity_high`, `activity_low`, `oom_high`, `oom_low`(默认 10% 分位) 3. 异常分类: - **high_activity_high_oom**: `activity_norm ≥ activity_high` 且 `oom_norm ≥ oom_high` - **low_activity_low_oom**: `activity_norm ≤ activity_low` 且 `oom_norm ≤ oom_low` - **normal**: 其他情况 ### 重新跑分析 当你修改了活跃度/异常判定逻辑,或者只是希望基于库里现有原始数据重新生成切片分析结果时,可以直接执行: ```bash python3 scripts/import_csv_bundle.py --database data/process_heatmap.db --analyze ``` 如果只想重算某个时间窗: ```bash python3 scripts/import_csv_bundle.py \ --database data/process_heatmap.db \ --analyze \ --start-time 2026-03-27T09:00:00 \ --end-time 2026-03-27T10:00:00 ``` 如果数据库表结构已经变化,需要先重建 schema: ```bash python3 scripts/rebuild_database.py --database data/process_heatmap.db ``` 然后重新导入 CSV 并分析: ```bash python3 scripts/import_csv_bundle.py \ --input-dir /path/to/csv_dir \ --database data/process_heatmap.db \ --replace-existing \ --analyze ``` 说明: - 只跑 `--analyze`:适用于数据库里已经有 `memory_info` / `schedule_info` / `ipc_info` 等原始表数据 - 跑 `--replace-existing --input-dir ... --analyze`:适用于从 CSV 全量重建并重算 - `memory_slice_process_activity` 和 `memory_slice_summary` 都属于分析产物,修改分析逻辑后必须重跑才会生效 ## 前端技术栈 - **框架**: React 18 + TypeScript - **构建工具**: Vite - **路由**: React Router v6 - **图表**: ECharts + echarts-for-react(懒加载优化) - **样式**: Tailwind CSS + Material Design 3 暗色主题 - **HTTP 客户端**: Axios - **日期处理**: date-fns - **图标**: lucide-react ### 设计规范 遵循 Material Design 3 暗色主题: - 主背景: `#111318` - 主色: `#00daf3` (Teal) - 辅助色: `#ffcf8f` (Amber) - 字体: Space Grotesk (标题), Inter (正文), JetBrains Mono (数据) ## 配置 ### 环境变量(可在 `.env` 文件中设置) | 变量 | 默认值 | 说明 | |------|--------|------| | `DATABASE_PATH` | `data/process_heatmap.db` | SQLite 数据库路径 | | `API_HOST` | `0.0.0.0` | 后端监听地址 | | `API_PORT` | `9000` | 后端监听端口 | ### 分析参数 | 变量 | 默认值 | 说明 | |------|--------|------| | `ACTIVITY_DECAY_TAU_SECONDS` | 5.0 | 活跃度指数衰减时间常数(秒)| | `ACTIVITY_COLD_THRESHOLD_SECONDS` | 60.0 | 超过此时间无活动则活跃度为 0(秒)| | `HEATMAP_MAX_SLICE_POINTS` | 300 | 热力图最大切片点数 | | `HEATMAP_MAX_PROCESS_POINTS` | 200 | 热力图最大进程点数 | | `ANOMALY_THRESHOLD_PERCENTILE` | 0.1 | 异常检测百分位阈值(10%)| ## Docker 部署 ```bash cd docker docker-compose up -d ``` 服务启动后: - 前端: http://localhost:5000 - 后端: http://localhost:9000 ## 合成数据演示 项目提供了合成 CSV 数据的 E2E 演示脚本,用于快速验证功能: ```bash # 生成合成 CSV 并导入分析 python3 scripts/e2e_synthetic_csv_demo.py --work-dir /tmp/process_activity_heatmap_e2e # 可选:指定 DB 路径(CSV 会默认写在 DB 同目录) python3 scripts/e2e_synthetic_csv_demo.py --database /tmp/process_activity_heatmap_e2e/process_heatmap.db ``` 生成的数据包含多个进程在时间轴上的 Running/IPC 活跃状态,可用于演示热力图、异常检测和基线计算功能。 ## 前端页面 | 页面 | 路由 | 说明 | |------|------|------| | **热力图** | `/` | 主页:时间概览、切片热力图、切片详情,支持点击钻取和缩放联动 | | **异常切片** | `/abnormal` | 筛选存在异常候选的切片,显示高活跃高 OOM / 低活跃低 OOM 进程列表 | | **基线视图** | `/baseline` | 按分位数或内存阈值计算最小异常进程集合,评估 PSS 影响 | | **进程详情** | `/process/:pid` | 单进程在切片时间轴上的活跃度、PSS、OOM 和异常状态趋势 | | **使用说明** | `/help` | CSV 字段约定和导入流程说明 | ## API 端点 ### 切片汇总 - `GET /api/v2/slices/summary` - 获取切片汇总(分桶聚合) - 查询参数: `start_time`, `end_time`, `bucket_count` - `GET /api/v2/slices` - 获取切片列表(分页) - 查询参数: `start_time`, `end_time`, `limit`, `cursor` ### 切片进程查询 - `GET /api/v2/slices/{slice_ts}/processes` - 获取指定切片的进程列表 - 查询参数: `baseline_type`, `baseline_value`, `sort_by`, `page`, `page_size`, `anomaly_only` ### 热力图窗口 - `POST /api/v2/heatmap/window` - 获取热力图数据窗口(后端自动控量/采样) - 请求体: `start_time`, `end_time`, `slice_limit`, `process_limit`, `process_filter` ### 进程时间线 - `GET /api/v2/processes/{pid}/timeline` - 获取进程时间线 - 查询参数: `start_time`, `end_time`, `limit` - 返回字段: `rows`, `kills` ### 采集包导入 - `POST /api/collector/import` - 上传并导入采集包,可选立即重跑分析 - 查询参数: `replace_existing`, `run_analysis`, `start_time`, `end_time` - 说明: `start_time/end_time` 会在导入阶段直接裁剪时间窗,并把同一时间窗用于分析 - `GET /api/collector/latest-run` - 获取当前数据库中的导入/分析条数摘要 ### 系统状态 - `GET /` - API 根路径和版本信息 - `GET /api/health` - 健康检查 - `GET /api/status` - 系统状态 ## 许可证 MIT License