• No results found

Three High-Level Transactional Memory Algorithms

In this section we outline three high-level transactional memory algorithms: an algorithm employ- ing eager conflict detection and eager version management, an eager conflict detection/lazy version management algorithm, and a lazy conflict detection/lazy version management algorithm. These algorithms are not the only possible transactional memory algorithms. However, many of the trans- actional memory systems that we will describe later in this dissertation implement one of these three basic algorithms. Our own proposals will largely seek to implement the eager conflict detec- tion/eager version management algorithm, for reasons that we detail in Section 2.6.

Eager Conflict Detection/Eager Version Management Transactional Memory Algorithm begin

in_transaction = true timestamp = current time read_set = {}

write_set = {} old_values = {}

read(A)

foreach remote transaction T if A in T.write_set resolve_conflict(T) if in_transaction read_set[A] = true return Mem[A] write(A,v)

foreach remote transaction T if (A in T.write_set) or (A in T.read_set) resolve_conflict(T) if in_transaction if A not in write_set old_values[A] = Mem[A] write_set[A] = true Mem[A] = v resolve conflict(T) if (T.timestamp < timestamp) stall until T ends

else

T.abort()

abort

foreach (A,v) in old_values Mem[A] = v

in_transaction = false

commit

in_transaction = false

Figure 2.7: Algorithm for a transactional memory system employing eager conflict detection and eager version management. The algorithm checks for conflicts on each memory access, utilizes age-based conflict resolution, and performs transactional writes in-place.

2.4.1 An Eager Conflict Detection/Eager Version Management Algorithm

Figure 2.7 on page 23 gives the pseudocode for a transactional memory algorithm implementing eager conflict detection and eager version management as well as age-based conflict resolution. Each transaction maintains its read set and write set, and additionally maintains a log of pretrans- actional values of written blocks (old values). At transaction begin the transaction is assigned a timestamp for conflict resolution (if the transaction had previously been aborted, it would retain its previously-assigned timestamp). The read and write sets as well as the log of old values are set to be empty.

On transactional reads and writes, the algorithm checks the read and/or write sets of all other concurrently-executing transactions for conflicts. Assuming that no conflict is detected, the relevant

checks whether this is the first transactional write to the given location; if so, the pretransactional value of the location is added to the log of pretransactional values. The algorithm thus maintains the invariant that any address in the write set also has an entry inold values.

If the algorithm instead detects a conflict, it initiates conflict resolution. Depending on the relative ages of the transactions involved in the conflict, the conflict will be resolved either by stalling the requester until the requestee releases isolation or by aborting the requestee.

To abort, a transaction restores the pretransactional value of each transactionally-written block. To commit, the transaction simply releases isolation by clearing its read and write sets.

2.4.2 An Eager Conflict Detection/Lazy Version Management Algorithm

Figure 2.8 on page 25 gives the pseudocode for an eager conflict detection/lazy version manage- ment transactional memory algorithm that employs age-based conflict resolution. This algorithm is similar to the eager conflict detection/eager version management algorithm described above. The difference is that instead of maintaining pretransactional values in a private buffer, this algorithm maintainscurrentvalues in a private buffer (curr values).

The change from eager version management to lazy version management affects several parts of the algorithm. First, a transactional write performs its write into the private buffer rather than into memory. As a consequence of this fact, transactional reads must check the buffer in order to obtain the correct value for locations that have been previously written by the transaction. Finally, the actions that the transaction takes on commit and abort are the inverse of the above algorithm. To commit, the transaction performs its writes from its private buffer into memory (stalling any other conflicting transactions during this process to maintain isolation). No special action has to be taken to restore pretransactional state on abort, as transactions do not modify memory until they commit.

2.4.3 A Lazy Conflict Detection/Lazy Version Management Algorithm

Figure 2.8 on page 25 gives the pseudocode for a lazy conflict detection/lazy version management transactional memory algorithm. The algorithm employs a commit token for conflict resolution as described in Section 2.3. This algorithm uses the buffer of current values (curr values) in the same way as the above-described eager conflict detection/lazy version management algorithm.

Eager Conflict Detection/Lazy Version Management Transactional Memory Algorithm begin

in_transaction = true committing = false

timestamp = current time read_set = {}

write_set = {} curr_values = {}

read(A)

foreach remote transaction T if A in T.write_set resolve_conflict(T) if in_transaction read_set[A] = true if A in curr_values return curr_values[A] return Mem[A] write(A,v)

foreach remote transaction T if (A in T.write_set) or (A in T.read_set) resolve_conflict(T) if in_transaction write_set[A] = true curr_values[A] = v else Mem[A] = v resolve conflict(T) if (T.timestamp < timestamp) or (T.committing)

stall until T ends else T.abort abort in_transaction = false commit committing = true

foreach (A,v) in curr_values Mem[A] = v

in_transaction = false

Figure 2.8: Algorithm for a transactional memory system employing eager conflict detection and lazy version management.The algorithm checks for conflicts on each memory access, utilizes age-based conflict resolution, and performs transactional writes into a private buffer that is copied to memory at commit.

However, the choice of lazy rather than eager conflict detection and the utilization of the commit token result in significant differences.

Rather than detecting conflicts at each memory access, this algorithm performs conflict detec- tion at commit. Note that in the pseudocode for reads and writes there is no longer any conflict detection. At commit, the transaction first arbitrates to receive acommit token, of which there is only one in the system2. Once a transaction has obtained the commit token, it performs its updates

2

Prior work has proposed optimized implementations of the commit token, e.g., implementations in which it is distributed [18, 20].

Lazy Conflict Detection/Lazy Version Management Transactional Memory Algorithm begin in_transaction = false read_set = {} write_set = {} curr_values = {} read(A) if in_transaction read_set[A] = true if A in curr_values return curr_values[A] return Mem[A] write(A,v) if in_transaction write_set[A] = true curr_values[A] = v else Mem[A] = v abort in_transaction = false commit

obtain commit token

foreach address A in write_set Mem[A] = curr_values[A] foreach remote transaction T

if (A in T.read_set) T.abort()

release commit token in_transaction = false

Figure 2.9: Algorithm for a transactional memory system employing lazy conflict detection and lazy version management. The algorithm performs transactional writes into a private buffer that is copied to memory at commit, at which time it checks for conflicts. It uses a commit token for conflict resolution.

into memory. During this process, it also checks for conflicts with all other concurrently-executing transactions, aborting any conflicting transactions that it finds.

2.4.4 Implementing These Algorithms

Implementing the above-described algorithms with high performance is challenging. In the case of eager conflict detection, the primary performance challenge is that conflict detection must be low- overhead since it is performed on every transactional memory access. In the case of lazy conflict detection, the primary performance challenge is engineering the system so that commit does not become a bottleneck.

One active body of research is devising software transactional memory (STM) implementations –i.e., implementations of transactional memory that run on stock hardware (e.g., [42, 43, 46, 68, 94, 97]). The predominant challenge faced by these implementations is that performing conflict detection in software can have high overheads [17].

The original transactional memory proposal observed that it is possible to support transactional memory in hardware with minor extensions to existing multiprocessors [47]. This design is highly concurrent and has low overheads, but bounds the size and duration of transactions. We present an overview of bounded hardware transactional memory in Section 2.6 after reviewing current multi- processor memory systems in the next section. Extending this design to support transactions that

areunboundedin size and duration is one of the major goals of this dissertation.

Related documents