{'fraction_non_alphanumeric': 0.031019529175762582, 'fraction_numerical': 0.0098530886777981, 'mean_word_length': 4.935650499036946, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Improving the Performance and Endurance of Persistent Memory with Loose-Ordering Consistency

Persistent memory provides high-performance data persistence at main memory. Memory writes need to be performed in strict order to satisfy storage consistency requirements and enable correct recovery from system crashes. Unfortunately, adhering to such a strict order significantly degrades system performance and persistent memory endurance. This paper introduces a new mechanism, Loose-Ordering Consistency (LOC), that satisfies the ordering requirements at significantly lower performance and endurance loss. LOC consists of two key techniques. First, Eager Commit eliminates the need to perform a persistent commit record write within a transaction. We do so by ensuring that we can determine the status of all committed transactions during recovery by storing necessary metadata information statically with blocks of data written to memory. Second, Speculative Persistence relaxes the write ordering between transactions by allowing writes to be speculatively written to persistent memory. A speculative write is made visible to software only after its associated transaction commits. To enable this, our mechanism supports the tracking of committed transaction ID and multi-versioning in the CPU cache. Our evaluations show that LOC reduces the average performance overhead of memory persistence from 66.9% to 34.9% and the memory write traffic overhead from 17.1% to 3.4% on a variety of workloads.

Since memory writes in persistent memory are persistent, they need to be performed atomically and in correct order to ensure storage consistency. Storage consistency ensures atomicity and durability of storage systems, so that the system is able to correctly recover from unexpected system crashes [18], [30], [70], [71], [76], [77], [82], [100], [118], where volatile data gets lost (See Section 2.2 for details). In this work, we borrow the transaction concept, which is commonly used to provide storage consistency in traditional storage systems [18], [82], [100], to manage persistent memory. A transaction is atomic: either all of its writes complete • Youyou Lu, Jiwu Shu and Long Sun  and update persistent memory or none. To accomplish this, both the old and new versions of the data associated with the location of a write are kept track of within the transaction. The writes within and across transactions are persisted (i.e., written to persistent memory) in strict program order, to ensure that correct recovery is possible in the presence of incomplete transactions. As such, any persistent memory protocol needs to support both transaction atomicity and strict write ordering to persistent memory (i.e., persistence ordering) in order to satisfy crash consistency requirements. Traditionally, disk-based storage systems have employed transaction-based recovery protocols, such as write-ahead logging [82] or shadow paging [30], to provide both transaction atomicity and persistence ordering. These protocols maintain 1) two copies/versions of each data written within a transaction, and 2) a strict write order to the storage device, which enables the atomic switch from the old version of data to the new version upon transaction commit. Persistent memory is much faster than disk-based storage and has endurance limitations, i.e., a memory cell wears out after a limited number of writes [58], [101]. Traditional transaction-based recovery protocols, designed with highlatency disk-based storage systems in mind, are not suitable for persistent memory due to their large performance and endurance overhead [20], [83], [93], [99], [120], [125].
Transaction support in persistent memory has two major challenges. First, the boundary of volatility and persistence in persistent memory lies between the hardwarecontrolled CPU cache and the persistent memory. In contrast, in traditional disk-based storage systems, the boundary between volatility and persistence lies between the software-controlled main memory and disk storage. While data writeback from main memory is managed by the operating system software in traditional systems, enabling arXiv:1705.03623v1 [cs.AR] 10 May 2017 transactional protocols to effectively control the order of writes to persistent storage, data writeback from the CPU cache is managed by hardware in persistent memory systems, making it harder to control the order of writes to persistent memory at low performance overhead. This is because the CPU cache behavior is opaque to the system and application software. Therefore, in order to preserve persistence ordering from the CPU cache to persistent memory, software needs to explicitly include the relatively costly cache flush (e.g., clflush) and memory fence (e.g., mfence) instructions (at the end of each transaction) to force the ordering of cache writebacks [19], [120], [121], [122]. The average overhead of a clflush and mfence combined together is reported to be 250ns [121], which makes this approach costly, given that persistent memory access times are expected to be on the order of tens to hundreds of nanoseconds [57], [58], [103]. Recently, Intel has introduced two new instructions to reduce flush overheads: 1) clflushopt, which provides unordered flush, and 2) clwb, which enforces data persistence without invalidating cache lines. However, recent research shows that these instructions still incur high performance overhead, e.g., an average slowdown of 7x for write-intensive persistent memory applications [56]. In addition, frequent flush operations lead to high memory write traffic, which accelerates the wear-out process of persistent memory, thereby hurting its endurance.
Second, existing systems reorder operations, including writes, at multiple levels, especially in the CPU and the cache hierarchy in order to maximize system performance. For example, writebacks from the cache are performed in an order that is usually completely different from the programspecified order of writes. Similarly, the memory controller can reorder writes to memory to optimize performance (e.g., by optimizing row buffer locality [7], [88], bank-level parallelism [63], [89] and write-to-read turnaround delays [62], [107], [126]). Enforcing a strict order of writes to persistent memory to preserve storage consistency eliminates the reordering across not only writes/writebacks but also limits reordering possibilities across other operations, thereby significantly degrading the performance. This is because ensuring a strict order of writes requires 1) flushing dirty data blocks from each cache level to memory, 2) writing them back to main memory in the order specified by the transaction at transaction commit time, and 3) waiting for the completion of all memory writes within the transaction before a single write for the next transaction can be performed. Doing so can greatly degrade system performance, by as high as a factor of 10 for some memory-intensive workloads we evaluate, as we demonstrate in Section 5.2).
Our goal in this paper is to design new mechanisms that reduce the performance and endurance overhead caused by strict ordering of writes in persistent memory. To achieve this, we identify different types of persistence ordering that degrade performance: intra-transaction ordering (i.e., strict ordering of writes inside a transaction) and intertransaction ordering (i.e., strict ordering of writes between transactions). We observe that relaxing either of these types of ordering can be achieved without compromising storage consistency requirements by changing the persistent memory log organization and providing hardware support in the CPU cache. Based on this observation, we develop two complementary techniques that respectively reduce the performance overhead due to intra-and inter-transaction (tx) ordering requirements. We call the resulting mechanism Loose-Ordering Consistency (LOC) for persistent memory.
LOC consists of two new techniques. First, a new transaction commit protocol, Eager Commit, enables the commit of a transaction without the use of commit records, which traditionally are employed to record the status of each transaction [16], [70], [71], [82], [100]. Doing so removes the need to perform a persistent commit record write at the end of a transaction and eliminates the intra-transaction ordering requirement, thereby improving performance. To achieve this, Eager Commit organizes the memory log in a static manner and divides it into groups of blocks (i.e., block groups). In each group, one metadata block is allocated to keep the transaction metadata of the other (e.g., seven) data blocks in the block group. The metadata block is stored along with the data blocks in each block group. This static log organization enables the system to determine the status of each transaction by inspecting the metadata information during recovery, without requiring the use/query of a commit record. Hence, Eager Commit eliminates the use of commit records and removes their associated ordering overhead from the critical path of transaction commit.
Second, Speculative Persistence relaxes the ordering of writes between transactions by allowing writes to be speculatively written to persistent memory. This allows data blocks from multiple transactions to be written to persistent memory, potentially out of the specified program order. A speculative write is made visible to software only after its associated transaction commits, and transactions commit in program order. To enable this, our mechanism requires the tracking of committed transaction ID and support for multiversioning in the CPU cache. Hence, Speculative Persistence ensures that storage consistency requirements are met while ordering of persistent memory writes is relaxed, improving performance and endurance.
The major contributions of this paper are as follows: • We identify two types of persistence ordering that lead to performance degradation in persistent memory: intra-transaction ordering and inter-transaction ordering. • We introduce a new transaction commit protocol, Eager Commit, that eliminates the use of commit records (traditionally needed for correct recovery from system crash) and thereby reduces the overhead due to intratransaction persistence ordering. •

