Incidental Sharing

Sharing is incidental when tasks use the same memory location, but do not communicate any information using it.

The Basic Pattern

Suppose that a task always writes to a memory location before reading from it, and that the value that it writes is not read again outside the task. For example:

extern int x;
// ...
ANNOTATE_SITE_BEGIN(site1);
for (i = 0; i != n; ++i) {
    ANNOTATE_ITERATION_TASK(task1);
    x = a[i];
    b[i] = x * b[i];
}
ANNOTATE_SITE_END(site1);

The variable x is both read and written in the task, so there will be a sharing problem when multiple copies of the task execute at the same time. For example:

  1. Task 0 sets x to a[0].

  2. Task 1 sets x to a[1].

  3. Task 0 computes x * b[0].

What is interesting is that the sharing is incidental to the logic of the program. Each iteration of the loop uses x, but its use in each iteration is totally independent. Memory locations used in this way are called privatizable, because giving each task its own private memory location will eliminate the sharing without changing the program behavior.

Memory Allocators

The use of dynamically allocated memory is a special case of incidental sharing. Consider this task:

ANNOTATE_TASK_BEGIN(task2);
Type *ptr = allocate_Type();
// some code that uses the object pointed to by ptr
free_Type(ptr);
ANNOTATE_TASK_END();

If allocate_Type() returns the same address to one task that was used and freed by another task, then those tasks will both access the same memory location, but the sharing is incidental. The memory allocator will never return a pointer to memory that has been allocated and not freed, so the tasks will not use the same dynamically allocated memory location at the same time, and the appearance of sharing is an illusion.

The Dependencies tool understands the standard memory allocators such as C/C++ new/delete and malloc/free, but it does not know about any custom memory allocators that your program might have. If your code has custom memory allocators, you can mark their uses with the special-purpose C/C++ annotations ANNOTATE_RECORD_ALLOCATION and ANNOTATE_RECORD_DEALLOCATION.

For more complete information about compiler optimizations, see our Optimization Notice.