如何计算CPU核心频率

2024-06-28

我正在尝试使用 RDTSC,但似乎我的方法获取核心速度可能是错误的:

#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <iostream>

using namespace std;

struct Core
{
    int CoreNumber;
};

static void startMonitoringCoreSpeeds(void *param)
{
    Core core = *((Core *)param);
    SetThreadAffinityMask(GetCurrentThread(), 1 << core.CoreNumber);
    while (true)
    {
        DWORD64 first = __rdtsc();
        Sleep(1000);
        DWORD64 second = __rdtsc();
        cout << "Core " << core.CoreNumber << " has frequency " << ((second - first)*pow(10, -6)) << " MHz" << endl;
    }
}

int GetNumberOfProcessorCores()
{
    DWORD process, system;
    if (GetProcessAffinityMask(GetCurrentProcess(), &process, &system))
    {
        int count = 0;
        for (int i = 0; i < 32; i++)
        {
            if (system & (1 << i))
            {
                count++;
            }
        }
        return count;
    }
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    return sysinfo.dwNumberOfProcessors;
}

int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < GetNumberOfProcessorCores(); i++)
    {
        Core *core = new Core {0};
        core->CoreNumber = i;
        _beginthread(startMonitoringCoreSpeeds, 0, core);
    }
    cin.get();
}

它总是打印出 3.3 GHz 左右的值,这是错误的,因为 Turbo Boost 之类的东西会时不时地打开,而我的核心肯定会跳到 4.3 GHz。让我交叉参考这个想法背后的一些文章。