Storage Consistency
Storage Transactions. In database management systems, transaction management provides four properties: atomicity (A), consistency (C), isolation (I), and durability (D). To achieve the ACID properties, transaction management has to provide 1) concurrency control for the execution of multiple transactions, 2) transaction recovery in case of failure. Isolation of concurrent execution of multiple transactions is the subject of concurrency control, and the atomic and durable update of state by each transaction is the subject of transaction recovery [104]. The two concepts are respectively borrowed by transactional memory [31], [37] and storage transactions [18], [70], [71], [72], [77], [78], [100], [118]. Figure 1 illustrates the differences of transaction modules between disk-based storage systems and persistent memory. While transaction recovery works at the boundary between the DRAM and disks in disk-based storage systems, it now moves to the boundary between the CPU cache and the persistent memory in persistent memory systems. In this paper, we focus on storage transactions (to provide atomicity and durability guarantees in the presence of system failures) in persistent memory using the transaction recovery mechanism.
Transaction Recovery. Transaction recovery requires data blocks modified by one transaction to be atomically persisted to storage devices, such that the persistent data blocks can be used to recover the system to a consistent state after an unexpected system crash/failure. To enable this, existing transaction recovery protocols maintain 1) two copies/versions of each written data within a transaction, and 2) a strict write order to the storage device, which  enables the atomic switch from the old version of data to the new version upon transaction commit. We briefly describe Write-Ahead Logging (WAL) [82], the commonlyused protocol which we use as our baseline.
Write-Ahead Logging (WAL) [82] is a commonly used protocol for transaction recovery. A transaction commit occurs in four phases to ensure correct recoverability of data, as illustrated in the left half of Figure 2. In Phase 1 (during transaction execution), WAL writes the new version of each updated data block to a log area in persistent memory, while the old version is kept safe in its home/original location. In Phase 2 (which starts right after the program issues a transaction commit request), WAL first waits until all the data blocks the transaction has updated are written into the log. After this, WAL writes a commit record to the log to keep the transaction status. At the end of Phase II, the new-version data and the commit record are persisted completely and WAL sends an acknowledgment to the program indicating that the transaction commit is done. In Phase 3, WAL copies the new version of each updated data block from the log to its home location to make it visible to accesses from the software (this is called in-place update of data). Finally, after in-place update completes, in Phase 4, WAL truncates the log such that the committed transaction is removed from the log. We call each of these phases an I/O phase.
Shadow paging also consists of I/O phases, but it is based on out-of-place updates. In phase one, the new-version data are updated in newly allocated space. The root node is written only after the updates of its descendants complete, as shown in phase two. Like the commit record, the root node serves as the consensus between normal execution and recovery process. Once the system crashes, the new-version data are accessible only if the root has been updated. In phase three, the old-version data can be garbage collected only after the update of the root. The right half of Figure 2 shows a variant of shadow paging, Short-Circuit Shadow Paging [20], which is used in persistent memory that is byte addressable and that supports 64-bit atomic writes.
In addition to transaction-based recovery, which we adopt in this paper, Soft Updates is a technique to provide consistency by writing data blocks that have dependencies in an ordered way [28], [106]. Soft Updates is different from transactions in that it does not keep both the old and new data versions and cannot be recovered to the old version after system crashes. However, it still has to keep the ordering of writes and has the ordering overhead as in transaction-based recovery. More recently, the ThyNVM [105] consistency model has been proposed to provide crash consistency to unmodified programs, but it requires a significant departure from the storage interface to load/store interface to persistent memory.   Ordering. To achieve atomicity and durability, I/O phases are performed one by one, in strict order. This is done to ensure correct recovery in case the system fails/crashes during transaction commit. Updates to persistent memory across the I/O phases are performed in a strict order such that one phase cannot be started before the previous phase is complete. This is called persistence ordering. Note that this is different from the ordering of program instructions (loads and stores), which is enforced by the CPU. Persistence ordering is the ordering of cache writebacks to persistent memory such that the correct ordering of storage transactions is maintained. As shown in Figure 2, there are two kinds of persistence ordering in transaction recovery.
Intra-transaction (Intra-tx) Ordering refers to the ordering required within a transaction. Before a transaction commits, WAL needs to ensure that the new version of each updated data block of the transaction is completely persisted. Only after that, WAL updates the commit record. Otherwise, if the commit record is updated before all data blocks updated by the transaction are persisted, the transaction recovery process, after a system crash, may incorrectly conclude that the transaction is committed, violating atomicity and consistency guarantees. Intra-tx ordering ensures that the new versions of data are completely and safely written to persistent memory when the commit record is found during the transaction recovery process.
Inter-transaction (Inter-tx) Ordering refers to the ordering required across transactions. The program needs to wait for the commit acknowledgment (shown as "Software Acknowledgment" in Figure 2) of a transaction in order to start the next transaction. Inter-tx ordering ensures that the transaction commit order is the same as the order specified by the program.

