目录
[5.1.windows API实现](#5.1.windows API实现)
1.简介
TypePerf 是 Windows 内置的命令行性能监控工具,可实时采集并输出系统性能计数器数据,支持写入控制台或多种格式日志文件(CSV/TSV/BLG),常用于自动化监控、性能分析与问题排查。
它的主要功能有:
- 实时监控:持续采集 CPU、内存、磁盘、网络等系统资源指标
- 日志记录:将性能数据写入文件,支持后续分析与报告生成
- 计数器查询:列出系统中所有可用的性能对象与计数器
- 跨机采集:支持远程 Windows 计算机的性能数据采集
- 轻量高效:命令行工具,资源占用低,适合服务器 / 后台环境
2.基本语法与核心参数
语法:
cpp
typeperf <counter [counter ...]> [options]
typeperf -cf <filename> [options]
typeperf -q [object] [options]
typeperf -qx [object] [options]
常用参数(速查表):
| 参数 | 说明 | 示例 |
|---|---|---|
| -cf <文件名> | 从文件读取计数器列表(每行一个) | -cf counters.txt |
| -si <时间> | 采样间隔(默认 1 秒,格式:hh:mm:ss) | -si 5(5 秒) |
| -sc <次数> | 采样次数(默认无限) | -sc 10(10 次后停止) |
| -o <文件名> | 输出文件路径 | -o perf.csv |
| -f <格式> | 输出格式(CSV/TSV/BLG) | -f TSV |
| -s <计算机名> | 远程计算机名 / IP | -s 192.168.1.100 |
| -q [对象] | 列出已安装计数器(无实例) | -q Processor |
| -qx [对象] | 列出计数器及实例 | -qx PhysicalDisk |
| -y | 无提示覆盖文件 | -y |
| -? | 显示帮助信息 | typeperf -? |
3.性能计数器路径
计数器路径格式:
cpp
\\[计算机名]\[性能对象]([实例])\[计数器]
- 本地计算机可省略计算机名部分
- _Total 表示汇总所有实例(如所有 CPU 核心)
- 示例 :
\Processor(_Total)\% Processor Time(CPU 总使用率)\Memory\Available MBytes(可用内存 MB)\LogicalDisk(C:)\% Free Space(C 盘可用空间百分比)
4.典型用法示例
4.1.基础监控(实时显示)
监控 CPU 使用率:
cpp
typeperf "\Processor(_Total)\% Processor Time"
同时监控 CPU、内存、磁盘:
cpp
typeperf "\Processor(_Total)\% Processor Time" "\Memory\Available MBytes" "\LogicalDisk(C:)\% Free Space"
设置采样间隔为 3 秒:
cpp
typeperf "\Memory\Available MBytes" -si 3
4.2.日志记录(保存到文件)
保存到 CSV 文件(10 次采样,间隔 5 秒):
cpp
typeperf "\Processor(_Total)\% Processor Time" -si 5 -sc 10 -f CSV -o cpu_log.csv
从文件读取计数器列表并保存为 TSV:
cpp
typeperf -cf counters.txt -si 5 -sc 50 -f TSV -o system_perf.tsv
counters.txt 格式示例:
cpp
\Processor(_Total)\% Processor Time
\Memory\Available MBytes
\PhysicalDisk(_Total)\% Disk Time
\Network Interface(*)\Bytes Total/sec
4.3.计数器查询(查找可用指标)
列出所有性能对象:
cpp
typeperf -q
列出处理器相关计数器:
cpp
typeperf -q Processor
列出物理磁盘计数器及实例:
cpp
typeperf -qx PhysicalDisk
将计数器列表保存到文件:
cpp
typeperf -qx PhysicalDisk -o disk_counters.txt
4.4.远程监控(采集其他计算机数据)
cpp
typeperf "\\SERVER01\Processor(_Total)\% Processor Time" -s SERVER01
注意:需具备远程计算机的性能监控权限
4.5.监控GPU
1.整体 GPU 总利用率(任务管理器一致)
cpp
:: 所有GPU引擎总利用率(等价任务管理器GPU总占用)
typeperf "\GPU Engine(*)\Utilization Percentage"
2.分模块精准监控(3D / 解码 / 编码 / 计算)
cpp
:: 3D渲染引擎(游戏/图形渲染)
typeperf "\GPU Engine(*engtype_3D*)\Utilization Percentage"
:: 视频解码引擎(播放视频)
typeperf "\GPU Engine(*engtype_VideoDecode*)\Utilization Percentage"
:: 视频编码引擎(录屏/推流)
typeperf "\GPU Engine(*engtype_VideoEncode*)\Utilization Percentage"
:: 通用计算引擎(CUDA/OpenCL)
typeperf "\GPU Engine(*engtype_Compute*)\Utilization Percentage"
3.单 GPU 设备利用率(多显卡专用)
cpp
:: 查看所有GPU实例名称(找到你的GPU设备ID)
typeperf -qx "GPU Engine"
:: 指定单GPU监控(替换phys_0为你的设备ID)
typeperf "\GPU Engine(phys_0*)\Utilization Percentage"
4.实时监控(1 秒刷新,持续输出)
cpp
:: 同时监控GPU总利用率+3D渲染+显存使用
typeperf "\GPU Engine(*)\Utilization Percentage" "\GPU Engine(*engtype_3D*)\Utilization Percentage" "\GPU Adapter Memory(*)\Dedicated Usage" -si 1
5.采样 10 次、间隔 2 秒、输出 CSV 日志
cpp
typeperf "\GPU Engine(*)\Utilization Percentage" -si 2 -sc 10 -f CSV -o gpu_perf.csv -y
5.C++编程实现
5.1.windows API实现
启动控制台程序(比如 typeperf),并持续实时读取它的输出,直到程序退出。
cpp
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#define BUF_SIZE 4096
// 启动进程并持续读取输出
bool RunProcessAndReadOutput(LPCWSTR cmdLine)
{
HANDLE hRead = NULL, hWrite = NULL;
SECURITY_ATTRIBUTES sa = { 0 };
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// 创建管道
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
printf("创建管道失败!\n");
return false;
}
// 设置读句柄不被继承
SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(STARTUPINFOW);
si.hStdOutput = hWrite;
si.hStdError = hWrite;
si.dwFlags |= STARTF_USESTDHANDLES;
WCHAR cmdBuf[1024] = { 0 };
wcscpy_s(cmdBuf, cmdLine);
// 创建子进程
BOOL bRet = CreateProcessW(
NULL,
cmdBuf,
NULL,
NULL,
TRUE,
CREATE_NO_WINDOW, // 不弹出黑窗口(去掉则显示控制台)
NULL,
NULL,
&si,
&pi
);
if (!bRet) {
printf("启动进程失败!\n");
CloseHandle(hRead);
CloseHandle(hWrite);
return false;
}
// 关闭不需要的写端
CloseHandle(hWrite);
printf("==== 开始读取输出 ====\n\n");
char buf[BUF_SIZE] = { 0 };
DWORD bytesRead = 0;
// 循环读取,直到进程退出
while (true)
{
// 读取管道数据(实时输出)
if (ReadFile(hRead, buf, BUF_SIZE - 1, &bytesRead, NULL))
{
if (bytesRead == 0) break;
buf[bytesRead] = 0;
printf("%s", buf); // 直接打印输出
}
else
{
// 管道断开 = 进程退出
if (GetLastError() == ERROR_BROKEN_PIPE)
break;
}
// 检查进程是否已经退出
DWORD exitCode = 0;
GetExitCodeProcess(pi.hProcess, &exitCode);
if (exitCode != STILL_ACTIVE)
break;
}
printf("\n==== 进程退出 ====\n");
// 清理
CloseHandle(hRead);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
int main()
{
// 解决中文乱码
system("chcp 65001 >nul");
// ==================== 你要启动的命令 ====================
// 示例1:启动 typeperf 监控CPU
LPCWSTR cmd = L"typeperf \"\\Processor(_Total)\\% Processor Time\"";
// 示例2:持续 ping
// LPCWSTR cmd = L"ping 127.0.0.1 -t";
// 示例3:你自己的控制台程序
// LPCWSTR cmd = L"D:\\myapp.exe";
RunProcessAndReadOutput(cmd);
printf("\n按任意键退出...\n");
_getch();
return 0;
}
5.2.Qt实现(跨平台)
关键代码:
cpumemorylabel.h
cpp
#ifndef CPUMEMORYLABEL_H
#define CPUMEMORYLABEL_H
/**
* CPU内存显示控件 作者:feiyangqingyun(QQ:517216493) 2016-11-18
* 1. 实时显示当前CPU占用率。
* 2. 实时显示内存使用情况。
* 3. 包括共多少内存、已使用多少内存。
* 4. 全平台通用,包括windows、linux、ARM。
* 5. 发出信号通知占用率和内存使用情况等,以便自行显示到其他地方。
*/
#include <QLabel>
class QProcess;
#ifdef quc
class Q_DECL_EXPORT CpuMemoryLabel : public QLabel
#else
class CpuMemoryLabel : public QLabel
#endif
{
Q_OBJECT
Q_PROPERTY(bool showText READ getShowText WRITE setShowText)
public:
explicit CpuMemoryLabel(QWidget *parent = 0);
~CpuMemoryLabel();
private:
quint64 totalNew, idleNew, totalOld, idleOld;
quint64 cpuPercent; //CPU百分比
quint64 memoryPercent; //内存百分比
quint64 memoryAll; //所有内存
quint64 memoryUse; //已用内存
quint64 memoryFree; //空闲内存
QTimer *timerCPU; //定时器获取CPU信息
QTimer *timerMemory; //定时器获取内存信息
QProcess *process; //执行命令行
bool showText; //自己显示值
private slots:
void getCPU(); //获取cpu
void getMemory(); //获取内存
void readData(); //读取数据
void setData(); //设置数据
public:
//默认尺寸和最小尺寸
QSize sizeHint() const;
QSize minimumSizeHint() const;
//获取和设置是否显示文本
bool getShowText() const;
void setShowText(bool showText);
public Q_SLOTS:
//开始启动服务
void start(int interval);
//停止服务
void stop();
Q_SIGNALS:
//文本改变信号
void textChanged(const QString &text);
//cpu和内存占用情况数值改变信号
void valueChanged(quint64 cpuPercent, quint64 memoryPercent, quint64 memoryAll, quint64 memoryUse, quint64 memoryFree);
};
#endif // CPUMEMORYLABEL_H
cpumemorylabel.cpp
cpp
#pragma execution_character_set("utf-8")
#include "cpumemorylabel.h"
#include "qtimer.h"
#include "qprocess.h"
#include "qdebug.h"
#ifdef Q_OS_WIN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x502
#endif
#include "windows.h"
#endif
#define MB (1024 * 1024)
#define KB (1024)
CpuMemoryLabel::CpuMemoryLabel(QWidget *parent) : QLabel(parent)
{
totalNew = idleNew = totalOld = idleOld = 0;
cpuPercent = 0;
memoryPercent = 0;
memoryAll = 0;
memoryUse = 0;
//获取CPU占用情况定时器
timerCPU = new QTimer(this);
connect(timerCPU, SIGNAL(timeout()), this, SLOT(getCPU()));
//获取内存占用情况定时器
timerMemory = new QTimer(this);
connect(timerMemory, SIGNAL(timeout()), this, SLOT(getMemory()));
//执行命令获取
#ifndef Q_OS_WASM
process = new QProcess(this);
connect(process, SIGNAL(readyRead()), this, SLOT(readData()));
#endif
showText = true;
}
CpuMemoryLabel::~CpuMemoryLabel()
{
this->stop();
}
void CpuMemoryLabel::start(int interval)
{
this->getCPU();
this->getMemory();
if (!timerCPU->isActive()) {
timerCPU->start(interval);
}
if (!timerMemory->isActive()) {
timerMemory->start(interval + 1000);
}
}
void CpuMemoryLabel::stop()
{
#ifndef Q_OS_WASM
process->close();
#endif
if (timerCPU->isActive()) {
timerCPU->stop();
}
if (timerMemory->isActive()) {
timerMemory->stop();
}
}
void CpuMemoryLabel::getCPU()
{
#ifdef Q_OS_WIN
#if 0
static FILETIME lastIdleTime;
static FILETIME lastKernelTime;
static FILETIME lastUserTime;
FILETIME newIdleTime;
FILETIME newKernelTime;
FILETIME newUserTime;
//采用GetSystemTimes获取的CPU占用和任务管理器的不一致
GetSystemTimes(&newIdleTime, &newKernelTime, &newUserTime);
int offset = 31;
quint64 a, b;
quint64 idle, kernel, user;
a = (lastIdleTime.dwHighDateTime << offset) | lastIdleTime.dwLowDateTime;
b = (newIdleTime.dwHighDateTime << offset) | newIdleTime.dwLowDateTime;
idle = b - a;
a = (lastKernelTime.dwHighDateTime << offset) | lastKernelTime.dwLowDateTime;
b = (newKernelTime.dwHighDateTime << offset) | newKernelTime.dwLowDateTime;
kernel = b - a;
a = (lastUserTime.dwHighDateTime << offset) | lastUserTime.dwLowDateTime;
b = (newUserTime.dwHighDateTime << offset) | newUserTime.dwLowDateTime;
user = b - a;
cpuPercent = float(kernel + user - idle) * 100 / float(kernel + user);
lastIdleTime = newIdleTime;
lastKernelTime = newKernelTime;
lastUserTime = newUserTime;
this->setData();
#else
//获取系统版本区分win10
bool win10 = false;
#if (QT_VERSION >= QT_VERSION_CHECK(5,4,0))
win10 = (QSysInfo::productVersion().mid(0, 2).toInt() >= 10);
#else
win10 = (QSysInfo::WindowsVersion >= 192);
#endif
QString cmd = "\\Processor(_Total)\\% Processor Time";
if (win10) {
cmd = "\\Processor Information(_Total)\\% Processor Utility";
}
if (process->state() == QProcess::NotRunning) {
process->start("typeperf", QStringList() << cmd);
qDebug() << cmd;
}
#endif
#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
if (process->state() == QProcess::NotRunning) {
totalNew = idleNew = 0;
process->start("cat", QStringList() << "/proc/stat");
}
#endif
}
#include <QDebug>
void CpuMemoryLabel::getMemory()
{
#ifdef Q_OS_WIN
MEMORYSTATUSEX statex;
statex.dwLength = sizeof(statex);
GlobalMemoryStatusEx(&statex);
memoryPercent = statex.dwMemoryLoad;
memoryAll = statex.ullTotalPhys / MB;
memoryFree = statex.ullAvailPhys / MB;
memoryUse = memoryAll - memoryFree;
this->setData();
#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
if (process->state() == QProcess::NotRunning) {
process->start("cat", QStringList() << "/proc/meminfo");
}
#endif
}
void CpuMemoryLabel::readData()
{
#ifdef Q_OS_WIN
while (!process->atEnd()) {
QString s = QLatin1String(process->readLine());
//QString temp = s;
qDebug() << s;
s = s.split(",").last();
s.replace("\r", "");
s.replace("\n", "");
s.replace("\"", "");
if (!s.isEmpty() && s.length() < 10) {
cpuPercent = qRound(s.toFloat());
}
}
#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
while (!process->atEnd()) {
QString s = QLatin1String(process->readLine());
if (s.startsWith("cpu")) {
QStringList list = s.split(" ");
idleNew = list.at(5).toUInt();
foreach (QString value, list) {
totalNew += value.toUInt();
}
quint64 total = totalNew - totalOld;
quint64 idle = idleNew - idleOld;
cpuPercent = 100 * (total - idle) / total;
totalOld = totalNew;
idleOld = idleNew;
break;
} else if (s.startsWith("MemTotal")) {
s.replace(" ", "");
s = s.split(":").at(1);
memoryAll = s.left(s.length() - 3).toUInt() / KB;
} else if (s.startsWith("MemFree")) {
s.replace(" ", "");
s = s.split(":").at(1);
memoryFree = s.left(s.length() - 3).toUInt() / KB;
} else if (s.startsWith("Buffers")) {
s.replace(" ", "");
s = s.split(":").at(1);
memoryFree += s.left(s.length() - 3).toUInt() / KB;
} else if (s.startsWith("Cached")) {
s.replace(" ", "");
s = s.split(":").at(1);
memoryFree += s.left(s.length() - 3).toUInt() / KB;
memoryUse = memoryAll - memoryFree;
memoryPercent = 100 * memoryUse / memoryAll;
break;
}
}
#endif
this->setData();
}
void CpuMemoryLabel::setData()
{
//cpuPercent = (cpuPercent < 0 ? 0 : cpuPercent);
cpuPercent = (cpuPercent > 100 ? 0 : cpuPercent);
QString msg = QString("CPU %1% Mem %2% ( 已用 %3 MB / 共 %4 MB )").arg(cpuPercent).arg(memoryPercent).arg(memoryUse).arg(memoryAll);
if (showText) {
this->setText(msg);
}
Q_EMIT textChanged(msg);
Q_EMIT valueChanged(cpuPercent, memoryPercent, memoryAll, memoryUse, memoryFree);
}
QSize CpuMemoryLabel::sizeHint() const
{
return QSize(300, 30);
}
QSize CpuMemoryLabel::minimumSizeHint() const
{
return QSize(30, 10);
}
bool CpuMemoryLabel::getShowText() const
{
return this->showText;
}
void CpuMemoryLabel::setShowText(bool showText)
{
this->showText = showText;
}
完整代码:
通过网盘分享的文件:cpumemorylabel.zip
链接: https://pan.baidu.com/s/1I1out9H7dE_mdUF-JzElKA?pwd=1234 提取码: 1234
运行如下图所示:

6.高级用法与场景
1.批量监控脚本(Windows 批处理)
cpp
@echo off
set INTERVAL=5
set SAMPLES=30
set OUTPUT=system_perf_%date:~0,4%%date:~5,2%%date:~8,2%.csv
echo 开始监控系统性能...
typeperf -cf counters.txt -si %INTERVAL% -sc %SAMPLES% -f CSV -o %OUTPUT% -y
echo 监控完成!数据已保存到 %OUTPUT%
pause
2.结合 PowerShell 进行数据分析
cpp
# 读取CSV文件并显示CPU使用率趋势
$data = Import-Csv -Path "cpu_log.csv" -Header "时间戳", "CPU使用率" -Skip 2
$data | Select-Object -Last 10 | Format-Table
3.与其他工具配合
- logman:创建更复杂的性能日志会话
- relog:转换 / 合并性能日志文件(支持 CSV→BLG)
- perfmon:图形化查看性能计数器与日志文件
7.常用性能计数器速查
| 监控目标 | 计数器路径 | 说明 |
|---|---|---|
| CPU | \Processor(_Total)\% Processor Time |
总 CPU 使用率 |
| 内存 | \Memory\Available MBytes |
可用内存 (MB) |
| 磁盘 | \PhysicalDisk(_Total)\% Disk Time |
磁盘繁忙时间百分比 |
| 磁盘 IO | \PhysicalDisk(_Total)\Disk Bytes/sec |
磁盘读写速率 |
| 网络 | \Network Interface(*)\Bytes Total/sec |
网络总吞吐量 |
| 进程 | \Process(chrome)\% Processor Time |
特定进程 CPU 使用率 |
8.总结
TypePerf 是 Windows 系统管理员与开发人员的必备工具,尤其适合:
- 服务器后台性能监控
- 自动化性能测试脚本
- 系统瓶颈分析
- 长期性能趋势记录
通过命令行参数组合,可灵活定制监控方案,配合日志分析工具实现深度性能洞察。如需图形化界面,可使用 perfmon 工具;如需更复杂的日志管理,可结合 logman 命令。