__llwpcb

[Note: This document describes a pre-release version of Visual Studio 2010 SP1 and may be revised in any later version.]

Visual Studio 2010 SP1 is required.

Microsoft Specific

Generates the lightweight profiling (LWP) instruction llwpcb to pass the address of a lightweight profiling control block (LWPCB) to the LWP hardware and enable or disable lightweight profiling.

void __llwpcb(
   void *pcbaddress
);

Parameters

  • [in] pcbaddress
    Zero or a pointer to an LWP control block.

Return value

None.

Requirements

Intrinsic

Architecture

__llwpcb

LWP

Header file <intrin.h>

Remarks

This intrinsic generates code that enables or disables lightweight profiling. Lightweight profiling writes records for certain user-selected hardware or software events into a ring buffer in user space. The LWP control block selects the events to be recorded and describes the ring buffer. Sampling and writing event records happens very quickly, with minimal disruption to user code. When the ring buffer becomes nearly full, the hardware can generate an interrupt to activate code that processes the entries in the ring buffer. See AMD's "Lightweight Profiling Specification" (Publication Number 43724) for detailed information on lightweight profiling.

When the parameter pcbaddress points to a valid LWP control block, lightweight profiling is enabled as described by the control block. When pcbaddress is 0, the LWP internal buffers are flushed to the LWP ring buffer and LWP is disabled.

The llwpcb instruction is part of the LWP family of instructions. The LWP instructions require both hardware and operating system support. To determine hardware support for LWP, call the __cpuid intrinsic with InfoType = 0x80000001 and check bit 15 of CPUInfo[2] (ECX). This bit is 1 when LWP is supported by the hardware, and 0 otherwise. Once you know that LWP is supported by the hardware, call the __cpuid intrinsic with InfoType = 0x8000001C and check bit 0 of CPUInfo[0] (EAX). This bit is 1 if the operating system has made LWP available, 0 otherwise. If the bit is 1, there will be other important information available in CPUInfo[], as described below. Note that the values in CPUInfo[3] (EDX) represent the same LWP features as those in CPUInfo[0] (EAX), but the values in EDX represent the LWP capabilities of the hardware, while the values in EAX represent the LWP features currently enabled by the operating system.

CpuInfo[]

Bits

Field Name

Description

0 (EAX)

0

LwpAvail

LWP is supported by HW and OS

1

LwpVAL

LWPVAL instruction available

2

LwpIRE

Instructions retired event available

3

LwpBRE

Branch retired event available

4

LwpDME

DCache miss event available

5

LwpCNH

CPU clocks not halted event available

6

LwpRNH

CPU reference clocks not halted event available

30-7

Reserved

31

LwpInt

Threshold overflow interrupt available

1 (EBX)

7-0

LwpCbSize

Size of LWPCB in quadwords

15-8

LwpEventSize

Size of a ring buffer event record in bytes

23-16

LwpMaxEvents

Maximum Eventid value supported (not including 255)

31-24

LwpEventOffset

Offset in bytes of EventInterval1 field from start of LWPCB. Always a multiple of 8.

2 (ECX)

4-0

LwpLatencyMax

Number of bits in cache latency counters

5

LwpDataAddress

1 if cache miss event records report data address of missing reference

8-6

LwpLatencyRnd

Bits by which cache latency is rounded (0 to 4)

15-9

LwpVersion

Version of LWP implementation

23-16

LwpMinBufferSize

Minimum size of the LWP ring buffer, in units of 32*EventSize

Example

#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);
}
32-bit compiler
9 entries in ring buffer
4 LWPVAL instructions, 5 LWPINS instructions
or
64-bit compiler
17 entries in ring buffer
7 LWPVAL instructions, 10 LWPINS instructions
or
      A message saying that LWPVAL is not available along with the appropriate output from above, but with counts of zero for LWPVAL and with the number of ring buffer entries reduced to match.
or
A message that LWP is not supported or available.

See Also

Reference

__lwpval32, __lwpval64

__lwpins32, __lwpins64

__slwpcb

LWP Intrinsics Added for Visual Studio 2010 SP1

Change History

Date

History

Reason

March 2011

Added this content.

SP1 feature change.