LOOSE-ORDERING CONSISTENCY
Loose-Ordering Consistency (LOC) is designed to mitigate the performance and endurance degradation caused by strict ordering of writes by loosening the ordering without compromising consistency in persistent memory. It aims to reduce both intra-tx and inter-tx ordering overheads. LOC consists of two techniques: 1) Eager Commit, a commit protocol that eliminates the use of commit records, thereby removing intra-tx ordering. 2) Speculative Persistence that allows writes from different transactions to speculatively update persistent memory in any order while making them visible to software only in program order, thereby relaxing inter-tx ordering. This section describes both techniques in detail after giving an overview of the LOC mechanism. Figure 3 shows an overview of the LOC design. CPU issues load and store instructions to perform memory I/O operations. From the program's point of view, the volatile CPU cache and the persistent main memory are not differentiated; all stores to memory within a storage transaction are deemed to be persistent memory updates. In order to keep the storage system that resides in persistent memory consistent, both the I/O interface and the CPU cache hardware are extended to make sure that the data in the volatile cache is persisted to persistent memory atomically. Interface. The I/O interface, which lies between the CPU core and the CPU cache hardware, is extended with transactional instructions: TxBegin, TxCommit, TxAbort and TxFlush. TxBegin, TxCommit and TxAbort are respectively used to start, commit and abort a transaction. TxFlush is used to explicitly write data to persistent memory from the CPU cache. In LOC, durability and atomicity are decoupled, similarly to the approaches of [16], [20], [83]. TxCommit and TxFlush are combined to provide both atomicity and durability in LOC.

Design Overview
Components. LOC also extends the cache and memory controllers to support transactional operations and allocates a dedicated memory area for logging. Figure 3 shows the extended components (as highlighted). Memory Log Area is a memory area that is used for keeping logs and is directly managed by the commit and recovery logic. Memory log area is not visible to the programs. To exploit the parallelism for logging performance, memory log area spans across different memory banks. Transaction (Tx) Tracking component has two roles. First, it tracks all transactional writes. Transactional writes are the writes wrapped between TxBegin and TxCommit/TxAbort. Each transactional write is tagged with its TxID. Second, the Tx Tracking component tracks the status of each transaction and the commit sequence of running transactions. Commit and Recovery Logic commits or aborts a transaction and initializes the recovery process if the system crashes. The commit logic directly manages the memory log area and enforces the ordering between different transaction phases. During the recovery period after system failures, the recovery logic reads logs from the memory log area, checks the status of transactions, and redoes the committed transactions while discarding the uncommitted ones.
Operations. A transaction writes data in three phases: execution, logging and checkpointing. In the execution phase, data are written to the CPU cache. In this phase, transactional semantics are passed to the CPU cache with the extended transactional interface. Transactional writes are buffered in the CPU cache until the transaction commits. When a transaction commits, it enters the logging phase, in which data are persisted to the memory log area (i.e., log write). Only after all data are completely persisted to the log, a transaction can enter the checkpointing phase, in which data are written to their home locations in persistent memory (i.e., in-place write).
In LOC, rather than keeping two copies (log write and in-place write) of each data block in the CPU cache, LOC only stores a single copy by directly managing the Memory Log Area. To improve both performance and endurance of persistent memory, LOC provides the Eager Commit technique (to remove the intra-tx ordering at the end of logging phase) and the Speculative Persistence technique (to relax the inter-tx ordering just after the logging phase). We describe the two techniques in detail next.

Eager Commit
The commit protocol in storage transactions is the consensus between normal execution and recovery on system failure. It is used to determine when to switch between the old and new versions of data that is updated by a transaction. In the commonly used WAL protocol (described in Section 2), a commit record is used for each transaction to indicate this switch. The commit protocol in WAL makes sure that (1) the new version of data is persisted before writing the commit record, and (2) the old version of the data is overwritten only after the persistent update of the commit record. On a system crash/failure, the recovery logic checks the availability of the commit record for a transaction. If the commit record exists, the transaction is determined to be committed, and the new versions of the committed data blocks are copied from the log to their home locations in persistent memory; otherwise, the transaction is determined to be not committed (i.e., system might have crashed before the transaction commit is complete), and the log data associated with the transaction is discarded.
Unfortunately, it is the commit record itself that introduces the intra-tx ordering requirement (described in Section 2) and therefore degrades performance heavily in persistent memory. Eager Commit eliminates the use of the commit record and thus removes the intra-tx ordering. The key idea is to not wait for the completeness of log writes and instead eagerly commit a transaction. The completion check of log writes is delayed until the recovery phase. The removal of completion check from the critical commit path removes the intra-tx ordering and thus reduces the commit latency of each transaction. Eager Commit enables a delayed completion check at recovery time using a static log organization with a count-based commit protocol, which we describe next. This static log organization enables 1) the system to determine the status of each transaction during recovery without requiring the use/query of a commit record, 2) enables updates of different transactions to the log to be interleaved in the log.
Log Organization. Eager Commit organizes the memory log space in a static manner, as opposed to appending all updated data blocks and the commit record at the end of the log for a transaction, as done in WAL. It divides the memory log area into block groups, as shown in Figure 4. Each block group consists of eight data blocks, seven for the log data and one for the metadata associated with the seven data blocks. The size of each block is 64 bytes, which can be transmitted to memory in a single burst [41], [109]. In a block group, the eight blocks are issued serially by the memory controller, with simple enhancements to the memory controller as in [56], [126]. 1 This way, writes of the data and metadata blocks are ordered in each block group, ensuring that all data blocks are persisted first before metadata is persisted, which guarantees consistency. Since this ordering is ensured by the memory scheduling mechanism in the memory controller, it has negligible overhead compared to the ordering in the multi-level CPU cache. During recovery after a system crash, the metadata of the block group can be read to determine the status of the data blocks of the block group.