首先 (http://users.utcluj.ro/~ancapop/labscs/SCS2.pdf http://users.utcluj.ro/~ancapop/labscs/SCS2.pdf):“处理器核心上的 TSC 不同步。因此不确定进程是否在 从一个核心执行到另一核心时,测量不会受到影响。为了避免这个问题,测量的进程的亲和力必须设置为仅一个核心,以防止进程迁移。”这告诉我,RDTSC 应该使用我设置的亲和力掩码为我的线程所在的每个核心返回不同的值,这很好。

第二,请查看这篇文章 (http://randomascii.wordpress.com/2011/07/29/rdtsc-in-the-age-of-sandybridge/ http://randomascii.wordpress.com/2011/07/29/rdtsc-in-the-age-of-sandybridge/):“如果您需要一个跨内核工作且可用于测量时间的一致计时器,那么这是个好消息。如果您想测量实际的 CPU 时钟周期,那么您就不走运了。如果您希望在大范围内实现一致性CPU 系列那么你就太糟糕了。更新:Intel 系统编程指南的第 16.11 节记录了时间戳计数器的这种行为。粗略地说,它表示在较旧的处理器上时钟速率会发生变化,但在较新的处理器上它保持统一.Constant TSC 的最后一句话是:“这是向前发展的建筑行为。”好的,这告诉我 RDTSC 保持一致,这使得我的上述结果有意义,因为我的 CPU 核心额定为标准 3.3 GHz...

这确实引出了一个问题,像 Intel 的 Turbo Boost Technology Monitor 和 Piriform 的 Speccy 以及 CPUID 的 CPU-Z 这样的应用程序如何在进行 Turbo Boost 时实时测量处理器的时钟速度?


完整的解决方案如下。我已经调整了MSDN 上的 IOCTL 示例驱动程序 http://code.msdn.microsoft.com/windowshardware/IOCTL-a583bbeb去做这个。请注意,IOCTL 示例是我能找到的唯一相关的 WDM 示例骨架驱动程序,也是我能找到的最接近 WDM 模板的东西 https://stackoverflow.com/questions/24016441/why-is-there-no-wdm-kernel-mode-driver-template-in-windows-driver-kit因为 WDK 中的大多数开箱即用的内核模式模板都是基于 WDF 的驱动程序(任何 WDM 驱动程序模板实际上都是空白的,绝对没有源代码),但是我见过的唯一执行此输入/输出的示例逻辑是通过基于 WDM 的驱动程序 http://www.codeproject.com/Articles/9575/Driver-Development-Part-Introduction-to-Implemen。另外,我一路上学到了一些有趣的事实:内核驱动程序不喜欢浮点运算,并且您不能使用“windows.h”,这实际上限制了您只能使用“ntddk.h”,这是一个特殊的内核模式头。这也意味着我无法在内核模式内完成所有计算,因为我无法调用其中的 QueryPerformanceFrequency 等函数,因此我必须获取时间戳之间的平均性能比并将它们返回到用户模式以进行某些计算(如果没有 QueryPerformanceFrequency,您从存储像 QueryPerformanceCounter 使用的刻度的 CPU 寄存器中获得的值是无用的,因为您不知道步长;也许有一个解决方法,但我选择只使用平均值,因为它工作得非常好) 。另外,根据一秒睡眠,我使用它的原因是因为否则你几乎在多个线程上进行旋转计算,这确实会扰乱你的计算,因为你的频率会随着每个核心不断检查来自 QueryPerformanceCounter 的结果而上升(你当你进行更多的计算时,驱动你的核心) - 更不用说 - 它是一个比率......所以增量时间并不那么重要,因为它的每次周期......你总是可以增加增量,它仍然应该给你相对于步长相同的比率。此外,这已经是我所能做到的最简约的了。祝你好运,使它比这个小得多或短得多。另外,如果你想安装驱动程序,你有两个选择 https://stackoverflow.com/questions/24091822/how-can-i-install-this-driver除非您想从第三方购买代码签名证书,否则两者都很糟糕,所以选择一个并接受它。我们先从驱动程序开始:

driver.c:

//
// Include files.
//

#include <ntddk.h>          // various NT definitions
#include <string.h>
#include <intrin.h>

#include "driver.h"

#define NT_DEVICE_NAME      L"\\Device\\KernelModeDriver"
#define DOS_DEVICE_NAME     L"\\DosDevices\\KernelModeDriver"

#if DBG
#define DRIVER_PRINT(_x_) \
                DbgPrint("KernelModeDriver.sys: ");\
                DbgPrint _x_;

#else
#define DRIVER_PRINT(_x_)
#endif

//
// Device driver routine declarations.
//

DRIVER_INITIALIZE DriverEntry;

_Dispatch_type_(IRP_MJ_CREATE)
_Dispatch_type_(IRP_MJ_CLOSE)
DRIVER_DISPATCH DriverCreateClose;

_Dispatch_type_(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH DriverDeviceControl;

DRIVER_UNLOAD DriverUnloadDriver;

VOID
PrintIrpInfo(
    PIRP Irp
    );
VOID
PrintChars(
    _In_reads_(CountChars) PCHAR BufferAddress,
    _In_ size_t CountChars
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( PAGE, DriverCreateClose)
#pragma alloc_text( PAGE, DriverDeviceControl)
#pragma alloc_text( PAGE, DriverUnloadDriver)
#pragma alloc_text( PAGE, PrintIrpInfo)
#pragma alloc_text( PAGE, PrintChars)
#endif // ALLOC_PRAGMA


NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT   DriverObject,
    _In_ PUNICODE_STRING      RegistryPath
    )
/*++

Routine Description:
    This routine is called by the Operating System to initialize the driver.

    It creates the device object, fills in the dispatch entry points and
    completes the initialization.

Arguments:
    DriverObject - a pointer to the object that represents this device
    driver.

    RegistryPath - a pointer to our Services key in the registry.

Return Value:
    STATUS_SUCCESS if initialized; an error otherwise.

--*/

{
    NTSTATUS        ntStatus;
    UNICODE_STRING  ntUnicodeString;    // NT Device Name "\Device\KernelModeDriver"
    UNICODE_STRING  ntWin32NameString;    // Win32 Name "\DosDevices\KernelModeDriver"
    PDEVICE_OBJECT  deviceObject = NULL;    // ptr to device object

    UNREFERENCED_PARAMETER(RegistryPath);

    RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME );

    ntStatus = IoCreateDevice(
        DriverObject,                   // Our Driver Object
        0,                              // We don't use a device extension
        &ntUnicodeString,               // Device name "\Device\KernelModeDriver"
        FILE_DEVICE_UNKNOWN,            // Device type
        FILE_DEVICE_SECURE_OPEN,        // Device characteristics
        FALSE,                          // Not an exclusive device
        &deviceObject );                // Returned ptr to Device Object

    if ( !NT_SUCCESS( ntStatus ) )
    {
        DRIVER_PRINT(("Couldn't create the device object\n"));
        return ntStatus;
    }

    //
    // Initialize the driver object with this driver's entry points.
    //

    DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDeviceControl;
    DriverObject->DriverUnload = DriverUnloadDriver;

    //
    // Initialize a Unicode String containing the Win32 name
    // for our device.
    //

    RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME );

    //
    // Create a symbolic link between our device name  and the Win32 name
    //

    ntStatus = IoCreateSymbolicLink(
                        &ntWin32NameString, &ntUnicodeString );

    if ( !NT_SUCCESS( ntStatus ) )
    {
        //
        // Delete everything that this routine has allocated.
        //
        DRIVER_PRINT(("Couldn't create symbolic link\n"));
        IoDeleteDevice( deviceObject );
    }


    return ntStatus;
}


NTSTATUS
DriverCreateClose(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
/*++

Routine Description:

    This routine is called by the I/O system when the KernelModeDriver is opened or
    closed.

    No action is performed other than completing the request successfully.

Arguments:

    DeviceObject - a pointer to the object that represents the device
    that I/O is to be done on.

    Irp - a pointer to the I/O Request Packet for this request.

Return Value:

    NT status code

--*/

{
    UNREFERENCED_PARAMETER(DeviceObject);

    PAGED_CODE();

    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;

    IoCompleteRequest( Irp, IO_NO_INCREMENT );

    return STATUS_SUCCESS;
}

VOID
DriverUnloadDriver(
    _In_ PDRIVER_OBJECT DriverObject
    )
/*++

Routine Description:

    This routine is called by the I/O system to unload the driver.

    Any resources previously allocated must be freed.

Arguments:

    DriverObject - a pointer to the object that represents our driver.

Return Value:

    None
--*/

{
    PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
    UNICODE_STRING uniWin32NameString;

    PAGED_CODE();

    //
    // Create counted string version of our Win32 device name.
    //

    RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );


    //
    // Delete the link from our device name to a name in the Win32 namespace.
    //

    IoDeleteSymbolicLink( &uniWin32NameString );

    if ( deviceObject != NULL )
    {
        IoDeleteDevice( deviceObject );
    }



}

NTSTATUS
DriverDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

    This routine is called by the I/O system to perform a device I/O
    control function.

Arguments:

    DeviceObject - a pointer to the object that represents the device
        that I/O is to be done on.

    Irp - a pointer to the I/O Request Packet for this request.

Return Value:

    NT status code

--*/

{
    PIO_STACK_LOCATION  irpSp;// Pointer to current stack location
    NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success
    ULONG               inBufLength; // Input buffer length
    ULONG               outBufLength; // Output buffer length
    void                *inBuf; // pointer to input buffer
    unsigned __int64    *outBuf; // pointer to the output buffer

    UNREFERENCED_PARAMETER(DeviceObject);

    PAGED_CODE();

    irpSp = IoGetCurrentIrpStackLocation( Irp );
    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if (!inBufLength || !outBufLength || outBufLength != sizeof(unsigned __int64)*2)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        goto End;
    }

    //
    // Determine which I/O control code was specified.
    //

    switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    {
    case IOCTL_SIOCTL_METHOD_BUFFERED:

        //
        // In this method the I/O manager allocates a buffer large enough to
        // to accommodate larger of the user input buffer and output buffer,
        // assigns the address to Irp->AssociatedIrp.SystemBuffer, and
        // copies the content of the user input buffer into this SystemBuffer
        //

        DRIVER_PRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n"));
        PrintIrpInfo(Irp);

        //
        // Input buffer and output buffer is same in this case, read the
        // content of the buffer before writing to it
        //

        inBuf = (void *)Irp->AssociatedIrp.SystemBuffer;
        outBuf = (unsigned __int64 *)Irp->AssociatedIrp.SystemBuffer;

        //
        // Read the data from the buffer
        //

        DRIVER_PRINT(("\tData from User :"));
        //
        // We are using the following function to print characters instead
        // DebugPrint with %s format because we string we get may or
        // may not be null terminated.
        //
        PrintChars(inBuf, inBufLength);

        //
        // Write to the buffer
        //

        unsigned __int64 data[sizeof(unsigned __int64) * 2];
        data[0] = __readmsr(232);
        data[1] = __readmsr(231);

        DRIVER_PRINT(("data[0]: %d", data[0]));
        DRIVER_PRINT(("data[1]: %d", data[1]));

        RtlCopyBytes(outBuf, data, outBufLength);

        //
        // Assign the length of the data copied to IoStatus.Information
        // of the Irp and complete the Irp.
        //

        Irp->IoStatus.Information = sizeof(unsigned __int64)*2;

        //
        // When the Irp is completed the content of the SystemBuffer
        // is copied to the User output buffer and the SystemBuffer is
        // is freed.
        //

       break;

    default:

        //
        // The specified I/O control code is unrecognized by this driver.
        //

        ntStatus = STATUS_INVALID_DEVICE_REQUEST;
        DRIVER_PRINT(("ERROR: unrecognized IOCTL %x\n",
            irpSp->Parameters.DeviceIoControl.IoControlCode));
        break;
    }

End:
    //
    // Finish the I/O operation by simply completing the packet and returning
    // the same status as in the packet itself.
    //

    Irp->IoStatus.Status = ntStatus;

    IoCompleteRequest( Irp, IO_NO_INCREMENT );

    return ntStatus;
}

