User Guide

Contents

Lock Annotations

Lock annotations mark where you expect you will be adding explicit synchronization.

Syntax

C/C++:
ANNOTATE_LOCK_ACQUIRE(pointer-expression);
and
ANNOTATE_LOCK_RELEASE(pointer-expression);
Fortran:
call annotate_lock_acquire(address)
and
call annotate_lock_release(address)
C#:
Annotate.LockAcquire([int expr]);
and
Annotate.LockRelease([int expr]);
(for each annotation, its argument is optional)
With C/C++
and Fortran
programs, all of the lock annotations use an address value to represent distinct locks in your final program. You can use the address value 0 to represent a global
lock
that is the same across the entire program.
With C# programs, the argument is an
int
with a default value of 0 (zero).
Intel recommends that you start by using a default lock, unless you need additional locks for performance scaling.
The modeling step is aware of the standard locking routines in the Windows* OS API, as well as
Intel® Threading Building Blocks (Intel® TBB)
and OpenMP*, so there is no need to annotate existing locking. Lock annotations are only required for cases where you are not already using synchronization.
The lock-acquire and lock-release annotations denote points in your program where you intend to acquire and release locks. These annotations take a single parameter, which is an address that you choose.
For example, if you decided you would have a lock used only for
glob_variable
, you specify the same memory address for all cases where you are protecting access to
glob_variable
, to represent that specific lock. The sample below uses the variable's address to represent the lock that will be associated with
glob_variable
.
You typically can use one of the following four values, using a finer granularity of synchronization when necessary:
  • The value of 0 (zero) to represent a single unspecified lock that is the same across the entire program.
  • The address of a data structure or other aggregation of data. This represents using a single lock for the collection of data.
  • The address of a member of the data collection. This represents finer-grained locking than the previous value and provides better performance.
  • A variable representing a lock as you move toward final parallel code.
This C/C++ example shows the intent for the parallel program to acquire and release a lock around the access to the global variable
glob_variable
in each task:
    ...     extern int glob_variable = 0;     ...     ANNOTATE_SITE_BEGIN(sitename);     for (I=0; i<N; I++) {         ANNOTATE_TASK_BEGIN(taskfunc1);         func1(I);         ANNOTATE_LOCK_ACQUIRE(&glob_variable);         glob_variable++;         ANNOTATE_LOCK_RELEASE(&glob_variable);         func2(I);         ANNOTATE_TASK_END();     }     ANNOTATE_SITE_END();     ...
This Fortran example also shows the intent to acquire and release a lock around the access to the global variable
glob_variable
in each task:
 ... integer :: glob_variable = 0 call annotate_site_begin("sitename") do i=1,size call annotate_task_begin("taskfunc1") call func1(i) call annotate_lock_acquire(0) glob_variable = glob_variable + 1 call annotate_lock_release(0) call func2(i) call annotate_task_end end do call annotate_site_end  ...
This C# example also shows the intent to acquire and release a lock around the access to the global variable
glob_variable
in each task:
 ... public int glob_variable { get{return nrOfSolutions;} set{nrOfSolutions = value;} } Annotate.SiteBegin("sitename"); for (int i = 0; i < N; i++) { Annotate.TaskBegin("taskfunc1"); func1(i); Annotate.LockAcquire(); glob_variable++; Annotate.LockRelease(); func2(i); Annotate.TaskEnd(); } Annotate.SiteEnd();   ...
The following C/C++ example is a typical use of a data item's address. It shows the use of an
Entity
address, where there is a vector of integers that are each going to have an associated lock, because the program is counting random elements of the array that will be accessed by different tasks, some of which may occasionally have the same random value. The text from adding annotations appears in
bold
below.
   struct Entity {        int val;    };    ...    std::vector<Entity> v;    ...    for (int I=0; i<v.size()*10000; I++) {        int random_int = random_n();        ANNOTATE_LOCK_ACQUIRE(&v[random_int]);         v[random_int].val++;      ANNOTATE_LOCK_RELEASE(&v[random_int]);    }    ...

Using Lock Annotations

Lock addresses are the basis of lock annotations, and each lock address corresponds to the intent to create a unique lock, or other synchronization mechanism, in the final program. Tasks sharing a parallel site are modeled as executing in parallel unless you describe synchronization using lock addresses, or known locking mechanisms.

Product and Performance Information

1

Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.

Notice revision #20110804