Memory Log Area
BLK-TAG (64) BLK-TAG (64) BLK-TAG (64) BLK-TAG (64) BLK-TAG (64) BLK-TAG (64) BLK-TAG (64) CID (3)  TAG) of the other blocks. BLK-TAG records the CPU core ID (CID), the hardware thread ID (TID) 2 , the transactional identifier (TxID), the transactional counter (TxCnt), and the home location address (ADDR) of the data in the block. The first three IDs are used to identify the transaction. Therefore, blocks from different transactions can be written to the log in an interleaved manner. For the same reason, log blocks are allocated when the log data is evicted from the CPU cache to the memory controller. This ensures that the memory controller buffers do not overflow when buffering log blocks of the same transaction. On recovery, each data block is identified as belonging to some transaction using the three IDs. Afterwards, the commit protocol uses the pairs <T xID, T xCnt> to determine the transaction status, as described below. Finally, LOC retrieves the ADDR of a data block, which is a pointer that points to the home location in the data area of a data block, to write the committed data block in the memory log area to its home location in the data area.
Our current LOC implementation supports 128 running transactions using an 8-bit TxID 3 , and allows the largest transaction size of 32K blocks using a 16-bit TxCnt. The maximum memory space that is currently supported is 256 gigabytes, due to the 32-bit ADDR (for 64-byte blocks). These limitations can be altered by changing the bits allocated to the different fields or by using the reserved bits. In addition, we assume a 64-byte granularity for update operations. While finer-grained byte addressability reduces internal fragmentation, it leads to higher metadata overhead. We believe this is a general trade-off, and the 64byte granularity, which is the size of a cache block in many modern systems, is feasible for persistent memory transactions.
Commit Protocol. In the memory log area, each data block has associated transactional metadata, <T xID, T xCnt>. Eager Commit uses the pair <T xID, T xCnt> to determine the committed/not-committed status of each transaction. For each transaction, the last data block has its associated TxCnt value set to the total number of data blocks in its transaction, and all the others have TxCnt set to zero. During recovery, the number of data blocks logged for a transaction (those that have the same TxID) is counted and this count is compared with the non-zero TxCnt stored with 2. The CID and TID fields are not used in this paper, but are reserved to support multi-thread and multi-core transactions in future work.
3 one of the data blocks. If the count matches the non-zero TxCnt (indicating that all of the transaction's data blocks are already written to the log), the transaction is deemed to be committed and the recovery process copies its updated blocks from the log to the home locations of the blocks in persistent memory. Otherwise, the transaction is deemed to be not committed and its entries in the log are discarded. We borrow this count-based commit protocol from [70], where it is described in more detail.
Eager Commit shares the same philosophy with the torn bit technique in Mnemosyne [121] to distribute the commit record for a transaction across the individual log records comprising a transaction and to avoid the sequential dependency between all the individual logs and the commit record. In the torn bit technique, one bit is reserved in each data block to indicate the block's status. Thus, only 63 bits can be stored in each 64-bit data block, and the torn bit technique requires bit shifting. In contrast, Eager Commit statically organizes data blocks into groups and does not need to shift data in the log records. Eager Commit is more friendly to data writes, which are mostly byte-aligned.
In conclusion, Eager Commit removes the intra-tx ordering by using a static log organization and a count-based commit protocol that can enable the determination of transaction status upon recovery without requiring a commit record.

Speculative Persistence
Inter-tx ordering guarantees that the commit sequence of transactions in the storage system is the same as the commit issue order of transactions by the program (i.e., the order in which transaction commit commands are issued). To maintain this order, all blocks in one transaction must be persisted to the memory log before any block of a later transaction is persisted. To ensure this, a cache conflict in the CPU cache that causes a block of a later transaction to be evicted must force the eviction of all data blocks of itself and previous transactions. Thus, inter-tx ordering not only causes significant serialization of persistent memory requests but it also results in inefficient utilization of the CPU cache and higher memory traffic, thereby degrading system performance and endurance.
Speculative Persistence relaxes inter-tx ordering by allowing blocks from different transactions to be written to the persistent memory log speculatively, out of the softwarespecified transaction commit issue order. However, the written blocks become visible to software only in the softwarespecified order. As such, the high-level idea is somewhat similar to out-of-order execution in modern processors [90], [96], [117]: persistent memory writes are completed out-of the program-specified transaction order (within a window) but they are made visible to software in program transaction commit order. We call this property "out-of-order persistence, in-order commit".
With Speculative Persistence, a transaction starts persisting its data blocks without waiting for the completion of the persistence of previous transactions' data blocks. Instead, there is a speculation window, in which all transactions are persisted out-of-order. The size of the speculation window is called speculation degree (SD). Speculation degree defines the maximum number of transactions that are allowed to persist log blocks out-of-order. As such, the inter-tx ordering is relaxed. Relaxed inter-tx ordering brings two benefits. First, cache conflict of one data block does not force eviction of all blocks of its and all previous transactions. This improves the cache utilization. Second, writes from multiple transactions are coalesced when written back to memory, which leads to lower memory traffic and improved endurance. Figure 5 illustrates transaction persistence in a speculation window with a speculation degree of four. Within the speculation window, data blocks from the four transactions can be persisted in any order. For instance, blocks in T3 can be persisted before blocks in T2. For a data block that has multiple versions across transactions, only the latest version needs to be persisted. None of the blocks in T1 (A, B, C, D) need to be written to memory because their later versions, block A in T2 and blocks B, C, D in T3, will overwrite them. Therefore, inter-tx ordering is relaxed within the speculation window.  5 also illustrates that Speculative Persistence preserves the "out-of-order persistence, in-order commit" property: transaction T1 is reported to be committed while T3 is not, because T2 has not finished its updates to the persistent memory log. To preserve this property, Speculative Persistence has to carefully deal with 1) overlapping writes from different transactions (to the same block) to ensure that any write to any block is recoverable, and 2) commit dependencies between transactions to ensure that transactions are committed in program order. To enable the former, our mechanism supports multi-versioning in the CPU cache. To enable the latter, our proposal not only leverages multiversioning in the CPU cache but also keeps track of the committed transaction ID based on the commit issue order of transactions by the program. We describe both of these next.
Multiple Versions in the CPU Cache. In Speculative Persistence, multiple versions of a data block are maintained in the volatile CPU cache, similarly to the versioning cache [29]. Otherwise, if only a single copy (the latest copy) is kept but the transaction that last wrote to the block aborts, all previously committed transactions that were supposed to write to the block would also have to be aborted. With multiple versions of a data block present in the cache, one version can be removed only when one of its succeeding versions has been committed (i.e., the software has committed a laterin-program-order transaction that writes to the data block). This is because the committed version in a future transaction that is committed later in program order is guaranteed to overwrite any previous version regardless of whether the transaction that is supposed to write to the previous version is aborted or committed.
There are two issues with keeping multiple versions in the cache: 1) version overflow, 2) increased cache pressure. First, version overflow refers to the case that the associativity of the cache is not enough to keep all active versions of a cache block (or different cache blocks) in the corresponding cache set. When this happens, our design evicts the oldest version to the memory log to make space for the new version. This eviction can reduce the benefit of Speculative Persistence: probability of merging of writes from different transactions reduces and an old version of the block may be written to persistent memory unnecessarily. However, this eviction does not affect the correctness of the commit protocol. Second, since multiple versions of a block are kept in the cache set, the pressure on the cache set increases compared to a conventional cache, which may lead to higher miss rates. Both of these two cases hurt the efficiency of the CPU cache. 4 As a result, memory traffic increases, accelerating the wear-out process of persistent memory. Therefore, arbitrarily increasing the speculative degree does not always bring more benefit and in fact it can do harm by wearing out memory faster. Note that, although Speculative Persistence keeps multiple cache versions of a block, only the latest version is persisted to the memory log when versions do not overflow. As such, write coalescing is enabled across transactions within a speculation window. In general, memory traffic can be reduced by using speculative persistence, and memory endurance can be improved.
Commit Dependencies Between Transactions. Write coalescing for a block across different transactions causes new transaction dependencies that need to be resolved carefully at transaction commit time. This happens due to two reasons: 1) an aborted transaction may have overwritten a block in its preceding transactions, 2) an aborted transaction may have a block that is overwritten by succeeding transactions that have completed the update of their logs with the new version. Both reasons are caused by what we call as overlapped writes, i.e., multiple writes in which part or all of a data block are written by multiple transactions. To maintain out-of-order persistence, in-order commit property of Speculative Persistence, we have to deal with two problems when a transaction aborts: 1) how to rescue the preceding transactions that have overlapped writes with the aborted transaction?, and 2) how to abort the succeeding transactions that have completed the write of their logs for an overlapped write with the aborted transaction?
The two problems are solved by tracking the commit issue order of the transactions within each speculation window 4. If only a single copy is kept in the CPU cache (without a versioning cache), the speculative persistence technique is similar to the group commit technique (or transaction batching) [36]. Transactions in one speculative window are either all committed or all aborted. With multiple versions in the CPU cache, the speculative persistence technique can commit each transaction in the speculative window separately in a finegrained manner, which obeys the semantics of program transactions. along with leveraging the multi-versioning support in the CPU cache. To solve the first problem, when an abort happens, preceding transactions that have overlapped writes with the aborted transaction write their versions of the blocks written by the aborted transaction from the CPU cache to the persistent memory log. To solve the second problem, we simply abort the transactions that come later in the commit issue order than the aborted transactions. In the recovery phase, a transaction is determined to be committed only if it is checked to be committed using the countbased commit protocol that checks TxCnt (as described in Section 3.2) and its preceding transactions in its speculation window are committed.
Modifications to the Commit Protocol. In Speculative Persistence, overlapped writes in the same speculation window are merged, as described above. As a result, a transaction that has overlapped writes with succeeding transactions does not write the overlapped data blocks to the persistent memory log. This requires a modification to the commit protocol we described in Section 3.2 because, without modification of the commit protocol, the transaction might be mistaken as a not-committed transaction as the actual number of data blocks in the memory log area that are stored for it is different from the non-zero TxCnt. To differentiate between the two kinds of transactions (those with overlapped writes and non-overlapped writes), we add a new field of metadata, Transaction Dependency Pair, in the memory log to represent the dependency between transactions with overlapped writes. Transaction Dependency Pair <T a , T b , n> represents that transaction T a has n overlapped writes with its succeeding transaction T b . Transaction T a is determined to be committed if and only if T b is committed and the actual number of log blocks of T a plus n equals its non-zero TxCnt. As such, Transaction Dependency Pairs help the commit status identification of transactions with coalesced writes.

