{'fraction_non_alphanumeric': 0.03390127202707434, 'fraction_numerical': 0.008314855875831485, 'mean_word_length': 5.060289957567186, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 1, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Monitoring Weak Consistency

High-performance implementations of distributed and multicore shared objects often guarantee only the weak consistency of their concurrent operations, foregoing the de-facto yet performance-restrictive consistency criterion of linearizability. While such weak consistency is often vital for achieving performance requirements, practical automation for checking weak-consistency is lacking. In principle, algorithmically checking the consistency of executions according to various weak-consistency criteria is hard: in addition to the enumeration of linearizations of an execution’s operations, such criteria generally demand the enumeration of possible visibility relations among the linearized operations; a priori, both enumerations are exponential. In this work we identify an optimization to weak-consistency checking: rather than enumerating every possible visibility relation, it suffices to consider only the minimal visibility relations which adhere to the various constraints of the given criterion, for a significant class of consistency criteria. We demonstrate the soundness of this optimization, and describe an associated minimal-visibility consistency checking algorithm. Empirically, we show that our algorithm significantly outperforms the baseline weak-consistency checking algorithm, which naïvely enumerates all visibilities, and adds only modest overhead to the baseline linearizability checking algorithm, which does not enumerate visibilities.


Introduction
Programming software applications that can deal with multiple clients at the same time, and possibly, with clients that connect at different sites in a network, relies on optimized concurrent or distributed objects which encapsulate lockfree shared memory access or message passing protocols into high-level abstract data types. Given the potentially-enormous amount of software that relies on these objects, it is important to maintain precise specifications and ensure that implementations adhere to their specifications.
One of the standard correctness criteria used in this context is linearizability (or strong consistency) [22], which ensures that the results of concurrentlyexecuted invocations match the results of some serial execution of those same invocations. Ensuring such a criterion in a distributed context (when data is replicated at different sites in a network) is practically infeasible or even impossible [17,19]. Therefore, various weak consistency criteria have been proposed like eventual consistency [23,36], "session guarantees" like read-my-writes or monotonic-reads [35], causal consistency [25,28], etc.
An axiomatic framework for formalizing such criteria has been proposed by Burckhardt et al. [11,9]. Essentially, this extends the linearizability-based specification methodology with a dynamic visibility relation among operations, in addition to the standard dynamic happens-before and linearization relations. Permitting weaker visibility relations models outcomes in which an operation may not observe the effects of concurrent operations that are linearized before it.
In this work, we propose an online monitoring algorithm that checks whether an execution of a concurrent (or distributed) object satisfies a consistency model defined in this axiomatic framework. This algorithm constructs a linearization and visibility relation satisfying the axioms of the consistency model gradually as the execution extends with more operations. It is possible that the linearization and visibility constructed until some point in time are invalidated as more operations get executed, which requires the algorithm to backtrack and search for different candidates. This exponential blow-up is unavoidable since even the problem of checking linearizability is NP-hard in general [18].
The main difficulty in devising such an algorithm is coming up with efficient strategies for enumerating linearizations and visibility relations which minimize the number of candidates needed to be explored and the number of times the algorithm has to backtrack. We build on previous works that propose such strategies for enumerating linearizations [38,29] in the context of linearizability checking. Roughly, the linearizations are extended iteratively by appending operations which are minimal in the happens-before order (among non-linearized operations). The choice of the minimal operations to append varies from one approach to the other. Our work focuses on combining such strategies with an efficient enumeration of visibility relations which are compatible with a given linearization.
Rather than specializing our results to one single consistency model, we consider a general class of consistency models from Burckhardt et al.'s axiomatic framework [11,9] in which the visibility relation among operations is constrained to be contained in the linearization relation. That class includes, for instance, time-stamp based models employed in distributed object implementations, in which time stamps serve to resolve conflicts by effectively linearizing concurrent operations. We show that within this class of consistency models, it is not necessary to enumerate the set of all possible visibility relations (included in the linearization) in order to check consistency of an execution. More precisely, we develop an algorithm for enumerating visibility relations that traverses operations in linearization order and chooses for each operation o, a minimal set of operations visible to o that conforms to the consistency axioms (up to the linearization prefix that includes o). In general there may exist multiple such minimal sets of operations, and each of them must be explored. When the visibility relation cannot be extended, the algorithm needs to backtrack and choose different minimal visibility sets for previous operations. However, when all the minimal candidates have been explored, the algorithm can soundly report that the execution is not consistent, without resorting to the exploration of non-minimal visibility relations.
Besides demonstrating the soundness of minimal-visibility consistency checking, we also demonstrate its empirical impact by applying our algorithm to concurrent traces of Java concurrent data structures. We find that our algorithm consistently outperforms the baseline naïve approach to enumerating visibilities, which considers also non-minimal visibility relations. Furthermore, we demonstrate that minimal-visibility checking adds only modest overhead (roughly 2×) to the baseline linearizability checking algorithm, which does not enumerate visibilities. This suggests that small sets of minimal visibilities typically suffice in practice, and that the additional exponential enumeration of visibilities, atop the exponential enumeration of linearizations, may be avoidable in practice. Our implementation and experiments are open source, and publicly available on GitHub. 3 In summary, this work makes the following contributions: we develop a new minimal-visibility consistency-checking algorithm for Burckhardt et al.'s axiomatic consistency framework [11,9]; we demonstrate the soundness of minimal-visibility consistency checking; and we demonstrate an empirical evaluation comparing minimal-visibility consistency checking with the state-of-the-art consistency-checking algorithms.
To the best of our knowledge, our algorithm is the first completely automatic algorithm for checking weak-consistency of arbitrary abstract data type implementations which avoids the naïve enumeration of all possible visibility relations. The rest of this paper is organized as follows. Section 2 elaborates a formalization of Burckhardt et al.'s axiomatic consistency framework [11,9], and Section 3 develops a formal argument to the soundness of considering only minimal visibility relations. Section 4 describes our overall consistency checking algorithms, and Section 5 describes our implementation and empirical evaluation. Section 6 describes related work, and finally Section 7 concludes.

Weak Consistency
We describe a formal model for concurrent (distributed) object implementations. Clients interact with an object by making invocations from a set I and receiving returns from a set R (parameters of invocations, if any, are part of the invocation name). An operation is an invocation i ∈ I paired with a return r ∈ R; we denote such an operation by i ⇒ r. We denote individual operations by o. The invocation, resp., the return, in an operation o is denoted by inv (o), resp., ret(o). 3 The URL to our implementation and experiments has been suppressed for anonymity. The interaction between a client and an object is represented by a history po, hb over a set of operations O which consists of a program (order) po which is a partial order on O, and a happens-before (order) hb which is a partial order on O.
The program order is enforced by the client, e.g., by invoking a set of operations within the same thread or process, while the happens-before order represents the order in which the operations finished, i.e., (o 1 , o 2 ) ∈ hb iff operation o 1 finished before o 2 started. We assume that the program order is included in the happens-before order. Example 1. Let us consider a key-value map ADT containing operations of the form put(key, value) ⇒ old, which insert key-value pairs and return previouslymapped values for the given keys, remove(key) ⇒ value, which remove key mappings and return previously-mapped values, contains(value) ⇒ true/false, which test whether values are currently mapped, and get(key) ⇒ value, which return currently-mapped values for the given keys. Figure 1(a) pictures a history h where edges denote the program order po and happens-before hb. Such a history can be obtained by a client with three threads each making two invocations (the invocations within the same thread are aligned vertically).
The axiomatic specifications of concurrent objects we consider are based on the following abstract representation of executions: an abstract execution over operations O is a tuple po, hb, lin, vis that consists of a history po, hb over O, a linearization (order) lin 4 which is a total order on O, and a visibility (relation) vis which is an acyclic relation on O.
Intuitively, the visibility relation represents the inter-thread communication, how effects of operations are visible to other threads, while the linearization order models the "conflict resolution policy", how the effects of concurrent operations are ordered when they become visible to other threads.
We say that an operation o 1 such that o 1 , o 2 ∈ vis is visible to o 2 , and that o 2 sees o 1 . Also, the set of operations visible to o 2 is called the visibility set of o 2 . The extensions of inv and ret to partial orders on O are defined component-wise as usual.
Example 2. Figure 1(b) pictures an abstract execution containing the history in Figure 1(a). The visibility relation is defined by the edges labeled vis together with their transitive closure. The linearization order is defined by the order in which operations are written (from top to bottom).
A consistency criterion for concurrent objects is defined by a set of axioms over the relations in an abstract execution. These axioms relate abstract executions to a sequential semantics of the operations, which is defined by a function Spec : I * × I → R that determines the return value of an invocation given the sequence of invocations previously executed on the object 5 .
Example 3. The sequential semantics of the key-value map ADT considered in Example 1 is defined as expected. For instance, the return value of put(key, value) after a sequence of invocations σ is the value null if σ contains no invocation put(key, . . .), or old if put(key, old) is the last invocation of the form put(key, . . .) in σ.
The domain dom(R) of a relation R is the set of elements x such that x, y ∈ R for some y; the codomain codom(R) is the set of elements y such that x, y ∈ R for some x. By an abuse of notation, if x is an individual element, x ∈ R denotes the fact that x ∈ dom(R) ∪ codom(R). The (left) composition R 1 • R 2 of two binary relations R 1 and R 2 is the set of pairs x, z such that x, y ∈ R 1 and y, z ∈ R 2 for some y. We denote the identity binary relation { x, x : x ∈ X} on a set X by [X], and we write [x] to denote [{x}].
Return-value consistency [9], a variant of eventual consistency without liveness guarantees, states that the return r of every operation i ⇒ r can be obtained from a sequential execution of i that follows the invocations visible to o (in the linearization order). This constraint will be formalized as an axiom called Ret. The visibility relation can be chosen arbitrarily. Standard "session guarantees" can be described in the same framework by adding constraints on the visibility relation: for instance, read my writes, i.e., operations previously executed in the same thread remain visible, can be stated as vis ⊇ po and monotonic reads, i.e., the set of visible operations to some thread grows monotonically over time, can be stated as vis ⊇ vis • po. Then, a version of causal consistency [9,7], called causal convergence, is defined by the following set of axioms:   which state that the visibility relation is transitive, it includes program order, and it is included in the linearization order. Finally, linearizability is defined by the set of axioms lin ⊇ hb, vis = lin, and Ret.
To state our results in a general context that concerns multiple consistency criteria defined in the literature (including the ones mentioned above) and variations there of, we consider a language of consistency axioms φ defined by the grammar in Figure 2 In the following, we assume that every consistency model is stronger than return-value consistency, and also, that the linearization order is consistent with the visibility and happens-before relations. The assumptions concerning the linearization order correspond to the fact that for instance, concurrent operations are ordered using timestamps that correspond to real-time. Formally, we assume that every consistency model contains the axioms  Figure 1 We extend this semantics to consistency models as e |= Φ iff e |= φ for all φ ∈ Φ and to histories as: po, hb |= Φ iff ∃lin, vis. po, hb, lin, vis |= Φ Example 4. The abstract execution in Figure 1(b) satisfies causal convergence: the visibility relation is transitive, it includes program order, and it is consistent with the linearization order. Moreover, the axiom Ret is also satisfied. For instance, the invocation contains(0) returns exactly false when executed after put(1, 0); get(1); put (1,1). Similarly, it returns true when executed after put(1, 0); get(1); put(0, 0).
Checking whether a given history satisfies a consistency model is intractable in general. This essentially follows from the fact that checking linearizability is NP-hard in general [18]. While the main issue in checking linearizability is enumerating the exponentially many linearizations, checking weaker criteria like causal convergence requires also an enumeration of the exponentially many visibility relations (included in a given linearization). We prove in this section that it is enough to enumerate only minimal visibility relations (w.r.t. set inclusion), included in a given linearization, in order to conclude whether a given history and linearization satisfy a consistency model.
A linearized history σ = po, hb, lin consists of a history and a linearization lin such that lin ⊇ hb. The extension of |= to linearized histories is defined as: The i-th element of a sequence s is denoted by s[i] and the prefix of s of length i is denoted by s i . The projection of a linearized history σ = po, hb, lin to a prefix lin i of lin is denoted by For a linearized history po, hb, lin and a consistency model Φ, a visibility relation vis i on operations from a prefix lin i of lin is called Φ-extensible when there exists a visibility relation vis ⊇ vis i such that po, hb, lin, vis |= Φ. The relation vis is called a Φ-extension of vis i up to lin. By extrapolation, a Φextension of vis i up to lin j is a visibility relation vis j such that σ j , vis j |= Φ, for any i < j. Such an extension is called minimal when for every other Φ-extension vis j of vis i up to lin j , we have that vis j ⊆ vis j .
Example 5. Consider again the abstract execution in Figure 1(b). Ignoring the edges labeled by vis, it becomes a linearized history σ. The prefix σ 2 contains just the two operations put(1, 0) ⇒ null and get(1) ⇒ 0. For causal convergence, the visibility relation vis 2 = { put(1, 0) ⇒ null, get(1) ⇒ 0 } on operations of σ 2 is extensible, as witnessed by the visibility relation defined for the rest of the operations in this execution. The visibility relation is an extension of vis 2 up to lin 3 , and contains the operations in σ 2 together with put(0, 0) ⇒ null. Note that this extension is not minimal. A minimal extension would be exactly equal to vis 2 since, intuitively, put(0, 0) ⇒ null is not required to observe operations on keys other than 0.
The next lemma shows that minimizing the visibility sets of operations in a linearization prefix, while preserving the truth of the axioms on that prefix, doesn't exclude visibility choices for future operations (occurring beyond that prefix). In more precise terms, the Φ-extensibility status is not affected by choosing smaller visibility sets for operations in a linearization prefix. For instance, since the visibility vis 3 in Example 5 is extensible (for causal convergence), the smaller visibility relation in which put(0, 0) ⇒ null doesn't see any operation, is also extensible. This result relies on the specific form of the axioms, which ensure that smaller visibility sets impose fewer constraints on the visibility sets of future operations. For instance, the axiom vis ⊇ vis • vis enforces that vis contains Proof (Sketch). We show that the Φ-extension vis of vis i up to lin can be transformed to a Φ-extension of vis i up to lin by simply removing the pairs of operations in vis i \ vis i . Let vis be this visibility relation and Φ a consistency model. We prove that po, hb, lin, vis |= Φ by considering the different types of axioms defined in Figure 2.
Suppose that Φ contains an axiom of the form vis ⊇ rel (according to the notations in Figure 2 Therefore, po, hb, lin, vis |= vis ⊇ rel . The axiom Ret relates the return value of each operation o in σ to the set of operations visible to o. This relation is insensitive to the set of operations seen by an operation before o in the linearization order. Therefore, po, hb, lin, vis |= Ret is an immediate consequence of (σ i , vis i ) |= Ret and the fact that vis and vis are the same for operations which are not included in the prefix lin i .
The axioms of the form lin ⊇ rel (according to the notations in Figure 2) are straightforward implications of lin ⊇ hb and lin ⊇ vis, which are assumed to be included in any consistency model. They hold for any linearized history. Proof. (Sketch) Let σ be a linearized history such that σ |= Φ. Therefore, there exists a visibility relation vis such that σ, vis |= Φ. We prove by induction that there exists a visibility relation vis satisfying the claim of the theorem. Assume that there exists a Φ-extensible visibility relation vis j on operations in lin j which satisfies the claim of the theorem for every i < j (we take vis 0 = vis). Let vis j+1 be a minimal visibility relation on operations in lin j+1 such that and (σ j+1 , vis j+1 ) |= Φ (such a set exists because vis j is Φ-extensible). By Lemma 1, vis j+1 is Φ-extensible. Also, vis j+1 satisfies the claim of the theorem for every i < j + 1. The reverse direction is trivial. Example 6. In the context of the abstract execution in Figure 1(b), the visibility relation defined by removing the vis edge ending in put(0, 0) ⇒ null, and adding the transitive closure, satisfies the requirements in Theorem 1.

Efficient Monitoring of Consistency Models
We describe an algorithm for checking whether a given history satisfies a consistency model, which combines linearization enumeration strategies proposed in [38,29] with the visibility enumeration strategy proposed in Section 3.
The algorithm is defined by the procedure checkConsistency listed in Figure 4. This recursive procedure searches for extensions of the input linearization and visibility (initially, checkConsistency will be called with lin = vis = ∅) which witness that the input history h satisfies Φ. It assumes that the inputs lin and vis satisfy the axioms of the consistency model Φ when the input history is projected on the linearized operations (the operations in lin). This projection is denoted by h lin . Formally, the precondition of this procedure is that h lin , lin, vis |= Φ.
The extensions of lin and vis are built in successive steps. At each step, the linearization is extended according to the procedure linExtensions and the visibility according to the procedure visExtensions.
The abstract implementation of linExtensions, presented in Figure 4 happens-before relation. The fact that the operations in O are minimal among non-linearized operations ensures that the returned linearizations are consistent with the happens-before order.
Two linearization enumeration strategies proposed in the literature can be seen as instances of linExtensions. The strategy in [38] corresponds to the case where O contains exactly one minimal operation. For instance, for the history in Figure 1(a), this strategy will start by picking a minimal element in the happens-before relation, say put(1, 0) ⇒ null, then, a minimal operation among the rest, say get(1) ⇒ 0, and so on.
The strategy proposed in [29] is slightly more involved (and according to experimental results, more efficient), but it relies on a presentation of histories h as sequences of call and return actions (an operation spanning the time interval between its call and return action). The happens-before order is extracted as usual: an operation o 1 happens before an operation o 2 if its return occurs before the call of o 2 . This strategy defines O as the first non-linearized operation o that returned in h together with a set of non-linearized operations O that are concurrent with o (i.e., are not ordered after o in the happens-before order). The operation o is linearized last in the returned extensions. For instance, consider the history h in Figure 5 represented as a sequence of call/return actions (small boxes at the begin, resp., end, of an interval denote call actions, resp., return actions). The first linearization extension (when lin = ∅) includes put(1, 0) ⇒ null (the first operation to return) after some sequence of operations concurrent with it, for instance the empty sequence. Next, the current linearization put(1, 0) ⇒ null put(1, 0) ) null contains(0) ) false get(1) ) 0 put(1, 1) ) 0 put(0, 0) ) null contains(0) ) true The procedure checkConsistency backtracks to a different extension when the current one cannot be completed to include all the operations in the input history (checked by the recursive call). The correctness of the algorithm is stated in the following theorem.