VOID
PrintIrpInfo(
    PIRP Irp)
{
    PIO_STACK_LOCATION  irpSp;
    irpSp = IoGetCurrentIrpStackLocation( Irp );

    PAGED_CODE();

    DRIVER_PRINT(("\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n",
        Irp->AssociatedIrp.SystemBuffer));
    DRIVER_PRINT(("\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer));
    DRIVER_PRINT(("\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n",
        irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
    DRIVER_PRINT(("\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n",
        irpSp->Parameters.DeviceIoControl.InputBufferLength));
    DRIVER_PRINT(("\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n",
        irpSp->Parameters.DeviceIoControl.OutputBufferLength ));
    return;
}

VOID
PrintChars(
    _In_reads_(CountChars) PCHAR BufferAddress,
    _In_ size_t CountChars
    )
{
    PAGED_CODE();

    if (CountChars) {

        while (CountChars--) {

            if (*BufferAddress > 31
                 && *BufferAddress != 127) {

                KdPrint (( "%c", *BufferAddress) );

            } else {

                KdPrint(( ".") );

            }
            BufferAddress++;
        }
        KdPrint (("\n"));
    }
    return;
}

driver.h:

//
// Device type           -- in the "User Defined" range."
//
#define SIOCTL_TYPE 40000
//
// The IOCTL function codes from 0x800 to 0xFFF are for customer use.
//
#define IOCTL_SIOCTL_METHOD_IN_DIRECT \
    CTL_CODE( SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS  )

#define IOCTL_SIOCTL_METHOD_OUT_DIRECT \
    CTL_CODE( SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS  )

#define IOCTL_SIOCTL_METHOD_BUFFERED \
    CTL_CODE( SIOCTL_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS  )

#define IOCTL_SIOCTL_METHOD_NEITHER \
    CTL_CODE( SIOCTL_TYPE, 0x903, METHOD_NEITHER , FILE_ANY_ACCESS  )


#define DRIVER_FUNC_INSTALL     0x01
#define DRIVER_FUNC_REMOVE      0x02

#define DRIVER_NAME       "ReadMSRDriver"

现在,这是加载并使用驱动程序的应用程序(Win32 控制台应用程序):

频率计算器.cpp:

#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strsafe.h>
#include <process.h>
#include "..\KernelModeDriver\driver.h"

using namespace std;

BOOLEAN
ManageDriver(
_In_ LPCTSTR  DriverName,
_In_ LPCTSTR  ServiceName,
_In_ USHORT   Function
);

HANDLE hDevice;
TCHAR driverLocation[MAX_PATH];

void InstallDriver()
{
    DWORD errNum = 0;
    GetCurrentDirectory(MAX_PATH, driverLocation);
    _tcscat_s(driverLocation, _T("\\KernelModeDriver.sys"));

    std::wcout << "Trying to install driver at " << driverLocation << std::endl;

    //
    // open the device
    //

    if ((hDevice = CreateFile(_T("\\\\.\\KernelModeDriver"),
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL)) == INVALID_HANDLE_VALUE) {

        errNum = GetLastError();

        if (errNum != ERROR_FILE_NOT_FOUND) {

            printf("CreateFile failed!  ERROR_FILE_NOT_FOUND = %d\n", errNum);

            return;
        }

        //
        // The driver is not started yet so let us the install the driver.
        // First setup full path to driver name.
        //

        if (!ManageDriver(_T(DRIVER_NAME),
            driverLocation,
            DRIVER_FUNC_INSTALL
            )) {

            printf("Unable to install driver. \n");

            //
            // Error - remove driver.
            //

            ManageDriver(_T(DRIVER_NAME),
                driverLocation,
                DRIVER_FUNC_REMOVE
                );

            return;
        }

        hDevice = CreateFile(_T("\\\\.\\KernelModeDriver"),
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL);

        if (hDevice == INVALID_HANDLE_VALUE){
            printf("Error: CreatFile Failed : %d\n", GetLastError());
            return;
        }
    }
}

void UninstallDriver()
{
    //
    // close the handle to the device.
    //

    CloseHandle(hDevice);

    //
    // Unload the driver.  Ignore any errors.
    //
    ManageDriver(_T(DRIVER_NAME),
        driverLocation,
        DRIVER_FUNC_REMOVE
        );
}

double GetPerformanceRatio()
{
    BOOL bRc;
    ULONG bytesReturned;

    int input = 0;
    unsigned __int64 output[2];
    memset(output, 0, sizeof(unsigned __int64) * 2);

    //printf("InputBuffer Pointer = %p, BufLength = %d\n", &input, sizeof(&input));
    //printf("OutputBuffer Pointer = %p BufLength = %d\n", &output, sizeof(&output));

    //
    // Performing METHOD_BUFFERED
    //

    //printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n");

    bRc = DeviceIoControl(hDevice,
        (DWORD)IOCTL_SIOCTL_METHOD_BUFFERED,
        &input,
        sizeof(&input),
        output,
        sizeof(unsigned __int64)*2,
        &bytesReturned,
        NULL
        );

    if (!bRc)
    {
        //printf("Error in DeviceIoControl : %d", GetLastError());
        return 0;

    }
    //printf("    OutBuffer (%d): %d\n", bytesReturned, output);
    if (output[1] == 0)
    {
        return 0;
    }
    else
    {
        return (float)output[0] / (float)output[1];
    }
}

struct Core
{
    int CoreNumber;
};

int GetNumberOfProcessorCores()
{
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    return sysinfo.dwNumberOfProcessors;
}

float GetCoreFrequency()
{
    // __rdtsc: Returns the processor time stamp which records the number of clock cycles since the last reset.
    // QueryPerformanceCounter: Returns a high resolution time stamp that can be used for time-interval measurements.
    // Get the frequency which defines the step size of the QueryPerformanceCounter method.
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);
    // Get the number of cycles before we start.
    ULONG cyclesBefore = __rdtsc();
    // Get the Intel performance ratio at the start.
    float ratioBefore = GetPerformanceRatio();
    // Get the start time.
    LARGE_INTEGER startTime;
    QueryPerformanceCounter(&startTime);
    // Give the CPU cores enough time to repopulate their __rdtsc and QueryPerformanceCounter registers.
    Sleep(1000);
    ULONG cyclesAfter = __rdtsc();
    // Get the Intel performance ratio at the end.
    float ratioAfter = GetPerformanceRatio();
    // Get the end time.
    LARGE_INTEGER endTime;
    QueryPerformanceCounter(&endTime);
    // Return the number of MHz. Multiply the core's frequency by the mean MSR (model-specific register) ratio (the APERF register's value divided by the MPERF register's value) between the two timestamps.
    return ((ratioAfter + ratioBefore) / 2)*(cyclesAfter - cyclesBefore)*pow(10, -6) / ((endTime.QuadPart - startTime.QuadPart) / frequency.QuadPart);
}

struct CoreResults
{
    int CoreNumber;
    float CoreFrequency;
};

CRITICAL_SECTION printLock;

static void printResult(void *param)
{
    EnterCriticalSection(&printLock);
    CoreResults coreResults = *((CoreResults *)param);
    std::cout << "Core " << coreResults.CoreNumber << " has a speed of " << coreResults.CoreFrequency << " MHz" << std::endl;
    delete param;
    LeaveCriticalSection(&printLock);
}

bool closed = false;

static void startMonitoringCoreSpeeds(void *param)
{
    Core core = *((Core *)param);
    SetThreadAffinityMask(GetCurrentThread(), 1 << core.CoreNumber);
    while (!closed)
    {
        CoreResults *coreResults = new CoreResults();
        coreResults->CoreNumber = core.CoreNumber;
        coreResults->CoreFrequency = GetCoreFrequency();
        _beginthread(printResult, 0, coreResults);
        Sleep(1000);
    }
    delete param;
}

int _tmain(int argc, _TCHAR* argv[])
{
    InitializeCriticalSection(&printLock);
    InstallDriver();
    for (int i = 0; i < GetNumberOfProcessorCores(); i++)
    {
        Core *core = new Core{ 0 };
        core->CoreNumber = i;
        _beginthread(startMonitoringCoreSpeeds, 0, core);
    }
    std::cin.get();
    closed = true;
    UninstallDriver();
    DeleteCriticalSection(&printLock);
}

它使用 install.cpp,您可以从 IOCTL 示例中获取该文件。我将发布一个工作的、完全工作的和准备好的解决方案(显然带有代码)my blog http://www.dima.to/blog在接下来的几天里,如果不是今晚的话。

编辑:博客位于http://www.dima.to/blog/?p=101 http://www.dima.to/blog/?p=101(那里有完整的源代码)...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何计算CPU核心频率 的相关文章

  • Google Directions api Web 服务 - 在地图上显示响应。是否可以?

    有没有办法使用来自调用的 Google 方向 Web 服务的响应 例如来自如下 C 代码 var url System String Format http maps googleapis com maps api directions x
  • 有关堆栈大小的警告消息

    I use Visual Studio 2010 with Code Analysis活性 在我的代码中 有一行在函数中分配一些内存 TCHAR someString 40000 代码分析抛出警告信息 警告 C6262 函数使用 40000
  • WTL 子窗口事件处理

    我正在开发窗口应用程序 因为我在左侧和右侧有 2 个子窗口 我想分别处理两个窗口的输入事件 如何实现 My code class EditorWindow public DxWindow public CSplitterWindow m v
  • 使用 fork/execvp 和系统调用之间的区别

    使用 system 执行二进制文件与使用 fork execvp 组合执行二进制文件有什么区别 安全性 可移植性 性能方面是否存在差异 系统还使用了一个fork exec 组合 如果你这样做fork exec您自己可以与正在运行的进程并行执
  • ASP.NET身份更改密码

    我需要能够由管理员更改用户密码 因此 管理员不应输入用户的当前密码 他应该能够设置新密码 我查看了 ChangePasswordAsync 方法 但该方法需要输入旧密码 因此 此方法不适合此任务 因此我通过以下方式做到了 HttpPost
  • 是否有合法的方法使用运算符 << 打印元组和对?

    我有一组模板 函数 允许我打印元组 对 假设元组 对中的每种类型都有operator lt lt 为其定义的 不幸的是 由于 17 4 3 1 添加我的内容是非法的operator lt lt 重载到std 有没有其他方法可以让 ADL 找
  • 如何使用鼠标指针和键盘快捷键捕获文本?

    我想使用 C 或 java 使用鼠标指针和键盘快捷键从打开的窗口捕获文本 喜欢babylon http babylon com 所以 我需要知道什么以及如何实施 我需要使用哪些库 或者我可以使用 winapi 吗 使用脚本语言创建您想要执行
  • 从 ASP.NET 插入到 MS Access

    我们正在尝试建立一个专门用于内联网的服务台票务系统 决定使用 Visual Studio 2008 Express 的 ASP NET C 如果需要的话 我们有一个完整版本 没什么花哨的 几页抓取 NTLM 信息 系统信息并将其与问题一起存
  • 如何更改 gdb 中的值

    所以我有这个家庭作业代码 我必须使用 gdb 进行调试 我发现了问题 但不知道如何使用gdb来改变它 define ARRAYSIZE 12 for i ARRAYSIZE 2 i gt 0 i for j i j lt ARRAYSIZE
  • 字符集中字符的顺序

    是否通过标准保证字符的顺序 例如 我可以算出字符集表中 1 符号后面跟着 2 符号吗 或者它是特定于平台的 1999 年的 C 标准对字符集是这样规定的 基本源字符集和基本执行字符集都应具有以下成员 拉丁字母表中的 26 个大写字母 拉丁字
  • 错误:非聚合类型“vector”无法使用初始值设定项列表进行初始化

    我是 C 的初学者 每次跑步时vector
  • 从 C# 运行多个 python 脚本

    我希望有人能够在这里帮助我 我对 C 比较陌生 正在尝试执行我在 C winform 应用程序中编写的一些 Python 代码 我想做的是从 winform 中的文本框中输入名称 并让它通过 python 脚本进行处理 并在 winform
  • 如何在没有 ADO 包装器的情况下在 C# 中使用 SQLite

    这可能吗 我读过的所有文章都指出 ADO 包装器是必要的 但 SQLite 网站暗示除了 DLL 之外不需要其他任何东西 如果可能的话 我希望那里有代码示例 看这里 http www sqlite org cvstrac wiki p Sq
  • SQL:使用 1 个查询更新一行并返回列值

    我需要更新表中的一行 并从中获取列值 我可以这样做 UPDATE Items SET Clicks Clicks 1 WHERE Id Id SELECT Name FROM Items WHERE Id Id 这会生成 2 个对该表的计划
  • 无法从 GetSystemTime() 获取毫秒

    我正在尝试打印秒和毫秒分辨率计时 我正在使用GetSystemTime 这是我的代码 GetSystemTime datetime RETAILMSG 1 T Time After Data Sent to USB d d r n date
  • WPF ICollectionView 过滤

    我写了一个代码过滤项目在组合框中 我的问题是 你会怎么做 我认为这种带有反射的解决方案可能非常有效slow ICollectionView view CollectionViewSource GetDefaultView newValue
  • 将 double 转换为 float 后值不正确

    我有一些由 gcc gcc GCC 4 4 4 20100726 Red Hat 4 4 4 13 编译的执行高精度算术的 C 代码 计算的最终结果是一个 double 值 其值为 622 07999995861189 我是将双精度型转换为
  • 用于获取 Vista/7 shell 缩略图的 IShellItemImageFactory 接口是否已损坏?

    我想用IShellItemImageFactory http msdn microsoft com en us library bb761084 28VS 85 29 aspx检索文件的外壳缩略图 根据 MSDN 文档 如果我传入 256x
  • ListView 内的 TextBox 绑定到对象,双向绑定不起作用

    Edit 好吧 在尝试了无数次但没有成功之后 我创建了一个非常小的 Wpf 应用程序 您可以直接复制此代码 请注意 当您更改文本框中的值并按 测试 按钮时 这些值永远不会更新 我不明白为什么双向绑定不起作用 请帮忙 这是 xaml
  • HTTPS文件下载C#

    我需要下载隐藏在 HTTPS 连接后面的文件 我对下载安全网站后面的文件不熟悉 我尝试使用凭据来解决此问题 但无济于事 据我所知 您需要创建并使用证书来完成此操作 但我没有找到任何示例 任何帮助表示赞赏 这就是我现在所拥有的 WebClie

随机推荐