Recovery from System Failure
Upon a system crash/failure, LOC scans the memory log area to recover the system to a consistent state. It first checks the start and end addresses of the valid logs, and then reads and processes the logs in the unit of speculation window. It processes each speculation window one by one, in program order. Since strict ordering is required between speculation windows, transactions across speculation windows have no dependencies. Each speculation window can thus be recovered independently.
First, the META block of each data block group is read in each speculation window,. LOC counts the number of BLK-TAGs for each <CID, T ID, T xID>; this is the number of logged blocks of a transaction. If the number matches the non-zero TxCnt in any BLK-TAG of the transaction, the transaction is marked as committed.
Second, Transaction Dependency Pairs from the memory log area are read. For each pair <T a , T b , n>, LOC adds the value n to T a if T b is committed. These pairs are checked in the reverse sequence, from tail to head. After this step, transactions that have overlapped writes are marked as committed using the commit protocol.
Third, the first not-committed transaction is found. All transactions after it are marked as not-committed. This guarantees the in-order commit property. After this, LOC finishes the committed transactions by writing the data blocks of these transactions to the home locations of the data blocks. Recovery completes after discarding all data blocks of the not-committed transactions from the log, and the system returns to a consistent state.

LOC vs. Transactional Memory
As discussed in Section 2, Transactional Memory (TM) [31], [37] and LOC work respectively on the concurrency control and transaction recovery aspects of transaction mechanisms. LOC focuses on how to provide crash consistency in the presence of a transactional interface (i.e., how to recover transaction states, crash recovery) and does not deal with how concurrency control is handled. In contrast, TM focuses on how to provide concurrency control. We currently assume a transactional interface for LOC (which supports storage transactions), but do not provide support for TM as our goal is to ensure LOC works with storage transactions. The combination of TM concurrency control mechanisms and LOC's transaction recovery mechanisms is left for future work.
LOC focuses on crash recovery of single-thread transactions, and does not currently support cross-core transactions. In LOC, a unique transaction can be performed only in one core at a given point in time. Concurrency of multi-cores can still be exploited, when there are enough threads from the software performing different transactions. Supporting concurrency control is complex due to the need for modifying cache coherence to provide isolation, which is the focus of transactional memory techniques [31], [37], but not LOC. While LOC and transactional memory share similar designs (e.g., a transactional interface and version control mechanisms) and work on different aspects of transactional execution mechanisms, they have potential to be combined to provide full ACID properties (as illustrated in Figure 1). We leave this exploration for future work.

IMPLEMENTATION AND HARDWARE OVERHEAD
We now describe the architecture implementation details and discuss the hardware overhead of LOC.

ISA Extensions
To support storage transactions, We extend the Instruction Set Architecture (ISA) with transactional instructions: TxBegin, TxCommit and TxAbort. The ISA extensions are similar to those in hardware transactional memory, which have been implemented in processors like Intel's Haswell [40] and IBM's zEC12 [44]. Different from transactional memory, ISA extensions in LOC require persistence in each phase of a transaction. In LOC, software defines the semantics of storage consistency and specifies the range of a transaction using existing transactional interfaces as in DBMSs, filesystems and other applications: txbegin, txcommit, txabort [70], [82], [100], [121]. A compiler can easily translate these interface commands into the extended ISA instructions, so as to enforce the software's transactional semantics/calls at the hardware level. Note that LOC allows reordering of non-transactional writes, and does not enforce an ordering between the transactional and non-transactional writes.
In addition, ISA is extended with another instruction, CheckMaxCommit, to check the last committed transaction. LOC adds a LastCommittedTxID register in the CPU cache.  TxST  CID  0  0  3  3  TID  1  1  1  1  TxID  8  8  8  8  TxDirty  0  0  1  0  TxCnt  0  0  0  16  State  0  0  0  2  Phase  0  0  0  2  Wrts  0  0  0  16  Total  9  9  12   A committed transaction updates the register with its ID when all previous transactions have been committed. The CheckMaxCommit instruction is used for software to query the last committed transaction. Limitations. LOC does not ensure application consistency after application crashes, but ensures system consistency for system crashes (e.g., power failure). This guarantee, i.e., system crash consistency, is the same as that provided by traditional file systems or database management systems. In an application crashes, there are two major types of errors. The first is an incomplete <TxBegin, TxCommit/TxAbort> pair, i.e., a transaction might not have stopped after being started. This kind of error can be checked by the compiler and can be reported during compilation time. The second type is application crash during execution, i.e., a runtime error. The OS can detect the crashed process and restart it. Before that, the failed process is killed and cleaned. Active transactions of threads of the process are aborted. The transaction (atomicity) semantics ensure the consistent state of persistent memory.

