__llwpcb
更新:2011 年 3 月
需要 Visual Studio 2010 SP1。
Microsoft 专用
生成轻量分析 (LWP) 指令 llwpcb 以将轻量分析控制块 (LWPCB) 的地址传递给 LWP 硬件并启用或禁用轻量分析。
void __llwpcb(
void *pcbaddress
);
参数
- [in] pcbaddress
零或指 LWP 控制块的指针。
返回值
无。
要求
内部 |
体系结构 |
---|---|
__llwpcb |
LWP |
头文件 <intrin.h>
备注
此内部函数生成启用或禁用轻量分析的代码。 轻量分析会将某些用户选择的硬件或软件事件的记录写入用户空间中的环形缓冲区。 LWP 控制块选择要记录的事件,并描述该环形缓冲区。 采样和编写事件记录发生速度非常快,与用户代码的中断最少。 当环形缓冲区快要满时,硬件可以生成中断以激活处理环形缓冲区中的条目的代码。 有关轻量分析的详细信息,请参见 AMD 的“Lightweight Profiling Specification”(轻量分析规范,出版物编号 43724)。
当参数 pcbaddress 指向有效的 LWP 控制块时,会按照控制块所述启用轻量分析。 当 pcbaddress 为 0 时,LWP 内部缓冲区会刷新为 LWP 环缓冲区并且 LWP 会被禁用。
llwpcb 指令是 LWP 系列指令的一部分。 LWP 指令需要硬件和操作系统支持。 若要确定 LWP 的硬件支持,调用 InfoType = 0x80000001 的 __cpuid 内部函数并检查 CPUInfo[2] (ECX) 位 15。 当硬件支持 LWP 时,此位为 1,否则为 0。 一旦您了解到硬件支持 LWP,即可调用 InfoType= 0x8000001C 的 __cpuid 内部函数并检查 CPUInfo[0] (EAX) 的位 0。 如果操作系统已可使用 LWP,则此位为 1;否则为 0。 如果该位是 1,则在 CPUInfo [] 中有其他重要信息,如下所述。 请注意,CPUInfo[3] (EDX) 中的值表示与 CPUInfo[0] (EAX) 中相同的 LWP 功能,但 EDX 中的值表示硬件的 LWP 功能,而 EAX 中的值表示当前由操作系统启用的 LWP 功能。
CpuInfo[] |
位 |
字段名 |
说明 |
---|---|---|---|
0 (EAX) |
0 |
LwpAvail |
LWP 受硬件和操作系统支持 |
1 |
LwpVAL |
可用的 LWPVAL 指令 |
|
2 |
LwpIRE |
可用的 Instructions Retired 事件 |
|
3 |
LwpBRE |
可用的 Branch Retired 事件 |
|
4 |
LwpDME |
可用的 DCache 缺失事件 |
|
5 |
LwpCNH |
可用的 CPU 时钟不暂停事件 |
|
6 |
LwpRNH |
可用的 CPU 参考时钟不暂停事件 |
|
30-7 |
保留 |
||
31 |
LwpInt |
可用的阈值溢出中断 |
|
1 (EBX) |
7-0 |
LwpCbSize |
四字中的 LWPCB 大小 |
15-8 |
LwpEventSize |
环形缓冲区事件记录的大小(以字节为单位) |
|
23-16 |
LwpMaxEvents |
支持的最大 Eventid 值(不包括 255) |
|
31-24 |
LwpEventOffset |
EventInterval1 字段从 LWPCB 的开始的偏移(以字节为单位)。 始终为 8 的倍数。 |
|
2 (ECX) |
4-0 |
LwpLatencyMax |
缓存延迟计数器中的位数 |
5 |
LwpDataAddress |
如果缓存缺失事件记录缺失的引用的报告数据地址,则为 1 |
|
8-6 |
LwpLatencyRnd |
缓存延迟舍入的位(0 到 4) |
|
15-9 |
LwpVersion |
LWP 实现版本。 |
|
23-16 |
LwpMinBufferSize |
LWP 环形缓冲区的最小大小,单位为 32*EventSize |
示例
#include <intrin.h>
#include <stdio.h>
#define MAX_EVENTS 6
#define LWPEVENTSIZE 32
#define BUFFERSIZE 4096
struct lwpEventRecord {
unsigned __int64 EventId : 8;
unsigned __int64 CoreId : 8;
unsigned __int64 Flags : 16;
unsigned __int64 Data1 : 32;
unsigned __int64 InstructionAddress;
unsigned __int64 Data2;
unsigned __int64 Reserved;
};
struct lwpEventRecord ringBuffer[BUFFERSIZE];
struct lwpcb0 {
unsigned __int64 Flags : 32;
unsigned __int64 BufferSize : 28;
unsigned __int64 Random : 4;
};
struct lwpcbEvent {
unsigned __int64 EventInterval : 26;
unsigned __int64 EIReserved1 : 6;
unsigned __int64 EventCounter : 26;
unsigned __int64 EIReserved2 : 6;
};
struct lwpcbStruct {
unsigned __int64 Flags : 32;
unsigned __int64 BufferSize : 28;
unsigned __int64 Random : 4;
unsigned __int64 BufferBase;
unsigned __int64 BufferHeadOffset : 32;
unsigned __int64 Reserved1 : 32;
unsigned __int64 MissedEvents;
unsigned __int64 Threshold : 32;
unsigned __int64 Filters : 32;
unsigned __int64 BaseIP;
unsigned __int64 LimitIP;
unsigned __int64 Reserved2;
unsigned __int64 BufferTailOffset : 32;
unsigned __int64 Reserved3 : 32;
unsigned __int64 Reserved4[7];
struct lwpcbEvent Events[MAX_EVENTS]; // event 1 == index 0
} myLWPCBStruct;
__m128d data[100];
extern void __cpuid(int *CPUInfo, int InfoType);
// Return 1 if LWP is supported by the hardware
int LwpSupported()
{
int cpuInfo[4] = {0};
__cpuid(cpuInfo, 0x80000001);
if (cpuInfo[2] & (1 << 15)) return 1;
else return 0;
}
// Return 1 if LWP is enabled by the OS
// Assumes LWP is supported by the hardware
int LwpAvailable()
{
int cpuInfo[4] = {0};
__cpuid(cpuInfo, 0x8000001C);
if (cpuInfo[0] & 1) return 1;
else return 0;
}
// Return 1 if LWPVAL instruction is supported by this hardware
// Assumes LWP is supported by the hardware
int LwpvalSupported()
{
int cpuInfo[4] = {0};
__cpuid(cpuInfo, 0x8000001C);
if (cpuInfo[3] & (1 << 1)) return 1;
else return 0;
}
// Return 1 if LWPVAL instruction is enabled by the OS
// Assumes LWPVAL is supported by the hardware
int LwpvalAvailable()
{
int cpuInfo[4] = {0};
__cpuid(cpuInfo, 0x8000001C);
if (cpuInfo[3] & (1 << 1)) return 1;
else return 0;
}
void
initializeLWPCB(struct lwpcbStruct *p)
{
int i, lwpvalok;
unsigned __int64 *dummy;
p->Flags = 0; // disable HW counters & threshold interrupts
p->BufferSize = sizeof(ringBuffer)/sizeof(struct lwpEventRecord);
p->BufferSize *= sizeof(struct lwpEventRecord);
p->Random = 0; // No randomness in counters
p->BufferBase = (unsigned __int64)&ringBuffer[0];
/// Value of BufferHeadOffset here is arbitrary
p->BufferHeadOffset = p->BufferSize -
3*sizeof(struct lwpEventRecord);
p->MissedEvents = 0;
p->Threshold = 2*p->BufferSize; // don't want threshold interrupts
p->Filters = 0; // shouldn't matter for this test
p->BaseIP = 0; // shouldn't matter for this test
p->LimitIP = 0; // shouldn't matter for this test
p->BufferTailOffset = p->BufferHeadOffset; // ring buffer empty
p->Reserved1 = p->Reserved2 = p->Reserved3 = 0;
for (i = 0; i < 7; i++) p->Reserved4[i] = 0;
for (i = 0; i < MAX_EVENTS; i++) {
p->Events[i-1].EventInterval = 0;
p->Events[i-1].EIReserved1 = 0;
p->Events[i-1].EventCounter = 0;
p->Events[i-1].EIReserved2 = 0;
}
if (LwpvalSupported() && LwpvalAvailable()) {
p->Flags |= 2; // Count LWPVAL events
p->Events[0].EventInterval = 9; // count every 10th LWPVAL
}
}
#define LOOPSIZE 31
main()
{
int i;
__m128d temp;
double sum = 0;
struct lwpcbstruct *plwpcb;
unsigned int tailOffset, headOffset, bufferSize, bufferCapacity;
unsigned int headRecord, tailRecord;
int headMinusTail;
unsigned int recordSize = sizeof(struct lwpEventRecord);
unsigned int numEntries;
unsigned int lwpvalCount, lwpinsCount;
if (!LwpSupported()) {
printf("LWP is not supported by this hardware\n");
exit(1);
}
if (!LwpAvailable()) {
printf("OS has not made LWP available\n");
exit(1);
}
#if defined(_M_X64)
printf("64-bit compiler\n");
#else
printf("32-bit compiler\n");
#endif
initializeLWPCB(&myLWPCBStruct);
__llwpcb(&myLWPCBStruct);
plwpcb = __slwpcb();
if ((unsigned __int64)plwpcb != (unsigned __int64)&myLWPCBStruct) {
printf("Test failed: bad return from __slwpcb()\n");
exit(1);
}
if (LwpvalSupported() && LwpvalAvailable()) {
for (i = 0; i < LOOPSIZE; i ++) {
if (i % 7 == 0) __lwpins32(0xdeadbeef, i, 0x01234567);
__lwpval32(0x0badf00d, i, 0xcad00cad);
}
#if defined(_M_X64)
for (i = 0; i < LOOPSIZE; i ++) {
if (i % 7 == 0) __lwpins64(0xdeadbeefdeadbeefll, i, 0x01234567);
__lwpval64(0x0badf00d0badf00dll, i, 0xcad00cad);
}
#endif
} else {
if (!LwpvalSupported()) {
printf("LWPVAL instruction not supported by the hardware\n");
} else if (!LwpvalAvailable()) {
printf("LWPVAL instruction not enabled\n");
}
for (i = 0; i < LOOPSIZE; i ++) {
if (i % 7 == 0) __lwpins32(0xdeadbeef, i, 0x01234567);
}
#if defined(_M_X64)
for (i = 0; i < LOOPSIZE; i ++) {
if (i % 7 == 0) __lwpins64(0xdeadbeefdeadbeefll, i, 0x01234567);
}
#endif
}
plwpcb = __slwpcb();
tailOffset = myLWPCBStruct.BufferTailOffset;
headOffset = myLWPCBStruct.BufferHeadOffset;
bufferSize = myLWPCBStruct.BufferSize;
bufferCapacity = bufferSize / recordSize;
headMinusTail = headOffset;
headMinusTail -= tailOffset;
if (tailOffset <= headOffset) numEntries = headMinusTail;
else numEntries = headMinusTail + bufferSize;
numEntries /= recordSize;
tailRecord = tailOffset / recordSize;
headRecord = headOffset / recordSize;
printf("%d entries in ring buffer\n", numEntries);
lwpvalCount = lwpinsCount = 0;
for (i = tailRecord; i != headRecord; i = (i + 1)%bufferCapacity) {
switch(ringBuffer[i].EventId) {
case 1:
lwpvalCount += 1;
break;
case 255:
lwpinsCount += 1;
break;
default:
printf("WARNING: bad EventId %d in ring buffer\n",
ringBuffer[i].EventId);
break;
}
}
printf("%d LWPVAL instructions, %d LWPINS instructions\n",
lwpvalCount, lwpinsCount);
}
请参见
其他资源
针对 Visual Studio 2010 SP1 添加的 LWP 内部函数
修订记录
Date |
修订记录 |
原因 |
---|---|---|
2011 年 3 月 |
添加了本内容。 |
SP1 功能更改。 |