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>