Components
LOC adds three new components to the system: Tx Tracking Component, Commit/Recovery Logic, and Memory Log Area. Figure 6 shows where these components reside. Tx Tracking Component has two parts: Tx Dirty Block It is supported with extra bits added to the tag store of each cache. As shown in Figure 6(a), each tag in all cache levels is extended with the hardware thread ID (TID) and the transaction ID (TxID). In the LLC, two other fields, the CPU core ID (CID) and the transaction dirty flag (TxDirty), are also added. TxDirty indicates whether the block has been written to the persistent memory log, and the original dirty flag indicates whether the block has been written to its home location. Transaction durability is achieved when log writes are persistent, i.e., TxDirty is unset. After that, homelocation writes can be performed using the original dirty flag as in a conventional CPU cache. The storage overhead of each cache is illustrated in Figure 6(b). Only 9 bits (or 12 bits) are added for each 64B block in each level of cache (or LLC). Tx State Table (TxST) tracks the status of active transactions, as shown in Figure 6. Each TxST entry contains the CID, TID, TxID, TxCnt, State, Phase and Wrts fields.
State denotes the transaction state, as shown in Figure 6(c). State transitions are induced by transactional commands. For instance, TxBegin changes the state from invalid to active; TxCommit (TxAbort) changes the state from active to committed (aborted). Phase denotes the current status of the write-back of the transaction: the transaction could be in the log writing phase, in-place writing phase updating home locations or could have completed the entire writeback, as shown in Figure 6(d). Wrts denotes the number of blocks written back in each phase, and is used to keep track of the completeness of log writing or in-place writing to determine the status of each transaction. The storage overhead is shown in Figure 6(b). Each TxST entry has 48 bits. For 128 transactions allowed in the system, the total size of TxST is 768 bytes.
Commit/Recovery Logic (CRL) receives transactional commands and manages the status of each transaction in the Tx State Table. CRL stalls new transactions until the current speculation window completes. For each speculation window, CRL tracks different versions of each data block and adds a 32KB volatile buffer to store its Tx Dependency Pairs. When a speculation window completes, the buffer is written back to the memory log area. In addition, CRL maintains a LastCommittedTxID register to keep the ID of the last committed transaction, which indicates to the software that all transactions with smaller IDs are committed.
Memory Log Area is a contiguous physical memory space to log the writes from transactions. At the beginning of the memory log area, there is a log head, which records the start and end addresses of the valid data logs. The main body of the memory log area consists of the log data block groups (as shown in Figure 4) and the metadata of Tx Dependency Pairs (introduced in Section 3.3). This area is invisible to the software, and is allocated by the memory controller. To overcome the endurance problem of NVM, allocation of this area is moved around in the physical memory periodically (similar to the notion of Start-Gap Wear Leveling [102]). Note that other techniques can also be employed to ensure that the memory log area or the memory does not wear out due to log updates. In our evaluations, 32MB memory is allocated for the Memory Log Area as this was empirically found to be enough for the supported 128 transactions, but this space can be dynamically expanded.

EVALUATION
In this section, we first compare LOC with previous transaction protocols. Then, we analyze the benefits of Eager Commit and Speculative Persistence. Finally, we study sensitivity to transaction size and memory latency.

Experimental Setup
We evaluate different transaction protocols using a fullsystem simulator, GEM5 [9]. GEM5 is configured using the syscall emulation (SE) mode. Benchmarks can directly run on the full system simulator without modification or recompilation. In the evaluation, GEM5 uses the Timing Simple CPU mode and the Ruby memory system. The CPU is 1 GHz, and the CPU cache and memory have the parameters shown in Table 1. We revise both the cache and memory controllers in GEM5 to simulate LOC, as shown in Figure 6. We faithfully model all overheads associated with LOC. In our evaluation, the Speculation Degree of LOC is set to 16 by default. Workloads. Table 2 lists the workloads we evaluate. B+ tree is a widely used data structure in both file systems and database management systems. We implement a B+ tree, in which each 4KB node contains 200 key(8B)-value(4B) pairs. Each transaction consists of multiple key-value insert or delete operations. Similarly, we use the hash table, redblack tree and random array swap data structures, also used in literature [19]. Our graph processing workload inserts and deletes edges in a large graph [4]. We also evaluate a database workload [2] on SQLite 3.7.17 [3]. In Table 2, we provide the average size of the persistence set (P-Set), which is the number of data blocks per transaction that have to be persisted to ensure transaction durability, in each workload.

