这是检索和存储 QueryPerformanceCounter 检索值的最快方法吗?

问题描述

我正在尝试用 VBA 编写一个基准测试程序。我的目标是尽可能多地排除延迟(基准)代码的因素。在测试中,LongLong 似乎比 Currency 快一点,但每个人都使用 UDT 或 Currency 数据类型。

我的主要问题是:检索到的 QPC 值的最佳数据类型是什么?

为了尽量减少调用基准程序的时间,最好的方法似乎是将检索到的 QueryPerformanceCounter (QPC) 值存储在一个数组中。然后在基准代码完成后处理存储的值。由于处理发生在之后,我不关心处理值本身所需的时间。 Windows API kernel32 函数 QPC 的返回类型为 LARGE_INTEGER:

typedef union _LARGE_INTEGER {
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } DUMMYSTRUCTNAME;
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } u;
  LONGLONG QuadPart;
} LARGE_INTEGER;

根据您使用的是 64 位系统,有两种或三种选择可以在 VBA 中捕获此数据类型:

  1. 具有两个 Long 值的用户定义类型 (UDT)(引导 u.LowPart 和 u.HighPart)
  2. Currency 捕获并转换 Quadpart ???
  3. LongLong 捕获 QuadPart(仅适用于 64 位 Office)

由于调用 QPC 函数比存储值本身花费更多的时间,我无法直接测试什么是最佳选择。但是,我确实测试了存储这些数据类型本身的值的最有效方法是什么。存储 UDT(设置其值之一 (usd.low = udt.low) 或仅将整个 UDT 实例设置为另一个实例 (udt1 = udt2))似乎比存储 LongLong、Currency 或任何其他数字花费两倍的时间数据类型相同。 因此,就速度而言,此选项已失效(假设差异不是因为 cpu 分支,而是因为 UDT 实际上必须存储 2 个单独的值而不是一个)。

这留下了两个选项,LongLong 和 Currency。 (或者你们中的一个人在 32 位系统上,但我不是)。 LongLongCurrency 都是 64 位(8 字节)整数数据类型,而货币据说是 VBA 提供的最准确的数据类型。它们都具有相同的范围,唯一的区别是 Currency 类型的逗号向左移动了 4 位。在测试 QPC 检索值时,货币似乎总是与放大的 LongLong 检索值相同(货币 = 10000 * LongLong)。只是为了清楚这两个值将返回什么(仅参数不同)。

Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (tickLongLong As LongLong) As Long
Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (tickCurrency As Currency) As Long

tickLongLong-->  3563633494792
tickCurrency-->  356363349,4792

我遇到了许多使用 UDTCurrency 数据类型的代码。它们都没有使用 LongLong 返回类型,但它似乎是最接近实际返回类型的 QuadPart,它也是 LongLong。

似乎在将 LongLong 转换为货币时,唯一需要做的就是将逗号移动 4 位。但这仍然需要一些额外的步骤。这让我认为以 LongLong 形式检索值应该(一点点)更快。我无法对其进行测试,因为调用 QPC 函数本身比将检索到的 LongLong 类型的值转换为货币花费更多的时间。

我唯一可以测试的是存储 LongLong 或将 LongLong 转换为货币所需的时间,反之亦然。乍一看似乎没有什么区别,而且 Currency 甚至更快,但最终测试表明 LongLong 类型(超过 1000 万次迭代的循环)实际上是。

Private Type Tudt
    low As Long
    high As Long
End Type
Private Sub test()
Dim i As Long,timer As Currency
Dim udt As Tudt: udt.low = 1000&: udt.high = 1000&
Dim lonlon As LongLong: lonlon = 1000^
Dim cur As Currency: cur = 1000@
Dim arUdt() As Tudt: ReDim arUdt(1 To 10000000)
Dim arLonlon() As LongLong: ReDim arLonlon(1 To 10000000)
Dim arCur() As Currency: ReDim arCur(1 To 10000000)

timer = MicroTimer
For i = 2 To 10000000 '10 million (63 milliseconds when empty)

''assigning the same value to each element in the array
arUdt(i).low = 1&      '165 milliseconds
arUdt(i) = udt         '215 milliseconds
arLonlon(i) = 1^       '103 milliseconds
arCur(i) = 1@          '103 milliseconds
'conclusion: setting only one of the UDT bounds
'already takes more then 50% more time. Setting
'a whole udt (what would be returned by the QPC)
'takes twice the time.

'assigning a random value in the array to exclude branching
arLonlon(i) = CLngLng(Int((1000 * Rnd) + 1))   '611-625 milliseconds
arCur(i) = CCur(Int((1000 * Rnd) + 1))         '580-595 milliseconds
'conclusion: assinging a random LongLong value
'takes longer,possibly because of Int conversion?

'excluding branching and int conveRSSion by assigning the value of the prevIoUs assigned value
If arLonlon(i - 1) = 2^ Then arLonlon(i) = 3^ Else arLonlon(i) = 2^ '270 milliseconds
If arCur(i - 1) = 2@ Then arCur(i) = 3@ Else arCur(i) = 2@          '380 milliseconds
'conclusion: excluding more cpu branching assigning
'a value to a LongLong datatype does seem to be a
'little faster.

Next i
Debug.Print MicroTimer - timer
End Sub

最后的测试表明,存储大量 LongLong 值比 Currency 快一点。

问题 1

我发现的所有代码片段都使用 Currency 或 UDT,没有一个使用 LongLong。但是LongLong要快一些。我假设选择 Currency 数据类型而不是 LongLong,因为 Currency 在 32 位系统上也可用。还有其他原因吗?

问题 2

货币不是 QPC docLargeInteger doc 中提到的数据类型之一。这意味着 VBA 将数据类型转换为货币,当它用作参数/检索值的数据类型时。我可以想象 VBA 只是存储所选数据类型的基数开始的数字(检索值的)(货币的基数是逗号右侧的第 4 个数字)。这是真的?如果是这样,它是否仍然可以命名为“转换”/是否需要更多步骤或时间让 cpu 将值放入货币数据类型?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...