Tuesday, December 6, 2011

Retrieving GetLastError() in Windbg

Let's say that you are debugging some code with windbg and some error happened, but the code doesn't call GetLastError() and store it in a local variable. Don't worry, you can still find out what the error was. It is stored in the TEB (thread environment block) and there is a debugger extension for the TEB.

0:002> !teb
TEB at 7f38d000
    ExceptionList:        018bfad0
    StackBase:            018c0000
    StackLimit:           018bc000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7f38d000
    EnvironmentPointer:   00000000
    ClientId:             0000076c . 00000518
    RpcHandle:            00000000
    Tls Storage:          0115a170
    PEB Address:          7f384000
    LastErrorValue:       1168
    LastStatusValue:      c000000d
    Count Owned Locks:    0
    HardErrorMode:        0
0:002> !error c000000d
Error code: (NTSTATUS) 0xc000000d (3221225485) - An invalid parameter was passed to a service or function.
0:002> !error 0n1168
Error code: (Win32) 0x490 (1168) - Element not found.

Note LastErrorValue is in decimal and not hex so be sure to add the 0n when using !error.  There you go, there is the last error.

source

Friday, December 2, 2011

new nothrow

I don't use STL, and I don't C++ exceptions.  I avoid them for a few reasons: under debugger, they make it a pain to find and walk the faulting call stack after they are thrown, and mostly I lean towards a more C style of programming style personally.  Still, you need to use the new operator to create new C++ objects, and new can throw and exception in low resource conditions.  There are a few ways to change this default behavior so that it just returns NULL instead of throwing.

One way is to add this into your sources file:

TARGETLIBS=\    
    $(SDK_LIB_PATH)\nothrownew.obj       \

Another way is to add a no throw each time you use the new operator:

    ClassX *pObj = new (std::nothrow) ClassX();

    if (!pObj)
        return E_OUTOFMEMORY;

Tuesday, November 15, 2011

Synchronization Primitives Available in Win32

I ran into this table in a concurrency training class.  It gives you the quick and dirty on synchronization primitives available in Win32.

Characteristic
CriticalSection
SRWLocks
Mutex
Semaphores
Events
Kernel call even if free and upon creation
N
N
Y
Non-FIFO (no convoys)
Y
Y
N
Spin before wait option
Y
Y
N
Try to acquire option
Y
N/Y on Win7
N
Cross-process
N
N
Y
Recursive acquires
Y
N
Mutex only
Use in WaitForMultiple..
N
N
Y


  • CriticalSections are the lightest weight and normally the best to use.
    • you can use them recursively on the same thread
  • SRWLocks are best if you need to differentiate reading and writing access.  For example you can take a shared lock for read only access to a shared resource and exclusive lock for writing.
    • It is generally better than just using a critical section if the ratio is 2 reads : 1 write
    • Cannot be used recursively
  • Mutex/Semaphores/Events are kernel objects
    • Can be used across process.
    • Obviously available in krenel mode.
    • In user mode, the will be less performant than critical sections and SRWlocks and will cause more context switching.
    • Are processed in convoys so they can avoid starvation
Instrumentation is the best way to know what kind of synchronization is best for your code.  Look at my previous post on how to instrument with ETW and XPerf for industrial grade perf testing.  Try different synchronization mechanisms and measure performance.

Thursday, August 4, 2011

How to Add Instrumentation to Your Manifest

To enable ETW performance tracing for your binary, the first thing you need to do is add an instrumentation section. Here is the MSDN documentation on how to do this if you want to read about this in detail:

http://msdn.microsoft.com/en-us/library/aa382776(v=VS.85).aspx

Also in the introduction for ETW (http://msdn.microsoft.com/en-us/magazine/cc163437.aspx), they make a tool recommendation for generating a manifest for ETW (ecmangen.exe). It is available in the Windows SDK. You can try it out; it may meet your needs just fine. As a person who still favors writing code in Vi, I opted to roll my own. Tools are great when they work for you. Using a tool; however, doesn’t make up for actually knowing how things work. It is good to understand how things work when things don’t come together. Read on if you would rather roll your own.

So below is the events section instrumentation manifest that has one start and stop even. You will need a start and stop for everything you want to time.

<events>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5501)"

opcode="win:Start"

symbol="CREATE_QUERY_START"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5500"

/>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5502)"

opcode="win:Stop"

symbol="CREATE_QUERY_STOP"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5501"

/>

events>

With some highlighting, I will show you where all the bits line up inside the full manifest.

<events>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5501)"

opcode="win:Start"

symbol="CREATE_QUERY_START"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5500"

/>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5502)"

opcode="win:Stop"

symbol="CREATE_QUERY_STOP"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5501"

/>

events>

Here is the full manifest:

xml version='1.0' encoding='utf-8' standalone='yes'?>

<assembly

xmlns="urn:schemas-microsoft-com:asm.v3"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

manifestVersion="1.0"

>

<assemblyIdentity

buildType="$(build.buildType)"

language="neutral"

name="Microsoft-Windows-Component"

processorArchitecture="$(build.arch)"

publicKeyToken="$(Build.WindowsPublicKeyToken)"

version="$(build.version)"

versionScope="nonSxS"

/>

<instrumentation xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events">

<events xmlns="http://schemas.microsoft.com/win/2004/08/events">

<provider

guid="{56c71c31-cfbd-4cdd-8559-505e042bbbe1}"

message="$(string.EventProviderName)"

messageFileName="%SystemRoot%\system32\component.dll"

name="Microsoft-Windows-ComponentProvider"

resourceFileName="%SystemRoot%\system32\component.dll"

symbol="component"

>

<channels>

<channel

chid="50"

name="Microsoft-Windows-ComponentProvider/Performance"

symbol="MS_COMPONENT_PERFORMANCE"

type="Analytic"

/>

channels>

<keywords>

<keyword

mask="0x1"

name="PerfTrackContext"

/>

<keyword

mask="0x2"

name="Component"

/>

<keyword

mask="0x4"

name="query"

/>

keywords>

<tasks>

<task

name="component_CreateQuery"

value="5000"

/>

tasks>

<templates>

<template tid="INFO_CONTEXT_INFO">

<data

inType="win:Pointer"

name="Context"

/>

template>

templates>

<events>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5501)"

opcode="win:Start"

symbol="CREATE_QUERY_START"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5500"

/>

<event

channel="50"

keywords="Component query"

level="win:Informational"

message="$(string.event_5502)"

opcode="win:Stop"

symbol="CREATE_QUERY_STOP"

task="component_CreateQuery"

template="INFO_CONTEXT_INFO"

value="5501"

/>

events>

provider>

events>

instrumentation>

<localization>

<resources culture="en-US">

<stringTable>

<string

id="EventProviderName"

value="Microsoft-Windows-Component"

/>

<string

id="event_5501"

value="create query has started."

/>

<string

id="event_5502"

value="create query has exited."

/>

stringTable>

resources>

localization>

<dependency

discoverable="false"

optional="false"

resourceType="Resources"

>

<dependentAssembly dependencyType="prerequisite">

<assemblyIdentity

buildType="$(build.buildType)"

language="*"

name="Microsoft-Windows-Component.Resources"

processorArchitecture="$(build.processorArchitecture)"

publicKeyToken="$(Build.WindowsPublicKeyToken)"

version="$(build.version)"

versionScope="nonSxS"

/>

dependentAssembly>

dependency>

assembly>