Overall Performance
We measure and compare both transaction throughput and memory write traffic of five different transaction protocols: S-WAL, H-WAL, LOC-WAL, Kiln and LOC-Kiln. S-WAL is a software WAL (Write-Ahead Logging) protocol that manages logging and ordering in software, as shown in Figure 2(a). H-WAL is a hardware WAL protocol that manages logging in hardware. Different from S-WAL, which writes two copies respectively for log and in-place writes in the CPU cache, H-WAL keeps only a single copy in the CPU cache and lets the hardware manage the log and in-place writes. H-WAL does not change the ordering behavior of S-WAL. LOC-WAL is our proposed protocol in this paper. Kiln is a recent protocol that uses a non-volatile last-level cache (LLC) to reduce the persistence overhead [125]. It keeps the new and old version of data blocks respectively in the LLC and persistent memory, thereby eliminating the need for performing double copies in persistent memory. Kiln also needs to preserve the order with which transactional writes are evicted from the LLC only after the transaction commits. Otherwise, the transactional writes overwrite the old-version data in persistent memory, which cannot be recovered after a transaction failure. Since Kiln's optimization is orthogonal to our LOC mechanism, we combine the two and also evaluate this combined version, called LOC-Kiln. LOC-Kiln achieves the best of both Kiln and LOC by only flushing L1 and L2 caches (as in Kiln) and performing loose ordering (as in LOC).
Transaction Throughput. Figure 7 shows the normalized transaction throughput of the five protocols. The results are normalized to the transaction throughput of the baseline, which runs benchmarks without any transaction support and thus without the associated overheads of transactions. Note that this baseline does not provide consistency upon system failure and is intended to show the overhead of providing such consistency via different mechanisms. Transaction throughput is calculated by dividing the total number of committed transactions with the total runtime of each benchmark. We make two key observations. (1) LOC significantly improves the performance of WAL, including both S-WAL and H-WAL. Normalized transaction throughput increases from 0.316 in S-WAL and 0.331 in H-WAL to 0.651 in LOC-WAL. In other words, LOC-WAL reduces ordering overhead from 68.4% in S-WAL and 66.9% in H-WAL to 34.9%. This is because S-WAL manages logging in software. The log writes and home-location writes have different memory addresses, and thus are independently cached in the CPU cache. Keeping two copies in the CPU cache hurts cache efficiency, which H-WAL removes, but this does not greatly reduce the overhead of WAL. LOC greatly reduces the overhead of WAL by removing intratx ordering using Eager Commit and loosening inter-tx ordering using Speculative Persistence. The loosened ordering improves cache efficiency and increases the probability of write coalescing in the CPU cache.
(2) LOC and Kiln can be combined favorably. Doing so improves normalized transaction throughput to 0.811 on average, i.e., the ordering overhead is reduced to 18.9%. Kiln shortens the persistence path by employing a non-volatile last-level cache. LOC mitigates performance degradation via a complementary technique, i.e., loosening the persistence ordering overhead that still exists in a non-volatile cache.
Endurance. Figure 8 shows the memory write traffic of the five protocols. The memory write traffic in the figure is calculated by dividing the total size of memory writes by the total size of program writes. Lower memory write traffic indicates better cache efficiency of the CPU cache and better endurance of persistent memory. As shown in the figure, the memory write traffic in different workloads is dramatically reduced from 0.200 in H-WAL and 0.171 in S-WAL to 0.034 in LOC-WAL on average. The benefits of LOC-WAL come from the write coalescing of overlapped transactional writes across transactions in the speculative persistence technique, which will be further evaluated in Section 5.4. Kiln uses a non-volatile last level cache, and the memory write traffic is only 0.008. LOC-Kiln has even lower memory write traffic, which is 0.06% lower than that in Kiln. We conclude that LOC effectively mitigates performance degradation and reduces write traffic (and thus improves endurance of persistent memory) due to persistence ordering by relaxing both intra-and inter-transaction ordering.

Effect of the Eager Commit Protocol
We compare the transaction throughput of H-WAL and EC-WAL. EC-WAL is the LOC mechanism for WAL with only Eager Commit but without Speculative Persistence. Figure 9 plots the normalized transaction throughput of the two techniques. EC-WAL outperforms H-WAL by 6.4% on average. This is because it removes the completeness check in Eager Commit from the critical path of transaction commit. The elimination of intra-tx ordering leads to fewer cache flushes and improves cache efficiency.

Effect of Speculative Persistence
To evaluate both performance and endurance gains from Speculative Persistence, we vary the speculation degree (SD) from 1 to 32 (SD was set to 16 in previous evaluations). Figure 10 shows the normalized transaction throughput of LOC-WAL with different SD values. On average, the normalized transaction throughput of LOC-WAL increases from 0.353 to 0.689 with 95.5% improvement, going from SD=1 to SD=32. This benefit comes from two aspects of Speculative Persistence. First, Speculative Persistence allows out-of-order persistence of different transactions. A cache block without a cache conflict is not forced to be written back to persistent memory within a speculation window (as explained in Section 3.3), thereby reducing memory traffic and improving cache efficiency. Second, Speculative Persistence enables write coalescing across transactions within the speculation window, thereby reducing memory traffic. Both of these effects increase as the speculation degree increases, leading to larger performance benefits with larger speculation degrees.  Figure 11 shows the memory write traffic of LOC-WAL with different speculation degrees. In each workload, the memory write traffic is reduced instantly when the speculation degree (SD) is increased from 1 to 16. This shows that the probability of write coalescing gets higher when more transactions are allowed to be persisted out-of-order. An exception to this trend is observed when SD is 32. When SD increases from 16 to 32, LOC-WAL shows a slight increase in memory write traffic. The reason is that more concurrently executed transactions incur a higher probability of cache evictions in the CPU cache. Generally, memory write traffic reduces with a higher speculation degree. In conclusion, LOC generally gains more benefits when the speculation degree is higher, i.e., when more transactions are allowed to be persisted concurrently.

Impact of Transaction Size
To study the impact of transaction size on performance penalty from ordering, we also measure the transaction throughput of LOC-WAL using B+ Tree with different transaction sizes. Transaction size is changed by updating a different number of tree nodes in each transaction, varying from 2 to 32. Figure 12 shows the normalized transaction throughput of LOC-WAL under workloads with different transaction sizes. Results in each transaction size setting are normalized to the baseline case, which runs benchmarks without transaction support. Two conclusions are in order. First, the LOC mechanism is more beneficial to workloads with smaller transaction sizes than those with larger ones. When the transaction size is small, amortized ordering overhead for each operation is high. Therefore, ordering overhead is more significant in workloads with smaller transaction sizes. Thus, relaxed ordering in the LOC mechanism has a larger effect. Second, performance gains from non-volatile last-level cache (LLC) are less significant than those from the LOC mechanism when transaction size is large. When the transaction size becomes larger, not all data blocks can be buffered in the LLC. As Kiln requires that all new-version data are persistently buffered in the LLC, Kiln has to fall back to WAL mode for memory logging for large transactions. Thus, Kiln provides less benefit for workloads with larger transaction sizes. When the transaction size increases to 32, both LOC-WAL and LOC-Kiln achieve performance comparable to baseline without any transaction overhead. In conclusion, the LOC mechanism is especially beneficial to workloads with small transaction sizes, yet it provides performance benefits across the board, for workloads with many different transaction sizes.

Sensitivity to Memory Latency
We evaluate LOC performance with different memory latencies to approximate the effect of different types of nonvolatile memories. We vary the memory latency between 35, 95, 168 and 1000 nanoseconds (our default evaluations so far were with a 168-nanosecond latency). We measure the transaction throughput of both H-WAL and LOC at each latency. Figure 13 shows the performance improvement of LOC over H-WAL at different memory latencies. In the figure, the black part of each stacked bar shows the normalized transaction throughput of H-WAL, and the grey part shows the performance improvement of LOC over H-WAL. Two major observations are in order. First, performance of H-WAL reduces as memory latency increases. This shows that higher memory latency in NVMs leads to higher persistence ordering overheads. Second, LOC's performance improvement increases as memory latency increases. This is because LOC is able to reduce the persistence overhead, which increases with memory latency. We conclude that persistence ordering overhead is becoming a more serious issue with higher-latency NVMs, which LOC can effectively mitigate.