Empirical Results
While our minimal-visibility consistency checking algorithm is applicable to a wide class of distributed and multicore shared object implementations, here we demonstrate its efficacy on histories recorded from executions of Java Development Kit (JDK) Standard Edition concurrent data structures. Recent work demonstrates that JDK concurrent data structures regularly admit non-atomic behaviors, often by design [14]; these weakly-consistent behaviors span many methods of the java.util.concurrent package, including the ConcurrentHashMap, Con-currentSkipListMap, ConcurrentSkipListSet, ConcurrentLinkedQueue, and the ConcurrentLinkedDeque, for instance, including the contains method described in Example 3.
We extracted 4,000 randomly-sampled histories from approximately 8,000 observed over approximately 1,000,000 executions in stress testing 20 randomlygenerated client programs of the ConcurrentSkipListMap with up to 15 invocations across up to 3 threads. In each program, the given number of threads invokes its share of randomly-generated methods with randomly-generated values. We consider random generation superior to collecting programs in the wild, since found client programs can mask inconsistencies by restricting method argument values, or by being agnostic to inconsistent return values. Furthermore, automated generation gives us the ability to evaluate our algorithm on unbiased sample sets, and avoid any technical problems in the collection of programs; it also allows us to test method combinations which might not appear in publicly-available examples.
We subject each client program to 1 second of stress testing 6 to record histories. The return value of each invocation is stored in a different thread-local variable which is read at the end of the execution. Recording the happens-before order between invocations without affecting implementation behavior significantly (e.g., without influencing the memory orderings between shared-memory accesses) is challenging. For instance, we found the use of high-precision timers to be unsuitable, since the response-time of System.nanoTime calls is much higher than calls to the implementations under test; invoking such timers between each invocation of implementation methods would prevent implementation methods from overlapping in time, and thus hide any possible inconsistent behaviors. Similarly, the use of atomic operations and volatile variables would impose additional synchronization constraints and prevent many weak-memory reorderings.
Essentially, our solution is to introduce a shared variable per thread storing its program counter -in our context, the program counter stores the number of call and return events thus far executed. A thread's program counter is read by every other thread before and after each invocation. Figure 6 demonstrates a simplified version 7 of our encoding for a program with two threads each invoking two methods. The program counter variables pc0 and pc1 are not declared volatile, which, in principle, provides stronger guarantees concerning the derived happens-before relation; such declarations would interfere with implementation weak-memory effects. The program counter values read by each thread allows us to extract a happens-before order between invocations which is sound in the sense that the actual happens-before may order more operations, but not fewerassuming that shared-memory accesses satisfy at least the total-store order (TSO) semantics in which writes are guaranteed to be performed according to program order. For instance, when pcs[0][0] > 2 in the second thread (thread1), the first invocation in the other thread (thread0) happens-before the first invocation in this thread. Otherwise, if pcs[0][0] < 2, then the two invocations are overlapping in time. The latter may not be true in the real happens-before due to the delay in incrementing and reading the program counter variables. Although some loss of precision is possible, we are unaware of other methods for tracking happens-before which avoid significant interference with the implementation under test. Based on the encoding described above, we generate histories as sequences of call and return actions which serve as input to our consistency checking algorithms. For simplicity, we have considered just two consistency models, linearizability and a weak consistency model defined by {Ret, lin ⊇ vis, lin ⊇ hb, vis ⊇ hb}see Section 2. We consider linearizability in order to measure the overhead of checking weak consistency due to visibility enumeration; the second model is simply the easiest weak-consistency model to support with our implementation; the choice among possible weak-consistency models appears fairly arbitrary, since the enumeration of visibility relations is common to all.
We consider several measurements, the results of which are listed in Figures  each recorded history, which we report here, is accomplished accurately, without interference, by computing the clock difference just before and after validation. Our first measurements establish the baseline linearizability and weak-consistency checking algorithms. On the left side of Figure 7 we consider the time required to check linearizability for each history by our own implementations of Wing and Gong's standard enumerative approach [38], along with Lowe's "just-in-time linearizability" algorithm [29] -see Section 4. We resolve the nondeterminism in these algorithms (e.g., in choosing which pending operation to attempt linearizing first) arbitrarily (e.g., first called), finding no clear winner: each algorithm performs better on some histories. Since these subtleties are outside the scope of our work, we avoid further investigation and choose Wing and Gong's algorithm as our baseline linearizability-checking algorithm.
Our second measurement exposes the overhead of enumerating visibility relations for checking weak consistency. On the right side of Figure 7 we consider the time required to check weak consistency of a given history versus the time required to check its linearizability. 8 We observe an overhead of approximately 10× due to visibility enumeration and validation. Our naïve implementation enumerates candidate visibilities in size-decreasing order since we expect visibilityloss to be the exception rather than the rule; for instance, atomic operations observe all linearized-before operations. We omit the analogous comparison between weak-consistency checking and just-in-time linearizability checking to avoid redundancy, since the just-in-time optimization is a seemingly-insignificant factor in our experiments: the results are nearly identical.
Our third measurement demonstrates the impact of our minimal-visibility consistency checking optimization. On the left side of Figure 8  difference is dramatic, with our optimized algorithm consistently outperforming, sometimes up to multiple orders of magnitude: the leftmost 1000ms timeout of the naïve algorithm is matched by a roughly 18ms positive identification. Finally, our fourth measurement, on the right side of Figure 8, demonstrates that the overhead of our minimal-visibility checking algorithm over linearizability checking is quite modest: we observe roughly a 2× overhead, compared with the observed 10× overhead without optimization. While our experiments clearly demonstrate the efficacy of our minimalvisibility consistency checking algorithm, we will continue to evaluate this optimization across a wide range of concurrent objects, consistency models, and client programs, e.g., including many more concurrent threads. While we do expect the performance of linearizability-and weak-consistency checking to vary with thread count, we expect the performance gains of minimal-visibility consistency checking to continue to hold.

