用CBrother监视windows电脑CPU占用、内存占用、NVIDIA显卡显存占用

工作中遇到一个软件总是莫名的崩溃到nvwgf2umx.dll,网上都说是显卡驱动问题,但是更新了驱动依然有该问题,于是怀疑是不是系统资源耗尽了。

为了定位以上问题,是用CBrother写了一个脚本定时读取数据写进日志里,这样可以根据软件崩溃时间看看当时的系统资源情况,最后发现还真的是有内存和显存泄漏,可帮了我大忙了。

import lib/consoleprocess
import lib/windows/winapi
import CBCLib.code

/*typedef struct _MEMORYSTATUSEX {
    DWORD dwLength;
    DWORD dwMemoryLoad;
    DWORDLONG ullTotalPhys;
    DWORDLONG ullAvailPhys;
    DWORDLONG ullTotalPageFile;
    DWORDLONG ullAvailPageFile;
    DWORDLONG ullTotalVirtual;
    DWORDLONG ullAvailVirtual;
    DWORDLONG ullAvailExtendedVirtual;
} MEMORYSTATUSEX, *LPMEMORYSTATUSEX;*/
var MEMORYSTATUSEX = new CLibStruct("int","int","int64","int64","int64","int64","int64","int64","int64");

/**
typedef struct _PDH_FMT_COUNTERVALUE {
    DWORD    CStatus;
    union {
        LONG        longValue;
        double      doubleValue;
        LONGLONG    largeValue;
        LPCSTR      AnsiStringValue;
        LPCWSTR     WideStringValue;
    };
} PDH_FMT_COUNTERVALUE, * PPDH_FMT_COUNTERVALUE;
 */
 var PDH_FMT_COUNTERVALUE = new CLibStruct("int","double","double");

@logger
function logger_config()
{
    var fileLogger = new logger::LoggerOutputFile(null,"freeMemory","%Y-%m-%d");
    var consoleLogger = new logger::LoggerOutputConsole();
    logger::addLoggerOutput(fileLogger,"[%d] %m");
    logger::addLoggerOutput(consoleLogger,"%m");
}

var rootlogger = logger::getLogger();

function getGPUFreeMemory(console)
{
    console.write("nvidia-smi --query-gpu=memory.free --format=csv
");
}

var g_CounteraValue = null;
var g_Pdh_PdhOpenQuery_func = null;
var g_Pdh_PdhAddCounter_func = null;
var g_Pdh_PdhCollectQueryData_func = null;
var g_Pdh_PdhGetFormattedCounterValue_func = null;
var g_query = null;
var g_counter = null;
var pdhdll = new CLib("pdh.dll");

function getCpuUsageRate()
{
    if (g_CounteraValue == null)
    {
        g_CounteraValue = new CLibStructData(PDH_FMT_COUNTERVALUE);
        g_CounteraValue.setInt(0,0);
        g_CounteraValue.setPointer(1,null);
		
        if(!pdhdll.load())
        {
            print "pdh.dll load err!";
            return;
        }

        g_Pdh_PdhOpenQuery_func = pdhdll.findFunc("PdhOpenQueryW","int","pointer","pointer","pointer");
        g_Pdh_PdhAddCounter_func = pdhdll.findFunc("PdhAddCounterA","int","pointer","string","pointer","pointer");
        g_Pdh_PdhCollectQueryData_func = pdhdll.findFunc("PdhCollectQueryData","int","pointer");
        g_Pdh_PdhGetFormattedCounterValue_func = pdhdll.findFunc("PdhGetFormattedCounterValue","int","pointer","int","pointer","pointer");

        var addr = new CLibPointer();
        addr.malloc(8);
        var res = g_Pdh_PdhOpenQuery_func.callFunc(null,null,addr);
        g_query = addr.readPointer();
        addr.free();

        if(res == 0)
        {
            var addr = new CLibPointer();
            addr.malloc(8);
            g_Pdh_PdhAddCounter_func.callFunc(g_query,"\Processor Information(_Total)\% Processor Utility",null,addr);
            g_counter = addr.readPointer();
            addr.free();
        }
    }

    var res = g_Pdh_PdhCollectQueryData_func.callFunc(g_query);
    if(res != 0)
    {
        return;
    }
    g_Pdh_PdhGetFormattedCounterValue_func.callFunc(g_counter,0x00000200,addr,g_CounteraValue.addr());
    var rateCpu = g_CounteraValue.getDouble(1);	
    rootlogger.info("cpu rate: " + rateCpu);
}

var g_kernel32_GlobalMemoryStatusEx_func = null;
function getFreeMemory()
{
    var structData = new CLibStructData(MEMORYSTATUSEX);
    structData.setInt(0,MEMORYSTATUSEX.size());
    structData.setInt(1,0);
    structData.setInt64(2,0);
    structData.setInt64(3,0);
    structData.setInt64(4,0);
    structData.setInt64(5,0);
    structData.setInt64(6,0);
    structData.setInt64(7,0);
    structData.setInt64(8,0);

    if (g_kernel32_GlobalMemoryStatusEx_func == null)
    {
        var kernel32dll = new CLib("kernel32.dll");
        if(!kernel32dll.load())
        {
            print "kernel32.dll load err!";
            return;
        }		
        g_kernel32_GlobalMemoryStatusEx_func = kernel32dll.findFunc("GlobalMemoryStatusEx","int","pointer");
    }
	
    var res = g_kernel32_GlobalMemoryStatusEx_func.callFunc(structData.addr());
    var totalMem = structData.getInt64(2);
    var freeMem = structData.getInt64(3);
    rootlogger.info("memory: " + freeMem / 1024 + " KB / " + totalMem / 1024 + " KB");
}

function main(parm)
{	
    var console = new ConsoleProcess();
    console.start();
	
    rootlogger.info("console pid:" + console.getChildPid());

    var str = console.read();
    rootlogger.info(str_convert(str,"ascii","utf-8"));	
    getGPUFreeMemory(console);
	
    while(true)
    {
        var l = console.readLine();
        if(l == null)
        {
            Sleep(1000 * 5);
            getFreeMemory();
            getCpuUsageRate();
            getGPUFreeMemory(console);
            continue;
        }
        if(strfind(l,">") == -1 && strfind(l,"--query-gpu") == -1)
        {
            rootlogger.info(str_convert(l,"ascii","utf-8"));
        }
    }

    console.closeProcess();
}

运行后会在脚本旁边写一个日志。出现问题直接在日志里查时间就行了。

有些电脑取显存这句命令行不行,"nvidia-smi --query-gpu=memory.free --format=csv",可以换一下两个试试:

"C:\Program Files\NVIDIA Corporation\NVSMI\nvidia-smi.exe --query-gpu=memory.free --format=csv"

或者

"C:\Windows\System32\nvidia-smi.exe --query-gpu=memory.free --format=csv"

取决于你nv驱动程序装在哪里