RELATED WORK
Mitigating the Ordering Overhead. As explained in Section 1, in order to preserve persistence ordering from the CPU cache to persistent memory, software combines cache flush (e.g., clflush) and memory fence (e.g., mfence) instructions to force the ordering of cache writebacks [19], [120], [121], [122]. The average overhead of a clflush and mfence combined together is reported to be 250ns [121], which makes this approach costly, given that persistent memory access times are expected to be on the order of tens to hundreds of nanoseconds [57], [58], [103]. 5 The two instructions flush dirty data blocks from the CPU cache to persistent memory and wait for the completion of all memory writes, and thus incur high overhead in persistent memory [20], [99], [121], [125].
Several works attempt to mitigate the ordering overhead in persistent memory with hardware support. These can be classified into two approaches, as follows.
(1) Making the CPU cache non-volatile: This approach aims to reduce the time gap between volatility and persistence by employing a non-volatile cache. Kiln [125] uses a nonvolatile last-level cache (NV-LLC), so that the path of data persistence becomes shorter and the overhead of the required ordering is smaller. Kiln also uses the NV-LLC as the log to eliminate the need to perform multiple writes in main memory. Whole-system persistence [93] takes this approach to the extreme by making all levels of the CPU cache nonvolatile. Similarly, JUSTDO [43] makes all levels of the CPU cache non-volatile and optimizes the log organization. The approach we develop in this paper, LOC, is complementary to the approach of employing NV caches.
(2) Allowing asynchronous commit of transactions: This approach allows the execution of a later transaction without waiting for the persistence of previous transactions. To ensure consistency, the program queries the hardware for the persistence status of transactions. BPFS [20] and CLC [83] use versions of this approach. They inform the CPU cache hardware of the ordering points within the program via the epoch command, and let the hardware keep the ordering asynchronously without waiting for data persistence within each epoch. In addition to the cache hierarchy, enhancements have been made to the memory controller to support the epoch semantics [56], [92]. The epoch semantic is also extended to multicore CPUs [47]. Strand persistency [99] enables the reordering of the commit sequence of transactions for better concurrency (instead of requiring a strict order in which transactions have to be committed). Mechanisms for isolation and concurrency have also been supported by enhancing the memory controller in various ways [23], [116], [126]. A recent work, ThyNVM [105], introduces checkpointing to the DRAM+NVM hybrid persistent memory to overlap application execution and hardware checkpointing, to provide transparent crash consistency.
The asynchronous commit approaches change only the execution order (i.e., the order of CPU cache writes) but not the persistence order (i.e., the order of persistent memory writes) as specified by the program. 6 In contrast, our proposal, LOC, allows the reordering of persistent memory writes of different transactions in a finer-grained manner 5. Recent research argues that these commands, which are used for cache coherence, do not correctly flush cache data to persistent memory, and thus proposes to ensure ordering in CPU hardware [20], [24]. 6. Even with strand persistency [99], the persistence order is fixed once transaction concurrency has been specified in the program. and can be combined with the asynchronous commit approaches.
BPPM [73], [74] reduces the persistence overhead by blurring the volatility-persistency boundary. This work relaxes the requirement of data persistence. In contrast, LOC does not require the relaxation of data persistence requirements. Instead, it reduces the consistency overhead by speculatively relaxing the ordering requirement using a hardware-based approach. Note that LOC can be combined with the method of [73], [74] for even higher benefits.
Eager and Speculative Techniques. Recent studies propose new commit protocols to reduce the overhead caused by strict ordering in traditional write-ahead logging or shadow paging mechanisms. In file systems research, NoFS [17] is proposed to use backpointers for pointer-based consistency. It is suitable for tree-like structures, e.g., file system metadata, but not for general transactions. OptFS [16] allows the reordering of log records and the commit record by storing the checksums of all log records in the commit record. The checksums can be used to determine the transaction status in the recovery phase, similar to the checksum usage in ext4 [1].
In flash-based storage, the no-overwrite property of flash memory requires updates to be performed in a copy-onwrite manner, which naturally simplifies transaction support. New commit protocols are proposed to eliminate the writes of logs and commit records by leveraging either the log-structured FTL [95] or the Out-of-Band (OOB) area [70], [77], [100]. In contrast to flash-based SSDs, non-volatile memory is byte addressable. NVM neither has an OOB area, nor does it need to update data out-of-place. Therefore, these techniques cannot be easily or efficiently applied to persistent memory.
In NVM-based secondary storage, MARS [18] proposes a new interface, editable atomic writes (EAW), in a PCIe SSD to optimize WAL. Since the PCIe SSD has the commit and recovery logic implemented inside the SSD controller, it is not suitable for persistent memory that is directly attached to the processor through memory interface. Different from such approaches that apply to storage, our proposed LOC mechanism is designed for persistent memory.
In persistent memory, Mnemosyne [121] introduces the torn-bit technique, which uses one bit in each block to indicate whether the block has been written to. The use of the torn-bit removes the usage of commit records. A recent work [55] proposes to defer transaction commit operations until after locks are released rather than performing such operations while holding the locks, to reduce persist dependencies for concurrently running transactions. While the two works [55], [121] require changes to the software, LOC is a hardware approach leveraging the memory organization.
Speculative techniques have been used in many architectural or system designs, including memory systems to reduce the overhead of memory fences for concurrent programs [10], [29]. These works deal with different problems from LOC. While these techniques are proposed for program or instruction concurrency (the ordering of program execution), speculative persistence in LOC is designed for the ordering of IO persistence.

CONCLUSION
Persistent memory provides disk-like data persistence at DRAM-like latencies, but requires memory writes to be written to persistent memory in a strict program order to maintain storage consistency. Enforcing such strict persistence ordering requires flushing dirty blocks from all levels of the volatile CPU caches and waiting for their completion at the persistent memory, which dramatically degrades system performance. Forced flush operations also incur high memory write traffic, which hurts the endurance of persistent memory. To mitigate this performance and endurance overhead, we introduced Loose-Ordering Consistency (LOC), which relaxes the persistence ordering requirement without compromising storage consistency. LOC's two key mechanisms, Eager Commit and Speculative Persistence, in combination, relax write ordering requirements both within a transaction and across multiple transactions. Our evaluations show that LOC can greatly improve system performance and endurance by reducing the ordering overhead across a wide variety of workloads. LOC also combines favorably with non-volatile CPU caches, providing performance benefits on top of systems that employ non-volatile last-level caches. We conclude that LOC can provide a high-performance consistency substrate for future persistent memory systems.