Related Work
Herlihy and Wing [22] described linearizability, which is the standard consistency criterion for shared-memory concurrent objects. Motivated by replication-based distributed systems, Burckhardt et al. [11,9] describe a more general axiomatic framework for specifying weaker consistencies like eventual consistency [36] and causal consistency [2]. Our weak consistency checking algorithm applies to consistency models described in this framework.
While several static techniques have been developed to prove linearizability [22,4,27,37,30,39,34,31,13,26,1,21,12,6,33,32,24], few have addressed dynamic techniques such as testing and runtime verification. The works in [38,29] describe monitors for checking linearizability that construct linearizations of a given history incrementally, in an online fashion. Line-Up [10] performs systematic concurrency testing via schedule enumeration, and offline linearizability checking via linearization enumeration. Our weak consistency checking algorithm combines these approaches with an efficient enumeration of visibility relations. The works in [16,15] propose a symbolic enumeration of linearizations based on a SAT solver. Although more efficient in practice, this approach applies only to certain ADTs. In this work, we propose a generic approach that assumes no constraints on the sequential semantics of the concurrent objects.
Bouajjani et al. [7] consider the problem of verifying causal consistency. They propose an algorithm for checking whether a given execution satisfies causal consistency, but only for the key-value map ADT with simple put and get operations. Our work proposes a generic algorithm that can deal with various weak consistency criteria and ADTs.
From the complexity standpoint, Gibbons and Korach [18] showed that monitoring even the single-value register type for linearizability is np-hard. Alur et al. [3] showed that checking linearizability of all executions of a given implementation is in expspace when the number of concurrent operations is bounded, and then Hamza [20] established expspace-completeness. Bouajjani et al. [5] showed that the problem becomes undecidable once the number of concurrent operations is unbounded. Also, Bouajjani et al. [8,7] investigate various ADTs for which the problems of checking eventual and causal consistency are decidable.

Conclusion
We have developed the first completely-automatic algorithm for checking weak consistency of arbitrary concurrent object implementations which avoids the naïve enumeration of all possible visibility relations. While methodologies for constructing reliable yet weakly-consistent implementations are relatively immature, we believe that such implementations will continue to be important for the development of distributed and multicore software systems. Likewise, automation for testing and verifying such implementations is, and will increasingly be, important. Besides improving state-of-the-art verification algorithms, our results represent an important step for future research which may find other ways to exploit the soundness of considering only minimal visibilities, on which our optimized algorithm relies.