{'fraction_non_alphanumeric': 0.028657273104019894, 'fraction_numerical': 0.0066929133858267716, 'mean_word_length': 5.013831775700934, 'pattern_counts': {'":': 0, '<': 2, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
Safe Execution of Concurrent Programs by Enforcement of Scheduling Constraints

Automated software verification of concurrent programs is challenging because of exponentially growing state spaces. Verification techniques such as model checking need to explore a large number of possible executions that are possible under a non-deterministic scheduler. State space reduction techniques such as partial order reduction simplify the verification problem, however, the reduced state space may still be exponentially large and intractable. This paper discusses Iteratively Relaxed Scheduling, a framework that uses scheduling constraints in order to simplify the verification problem and enable automated verification of programs which could not be handled with fully non-deterministic scheduling. Program executions are safe as long as the same scheduling constraints are enforced under which the program has been verified, e.g., by instrumenting a program with additional synchronization. As strict enforcement of scheduling constraints may induce a high execution time overhead, we present optimizations over a naive solution that reduce this overhead. Our evaluation of a prototype implementation on well-known benchmark programs shows the effect of scheduling constraints on the execution time overhead and how this overhead can be reduced by relaxing and choosing constraints.


Introduction
Concurrent programs with non-deterministic scheduling may show exponentially large state spaces which is a hurdle for automated verification such as model checking [Val96]. In contrast to testing, verification covers all possible program behavior, including different behavior due to non-deterministic scheduling. In order to reduce the complexity of the verification task, model checking techniques such as partial order reduction (POR) [CGMP99,God96,FG05] exist that reduce a concurrent program's state space. Although recent POR algorithms [WKO13, AAJS14, AAdlB + 17, SRDK17] show considerable improvements, even reduced state spaces may be of exponential size [God96] and state of the art tools for automated verification may need a long time to verify a program. In other cases, state of the art tools may even not terminate at all for a given program. Even if it is possible to manually rewrite such a program to make it tractable by a particular tool, such a process would be time consuming. Overall, the delay that is introduced by verification between completion of the implementation of a concurrent program and deployment, the verification delay, is presumably still unacceptably high for a wide industrial adoption of verification.
Iteratively Relaxed Scheduling (IRS) [MSBS17] is a framework for verification of safety properties on concurrent programs under non-deterministic scheduling. It enables a reduction and adjustment of the verification delay by enforcing scheduling constraints that ensure a safe program execution even when only a fraction of the sate space is already proven to be safe. By iteratively using intermediate verification results, scheduling constraints can be relaxed to gradually increase the amount of non-determinism of scheduling.
Permitting a safe execution of a program before complete verification has finished is a key novelty of IRS and distinguishes it from other verification techniques that use intermediate verification results. We are aware of two classes of approaches to restricting scheduling of programs, which is also necessary in IRS to ensure that only correct executions may occur. (A) Deterministic multithreading (DMT) and related techniques facilitate concurrency testing by reducing the amount of non-determinism due to concurrency, thereby reducing the number of necessary test cases and improving reproducibility of errors. Scheduling of concurrent programs is restricted such that scheduling is deterministic for a particular input or only a reduced set of schedules may occur for a particular input [LCB11, CSL + 13]. (B) Another approach to reduce non-determinism is to synthesize synchronization statements, which allows to restrict scheduling independently of inputs, in contrast to (A). Representatives of this class are automated fence insertion, which has been applied to facilitate verification of concurrent programs with relaxed memory models [BM08,FLM03] and synchronization synthesis such as [GHR + 15], which inserts locks and other synchronization primitives that are more powerful than fences in that also scheduler-related nondeterminism can be eliminated. Methods in (A) depend on concrete inputs and are therefore not suited for verification, as a change in the program inputs may have an effect on scheduling that is unforeseeable for the verifier. The effectiveness of (B) is limited as only non-determinism due to relaxed memory accesses is removed (in case of fence insertion) or deadlocks may be introduced [GHR + 15], which limits the program's functionality.
Compared to such existing approaches, IRS shows several differences that make it a candidate for more effective reduction of the verification delay. IRS uses intermediate verification results to record and iteratively increase knowledge about schedules that adhere to a given program specification (we denote such schedules as correct). Such schedules are guaranteed to show correct behavior independently of program inputs. IRS applies scheduling constraints in order to enforce that only correct schedules occur. As more schedules are explored during verification and thus known to be correct, scheduling constraints can be relaxed. In contrast to (A), determinism can be enforced independently of program inputs and the amount of non-determinism is controllable dynamically (during program execution) via scheduling constraints. Additionally, unlike some techniques in (A), IRS is able to provide strong determinism [OAA09]. In contrast to (B), IRS addresses scheduler-related non-determinism and enables to adjust the amount of non-determinism between fully deterministic and fully non-deterministic executions.
Common to all the aforementioned techniques is execution time overhead caused by additional synchronization. A central assumption underlying the feasibility of IRS is that scheduling constraints can be designed such that the execution time overhead drops below an acceptable threshold. This paper validates this assumption for different classes of benchmark programs. Hence, IRS allows to find a sweet spot between a low verification overhead and a low execution time overhead.
In order to iteratively relax scheduling constraints, it is necessary to collect knowledge about correct schedules already during the verification process rather than monolithically at the end. In contrast to existing model checking approaches that use intermediate verification results, IRS comprises additional requirements: an intermediate verification result proves safety under some scheduling constraints. These constraints must permit to fully use the program, i.e., no restrictions on the program inputs or the execution length may be applied. This paper provides a formal interface between IRS and a model checker that describes this requirement for finite executions. We leave the formalization of requirements for infinite (non-terminating) executions for future work.
Contributions. We provide a formal framework and algorithm for IRS that (1) states requirements for verification algorithms on their intermediate results and (2) enables a correct execution of a program provided with such an intermediate verification result, without introducing deadlocks. (3) We evaluate the effect of relaxing scheduling constraints on execution time overhead, based on an optimized scheduling implementation of IRS. Our results show that execution time overhead depends not only on the number of scheduling constraints but on their structure as well. After verifying only 1% of a program's Mazurkiewicz traces, execution time overhead of IRS can be reduced below 50%.

Overview
Iteratively relaxed scheduling (IRS) is an iterative verification approach for concurrent programs with non-deterministic scheduling, in contrast to the conventional, monolithic approach to program verification. This section reviews the basic IRS approach that we have previously presented [MSBS17]. Detailed definitions are provided in Section 3. The conventional approach to program verification can be described as follows: (1) Develop a program or update an existing program. (2) Verify the (updated) program. (3) Repeat steps (1)-(2) until the verification is successful. (4) The (updated) program can be safely used under a non-deterministic scheduler, i.e., with all feasible schedules. Since all feasible schedules have to be verified, the verification step may be slow or may even not terminate, in which case a different verification technique or tool would have to be tried or the program would have to be rewritten such that it is tractable by the used verification technique. In any of these cases, a large verification delay is introduced.
By constraining the scheduler and thereby reducing the number of feasible schedules, IRS tries to reduce the verification delay. A program can be safely used as soon as a sufficiently large initial set of safe schedules is found. An IRS execution environment ensures that only safe schedules are feasible. Safe schedules that are found later can be used to iteratively relax the scheduling constraints. In particular, the verification approach of IRS is: (1) Develop a program or update an existing program. (2) Start an iterative verification process which verifies in each iteration an individual schedule or a set of schedules.
(3) As soon as a sufficient subset of safe schedules is found, the program can be safely used inside an IRS execution environment. (4) New safe schedules that are found in subsequent iterations may relax the scheduling constraints during execution of the program.
The set of initially found safe schedules must enable a program execution without restricting functionality. Hence, for each possible input, a safe schedule must be available. Additionally, a specific use case may require additional initially safe schedules, for example to allow a practical enforcement of scheduling constraints.
Initial experiments have shown that constraining scheduling may introduces considerable execution time overhead [MSBS17]. Only if it is possible to reduce the execution time overhead by relaxing scheduling constraints, the overhead incurred by IRS can be adjusted: the more schedules are verified, the less overhead will occur. In this case, the sweet spot between a short verification delay and a small execution time overhead can be found by continuously testing the execution time overhead with the current set of schedules found to be safe. As soon as the execution time overhead is small enough (i.e., a "sufficient amount of non-determinism" is used), the program can be used and verification can be stopped (i.e., no more that the "necessary amount of non-determinism" is used).
If a program shows a sufficient set of schedules to use it without restricting functionality and additionally shows schedules that violate the specification, IRS can be used to nevertheless safely execute the program. The program may be fixed, in which case it may be possible to eventually remove all scheduling constraints, or it may be left unchanged and used only with scheduling constraints that guarantee safety.
Several conceivable use cases are given in [MSBS17], including (1) safely use programs that are not tractable by conventional verification, (2) safely use programs with bugs, (3) verify as many schedules as possible within a given time budget, and (4) verify as many schedules as necessary for a given budget of execution time performance.
An IRS execution environment may be realized inside an application program or by modifying the operating system. For example, in the former case, the program may be instrumented so that a thread waits before memory accesses that are not yet permitted to occur, according to the scheduling constraints.
Even if the scheduler of the operating system is non-deterministic, the scheduling constraints are enforced. In the latter case, it is conceivable to directly constraint the scheduler of the operating system to obtain an IRS execution environment and enforce schedules. Unlike previous approaches to deterministically execute concurrent programs (e.g., [LCB11,CSL + 13,CWG + 11]), IRS provides a novel approach to constraint scheduling independent from program inputs. This independence makes it compatible with program verification. However, only such verification techniques are suitable for IRS that yield meaningful intermediate verification results. Meaningful intermediate verification results either show a counter example for program correctness or guarantee correctness under some feasible scheduling constraints. No additional constraints should be necessary such as constraints about program inputs or execution length, as a program may not be fully operational under such constraints. In particular, a correct schedule has to be known for each possible program input, even if inputs are given interactively (during a program execution).
Intermediate verification results of this form have previously not been proposed, to the best of our knowledge. Nevertheless, some existing verification approaches show similarities or potential to be applied in the framework of IRS. Forward search-based, symbolic model checking, such as the Impact algorithm for concurrent programs by Wachter, Kroening, and Ouaknine [WKO13], seems to be suitable to generate intermediate verification results for IRS, by using a depth-first strategy. This strategy might use heuristics that prioritize executions according to their number of context switches, as it is done in context bounding analyses, e.g., by Qadeer and Rehof [QR05] or in iterative context bounding by Musuvathi and Qadeer [MQ07]. Furthermore, verification in IRS can partition the state space of a program into disjoint sets of schedules and verify each partition individually. A similar approach has been followed for bug finding by Nguyen et al. [NSF + 17]. Conditional model checking by Beyer et al. [BHKW12] could be used in the framework of IRS if conditions passed between verification runs encode suitable intermediate results.
Mazurkiewicz traces are equivalence classes on program executions and are used in the context of partial order reduction (POR) [GKW + 15,WKO13,FG05, GFYS07, AAJS14] to identify executions that can be skipped during verification. In order to formalize suitable intermediate verification results, IRS uses an extended notion of Mazurkiewicz traces, called symbolic traces. Based on symbolic traces, we formalize the requirements on a verifier for IRS in the following section.
As in the related field of DMT, additional synchronization is necessary to enforce scheduling constraints. Our experiments confirm that constraining scheduling introduces a considerable execution time overhead, in extreme cases a 44 times slowdown. A main concern for the praticality of IRS is to limit this overhead depending on the requirements of a use case. We try to design IRS with a low overhead by addressing several aspects: the amount of additional synchronization for schedule enforcement, storage and look-up of scheduling constraints, and the effect of relaxing constraints on the execution time overhead.
Section 3 addresses the former aspects: reducing the amount of additional synchronization is achieved by permitting threads to execute as long as possible without interruption. For an efficient encoding scheduling constraints, we introduce trace prefixes, based on symbolic traces. Section 5 investigates the latter aspect of execution time overhead due to scheduling constraints.

The IRS Algorithm
An IRS algorithm consists of a verifier and an execution environment, which run concurrently. The verifier continuously verifies schedules and reports sets of safe schedules to the execution environment. In order to guarantee program executions without functional restrictions, submitted sets of safe schedules must represent feasible schedules for all program inputs. This restriction for suitable intermediate verification results are formalized below as symbolic traces. A symbolic trace permits at least one schedule for each possible program input. A symbolic trace that is reported by the verifier to the execution environment is called an admissible trace. The execution environment maintains scheduling constraints, which are updated for each submitted admissible trace.
When implementing IRS, it is desirable to efficiently maintain and enforce scheduling constraints in order to incur as little overhead as feasible over conventional program execution. This section presents a detailed IRS algorithm and discusses its efficiency with respect to: • Storing scheduling constraints • Looking up scheduling constraints • Synchronization between threads for the enforcement of scheduling constraints The general IRS algorithm [MSBS17] maintains a set of admissible traces and controls the scheduling of a given program such that at any time, the current partial execution adheres to some admissible trace. As more and more schedules or symbolic traces are proven to be correct, they are added to the set of admissible traces. This representation of scheduling constraints has an exponential space requirement and it seems impractical to store all symbolic traces for large programs. Similarly, when permission for an event is checked, the look-up time is exponential if no further structure is given to the set of admissible traces. Unfoldings have been applied for model checking both Petri nets [McM92] and concurrent programs [KSH12,RSSK15,SRDK17]. By unfoldings, it is possible to represent all executions of a concurrent program in a single data structure, which is more space-efficient than storing a set of all symbolic traces since each event occurs only once in an unfolding. Looking up an event in an unfolding is faster than searching in an unstructured set of symbolic traces, as well. However, the size of an unfolding can still grow quickly (exponentially in the worst case) with an increasing number of threads [KSH14]. The space efficiency of verification based on a depth-first search is lost. Hence, unfoldings are not directly suitable to store scheduling constraints for practical programs. In order to implement IRS, we address the problem of space complexity by using trace prefixes. If all admissible Mazurkiewicz traces or executions are stored in order to express scheduling constraints, so that each time a new execution has been verified and is permitted, more space is required. In contrast, trace prefixes can be used as scheduling constraints such that when new executions are permitted, constraints may be removed and less space is required. However, the use of trace prefixes requires the verifier to explore symbolic traces in a depth-first manner. More freedom can be given to the verifier by extending trace prefixes to partial unfoldings, at the price of a higher space requirement. Additionally, an interesting question, however left for future work, is how to generalize scheduling constraints for non-terminating programs, for example by representing scheduling constraints via cyclic graphs or automatons.
Our tests of several IRS implementations confirmed that as expected, interthread synchronization incurs a major part of execution time overhead of IRS over unconstrained scheduling. In order to reduce the execution time overhead caused by synchronization between threads, it is crucial to omit such synchronization in case an event needs not to be scheduled after an event from an other thread. The IRS algorithm presented in this section achieves this by executing several events without intermediate synchronization, as is detailed below. Besides reducing the amount of inter-thread synchronization, execution time overhead can be considerably reduced by reducing the duration of a single synchronization, for example by using lock-free synchronization instead of locks. We discuss this matter in Section 4.
In the following, we state our system model and present the IRS algorithm, proving correctness and progress of the algorithm.

System Model
We model a (concurrent) program P is as a transition system (S, S init , Σ, →) where S is a set of states, S init ⊆ S is a set of initial states (program intputs), Σ is a finite set of threads, and →⊆ (S × Σ) S is an acyclic transition relation. We require that for a given state and thread, there is at most one successor state, i.e., scheduling is the only source of non-determinism. We write s 1 An execution of P is an initial state and a sequence of events (s 0 , u) ∈ S init × (Σ × N) * , where u = e 1 . . . e n , such that the following holds. (1) There exist states and transitions such that s 0 t1 − → s 1 · · · tn − → s n and (2) each event e i = (t i , k) contains thread t i and counts occurrences of t i in u before position i: k = |{e j : j < i ∧ e j = (t i , _)}|. We denote the thread t of an event e = (t, k) by tid (e). We write s 0 u − → s n if execution (s 0 , u) leads to state s n . An execution (s 0 , u) is complete, written ⇓ (s0,u) , if it leads to a terminal state and otherwise is partial. The set of all executions of P is denoted by executions(P ).
We assume that a dependency relation is given for every program P that gives rise to a Mazurkiewicz equivalence relation on executions [Maz86,AAJS14] via a happens-before relation between events. We extend the notion of Mazurkiewicz traces by symbolic traces, defined below. The happens-before relation of one or more executions is represented by a symbolic trace graph as a triple o = • C o is a set of path constraints (state predicates, e.g., collected during model checking), and is a partial order labeled with path constraints, which expresses a happens-before relation.
As an auxiliary function, we introduce remove(e, o), which removes event e from symbolic trace graph o. Formally, remove(e, An execution (s 0 , u) adheres to the happens-before relation of a symbolic trace • ∀(e, c, e ) ∈→ o . e = e 1 ⇒ s 0 c and • (s 1 , e 2 . . . e n ) remove(e 1 , o).

If u additionally contains exactly the events of
Based on symbolic trace graphs and their correspondence to happens-before relations of executions, we define (symbolic) traces, as a generalization of Mazurkiewicz traces. Intuitively, a symbolic trace contains scheduling information for all possible program inputs and represents all executions of a program with matching scheduling.
A trace prefix o is a trace, except that we do not require executions to be complete: ∀s 0 ∈ S init . ∃u. (s 0 , u) ∈ executions(P ) ∧ (s 0 , u) o.  Figure 1, is given in Figure 2. The program consists of two threads, T 1 and T 2 . Each thread is given a pointer as input and increments the value at the pointer's target, mistakenly without synchronization. Thread T 1 asserts that the target of x indeed holds the intended value. In case the pointers x and y point to different memory locations, the threads do not interfere with each other and the assertion holds. Otherwise, dependent accesses occur and the assertion does not hold under every possible ordering of events. The symbolic trace in Figure 2 ensures that the assertion holds in all executions that adhere to the trace. Nodes correspond to events and are labeled with the corresponding memory access for clarity. Edges between events of the same thread represent the thread's program order; edges between events of different threads represent scheduling constraints. Since dependencies between T 1 and T 2 occur only if the pointer targets match, x==y, the scheduling constraints are labeled with this condition.

Algorithm
The general IRS algorithm [MSBS17] requires a synchronization between individual threads and the IRS execution environment after each event in order to check compliance of the current execution with a previously verified trace. Additionally, it stores all current admissible traces explicitly, which increases space requirements and look-up times as the verification advances. With Algorithm 1, we present an IRS algorithm that can be efficiently implemented. It addresses both previously described issues by the use of trace prefixes as scheduling constraints and allowing threads to run uninterrupted for multiple memory events whenever scheduling constraints do not require synchronization.
In order to simplify the presentation, it is assumed that the IRS execution environment enforces sequential consistency independently from scheduling constraints. For platforms where this incurs a considerable slowdown, scheduling of events of the same thread can be relaxed by considering intra-thread scheduling constraints.
Do Not Synchronize Already Reversed Races. By using trace prefixes as scheduling constraints, it is possible to avoid synchronization before events when every possible continuation of the current execution is proven to be errorfree. The corresponding part in an admissible trace does not have to be enforced and scheduling constraints can be removed.
Instead of managing a set of admissible traces, Algorithm 1 uses a single trace as the current admissible trace prefix. Every event that occurs in this prefix has to be executed according to its partial order, however every additional event may be executed without synchronization. Once the verifier has collected enough information about correct executions of the program, the admissible trace prefix is updated. In order to prevent unnecessary assumptions on the verifier, we do not require the use of a specific data structure such as a state graph. Instead, we only require that the verifier maintains an internal state G that contains information on safe parts of the state space.
Definition 2. Given a program P and a state predicate error _free() (induced by the property to be verified), a verifier maintains an internal state G and provides predicates safe G () and finished G such that ∀s. safe G (s) ⇒ ∀u. ∀s . s u − → s ⇒ error _free(s ) and finished G holds when verification has finished.
In other words, a correct verifier guarantees safety for all (partial) executions from a state s whenever safe G (s) holds. We use a derived definition for safety of trace prefixes o that guarantees safety for all executions satisfying o: ). An implementation of the verifier may, for example, use an abstract reachability tree [WKO13] to realize G.
The current admissible trace prefix o adm is updated by shortening it, i.e., by removing constraints at the end of its happens-before order. Formally, a new admissible trace prefix o is required to satisfy o < o adm , which is defined as: On a more abstract level, the verifier finds an initial, complete, and correct trace o of the program and generates a sequence o > o 1 > . . . > o n of subsequent trace prefixes such that for all 1 ≤ i ≤ n, safe G (o i ).
A verifier can update a trace prefix o as follows. Each edge (e 1 , e 2 ) with tid (e 1 ) = tid (e 2 ) in o is interpreted as a scheduling constraint that requires e 2 to be executed after e 1 . Updates of trace prefixes remove scheduling constraints. Let o be o with e 1 , e 2 , and all their successors (w.r.t. the happens-before relation) removed. It is safe to remove the scheduling constraint (e 1 , e 2 ) if all states s that are reachable by a linearization of o are safe, i.e., safe G (s). Depending on the verification approach used, it may be more efficient to delay the removal of (e 1 , e 2 ) until it occurs at an end of o, w.r.t. the happens-before relation, i.e., no event happens after e 2 that has an incoming or outgoing edge with an event from an other thread.
In the worst case, even if scheduling constraint (e 1 , e 2 ) is at the end of a trace prefix, the verifier has to prove safety for exponentially many states before (e 1 , e 2 ) can be safely removed. On the one hand, this complexity is a general limitation of IRS. On the other hand, the duty of the verifier can be reduced exponentially by adding only one scheduling constraint, which may reduce the verification delay considerably.
Do Not Preempt Minimal Events. In addition to the use of trace prefixes, Algorithm 1 omits synchronization before events that do not have to occur second in a race, i.e., events that do not have a predecessor in o adm from a different thread, i.e., events {e ∈ o : ∀e ∈ o. e c − → o e ⇒ tid (e ) = tid (e)}. The execution environment of Algorithm 1 reduces the number of synchronizations by permitting a sequence of events, potentially from multiple threads, between two synchronizations. This sequence is chosen from the set free(s 0 , u, o) as a continuation of the current execution (s 0 , u) that adheres to o or contains only synchronization-free events. In Algorithm 1, verifier and execution environment are executed concurrently. The execution environment can be executed several times during a single run of the verifier.

Correctness and Progress
An IRS algorithm is correct if only safe executions, i.e., executions that do not violate the safety specification, can occur under its execution environment. The following theorem provides correctness of Algorithm 1. In addition to correctness, an important requirement is that a program is never completely blocked by scheduling constraints (provided that at least one correct execution exists). The following progress theorem guarantees that this cannot happen with Algorithm 1.
Theorem 2 (Progress). Whenever an execution (s 0 , u) has been executed by Algorithm 1 with verified state graph G and admissible trace prefix o adm , either the program has terminated or free(s 0 , u, o adm ) is not empty.
Proof. Assume that the program has not terminated. Let o adm be the initial admissible trace prefix and let o adm be the current admissible trace prefix. Case

Implementation
We have implemented Algorithm 1 from Section 3 in our IRS prototype [MSBS17]. This prototype handles C and C++ programs translated to LLVM-IR. The LLVM-IR code is instrumented via the LLVM compiler infrastructure [ZZZa] in order to enforce an admissible trace prefix whenever the program is executed. The IRS execution environment is realized completely inside the instrumented application program and does not depend on any modifications of the operating system or assumptions on the used scheduler. Via a standard dependency analysis the prototype identifies all dependent memory accesses, which are memory accesses that ether directly access global memory or may influence the result of an other global memory access. Scheduling constraints are enforced by callbacks directly before each dependent memory access that check whether this memory access is currently permitted. Callbacks directly after each dependent memory access communicate to other threads that the memory access has been performed. Memory fences inside these callbacks ensure sequential consistency, as assumed by our presentation in Section 3.2. Before each instrumented memory access, a thread checks whether an event of an other thread has to occur before its own upcoming event via a look-up in a global vector clock. Busy waiting is performed until the current thread is permitted to continue. After the memory access, the callback signals that the memory access is completed by updating the global vector clock. In contrast to earlier versions of our prototype, no thread is added to the program.
When testing several alternatives of implementing schedule enforcement, we observed that, as expected, lock-based implementations of waiting for other threads' events is much slower than busy waiting. A disadvantage of busy waiting is CPU consumption during waiting, which can reduce performance when more threads are active than hardware cores are available. We expect that improvements over our current, simple scheme of busy-waiting for permissions can be made by the use of a more advanced combination of busy waiting with lockbased synchronization or scheduler interaction (e.g., the POSIX sched_yield() system call). Additionally, we tested an implementation that uses a loadable kernel module to communicate with the Linux scheduler. Whenever an event is not yet permitted to be executed, the corresponding task's state is set to TASK_WAIT and only restored once the event is permitted. This design circumvents the additional CPU consumption of busy waiting. However, additional overhead appears because the current program counter of each thread has to be communicated to the loadable kernel module. In our tests, this design showed only an advantage if most events were constrained, i.e., the likelihood that an event has to wait is high.

Experimental Evaluation
Enforcing scheduling constraints in order to disable schedules outside of a given admissible trace is likely to incur execution time overhead (here: simply over-  head ) in comparison to plain program executions (without IRS). A crucial factor for the applicability of IRS in practice is how scheduling constraints in IRS influence this overhead, which we evaluate on several benchmark programs. The main goal of this evaluation is to investigate whether, for a given admissible trace and induced scheduling constraints, relaxing those constraints reduces the overhead and, if this is the case, how fast. Additionally, we investigate whether the selection of the initial and following admissible traces, i.e., the structure of the admissible trace prefix, influences the overhead.
Setup. All experiments have been conducted with our IRS implementation described in Section 4. The hardware used is an Intel Core i5-6500 CPU at 3.20GHz with four cores running Linux 4.8.0. Each benchmark is run with and without instrumentation by our prototype. The instrumented version is run in several configurations, with a decreasing amount of scheduling constraints. The initial number of scheduling constraints and the number of scheduling constraints that can be removed in one step, and thereby the number of configurations per benchmark, vary as the number of conflicting memory accesses varies among benchmarks. Each configuration is run 1000 times. We report the median execution time and overhead relative to the unmodified benchmark. Benchmark set 1. The first set of benchmarks are concurrent programs from the SV-COMP benchmark suite [ZZZb] and the POR literature (Shared Pointer, [GFYS07]). We chose these benchmarks because they are well-studied verification problems and contain a high amount of concurrent interaction, which is expected to highlight performance issues of IRS. All benchmarks contain two threads. The corresponding results are shown in Fig. 3. For these benchmarks, IRS produces a maximum overhead of 22%, which is much less than we expected and might be already an acceptable overhead for certain applications. For all benchmarks, the overhead is reduced by relaxing scheduling constraints, albeit in some cases, a significant reduction occurs only at the last reduction step. In some cases, the overhead is negative, i.e., the instrumented version of a benchmark executed faster than the plain benchmark. We conjecture that both measurement noise as well as improved timing of cache operations due to a different interleaving of memory operations may be relevant for this effect, as already noted by Olszewski et al. [OAA09]. Similarly, an increased overhead after removing scheduling constraints could be caused in such a way. Overall, both the initial overhead and the amount of reductions are lower than we expected.
Benchmark set 2. Since we expected a higher overhead, we conduct the same experiment on two benchmarks from the POR literature (Indexer [FG05] with 15 threads and Last Zero [AAJS14] with 16 threads), where we expect a higher overhead as a larger amount of threads and dependencies result in a higher amount of scheduling constraints. Fig. 4 shows the corresponding results. Indeed, for the Indexer and Last Zero benchmarks, the overhead is much higher. Interestingly, the overhead for Indexer abruptly decreases from 1904% to 61% at the transition from 3 to 2 scheduling constraints. We explain this observation by the fact that the permitted trace prefix with 3 scheduling constraints requires 3 threads to wait, while after removing 1 scheduling constraint, only 2 threads have to wait. Since our implementation uses busy waiting, many concurrently waiting threads may prevent threads that are not required to wait from quickly proceeding.
Structure of scheduling constraints. An interesting question is whether the overhead can be reduced by choosing a different trace prefix with roughly the same amount of scheduling constraints. Interestingly, we have found optimized traces for both Indexer and Last Zero that indeed show a drastically reduced overhead with the same or even more scheduling constraints. The corresponding results are depicted as Indexer-Opt and Last Zero-Opt in Fig. 4. For Indexer, we found that choosing a trace prefix that requires less threads to wait can be executed faster. Fig. 5 shows two alternative traces for Indexer. Nodes represent events and edges a happens-before relation. The nodes of even-indexed threads are shown in gray and events of the same thread are arranged vertically one below the other. Fig. 5a shows one of the slower trace prefixes, where many threads wait rarely, and Fig. 5b shows one of the faster (optimized) trace prefixes, where few threads wait often. For the former trace prefix, 16 Mazurkiewicz traces, for the latter trace prefix, only 8 Mazurkiewicz traces have to be verified. Although more scheduling constraints are enforced, the program execution is faster with the latter trace prefix. While we optimize trace prefixes manually, it is conceivable that verifiers can prioritize faster trace prefixes automatically, e.g., by applying a heuristic or by testing few traces and comparing their overhead. Such a prioritization resembles the effects of ordering heuristics on the performance of POR algorithms studied by Lauterburg et al. [LKMA10]. For Last Zero, our original trace prefixes require the second event of a worker thread to wait for the first event of the next worker thread. By letting threads wait already before their first events, the program execution is drastically accelerated already for 100% scheduling constraints, i.e., when only a single Mazurkiewicz trace is verified.
Summary. Our results show that relaxing scheduling constraints can reduce the overhead for all benchmarks. For example, after verifying only 8 of 4096 Mazurkiewicz traces of Indexer, the overhead is reduced from 2841% to 48%. However, in other cases, the execution time may not decrease considerably until a large part of all scheduling constraints have been removed. In yet other cases, the overhead is reduced considerably by removing a single scheduling constraint, while it does not change considerably before and after this step. Besides the number of scheduling constraints, the choice of the permissible trace prefix, i.e.,  the structure of the induced scheduling constraints, may have a large influence on the overhead. These observations suggest that a sensible selection of an initial trace during verification can considerably improve the execution time performance of a program that is executed with IRS. Comparing our current results for Indexer and Last Zero to earlier experiments with a less optimized schedule enforcement [MSBS17], we see a considerable speed-up when optimized trace prefixes are used.

Related Work
Deterministic multi-threading (DMT) [BAD + 10, CSL + 13, CWG + 11, LCB11, OAA09, AWHF10] limit the amount of non-determinism due to scheduling for multi-threaded programs. Dthreads by Liu et al. [LCB11] adapts the interface of the multi-threading library Pthreads and guarantees, for any given input, a deterministic execution. Dthreads interleaves parallel phases (in which threads write only to a local copy of the shared memory) and sequential phases (in which the local copies are merged). Dthreads cannot handle programs that bypass the Pthreads library by synchronizing directly over shared memory [LCB11].
Cui et al. propose Peregrine [CWG + 11], which initially records a set of executions and enforces schedules of these initial executions during subsequent executions where these schedules are compatible. Schedules may be incompatible if an input is seen that leads to a different schedule. In the subsequently presented Parrot framework [CSL + 13], Cui et al. propose to combine DMT with a model checker for bug-finding. Parts of a program that are manually marked as performance-critical are executed non-deterministically and model checked to increase the confidence about their correctness. Only the remaining parts of the program are executed deterministically, so that the overhead of additional synchronization is reduced.
In contrast to IRS, the above described DMT approaches do not provide any guarantees about which schedule is enforced, for a particular input. Using these approaches to simplify program verification is therefore impractical if many program inputs need to be covered. While we conjecture that some of the former techniques can be extended to communicate a general scheduling policy that guides a verifier, it is not directly clear how to do so. In contrast, IRS provides a formal interface that uses admissible traces to communicate scheduling constraints. Additionally, the above described DMT approaches do not allow to relax scheduling constraints during runtime, in contrast to IRS, which enables to iteratively relax scheduling constraints and, provided that the program is eventually proven safe, remove all scheduling constraints. On the implementation level, the approaches of [OAA09,LCB11,CSL + 13] (but not [BAD + 10,CWG + 11]) synchronize only at library calls (such as uses of Pthreads locks), which improves execution time performance but may result in non-determinstic executions when global memory is accessed (perhaps accidentally) directly, e.g., without lock protection. In contrast, our IRS implementation schedules all accesses to shared variables.
Program analyses that use context bounding [QR05] consider only those executions of a program which contain only up to k context switches between threads, for a typically small bound k. While reachability for concurrent, recursive programs is undecidable [Ram00], additionally bounding the number of context switches makes the problem decidable [QR05]. Context bounding may be used within IRS, although it is only a special case of scheduling constraints in IRS. Similar to context bounding, a generally undecidable model checking problem may become decidable when handled with IRS: by only checking a limited set of symbolic traces, IRS enables to safely use a program even if its reachability problem is undecidable under unconstrained scheduling.
When applied with bounded model checking (BMC) for concurrency bug finding [RG05,CF11,MQ07,LR09,ITF + 14], context bounding focuses the search for erroneous schedules to those with few context switches. Consequently, potential bugs are missed that manifest themselves only after more context switches than the current bound. However, based on empirical results, Musuvathi and Qadeer argue that a low context bound is sufficient to find many interesting bugs [MQ07]. They propose iterative context bounding (ICB) as an extension to BMC: a program is iteratively checked with an increasing context bound, similar to increasing the bound on execution lengths in BMC. Given limited resources (that usually do not allow to search the complete state space of a program), ICB prioritizes schedules with few context switches. This search strategy of ICB could be used by a model checker in conjunction with IRS. However, in contrast to bug finding based on BMC, IRS requires a sound program analysis (under scheduling constraints), i.e., a safety proof for complete, unbounded program executions, which is not given, in general, by BMC. Another difference between context bounding in bug finding and IRS are guarantees about scheduling: when searching for erroneous schedules, bug finding may use assumptions about the likelihood of schedules in order to guide the search. However, any assumptions about the likelihood of schedules are not enforced. Bug finding consequently accepts to miss feasible executions of a program that contain, e.g., a bug that has not been found under context bounding. In contrast, IRS guarantees that only checked executions may occur.
Nguyen et al.
[NSF + 17] transform a concurrent program into several in-stances that show only a reduced number of schedules. Each instance is checked individually by BMC (and with a context bound). Similar to IRS, this decreases the complexity of the model checking problem and improves bug finding. However, their approach of dividing a program into instances is based on lazy sequentialization for BMC [FIP13] and therefore not directly usable for verification. Conditional model checking [BHKW12] is a general framework to reuse (in general arbitrary) intermediate verification results. In contrast to IRS, it does not require intermediate verification results to prove safety of a fully functional program variant and does not enforce the preconditions of the intermediate result.
Partial order reduction (POR) [GKW + 15,WKO13,FG05,GFYS07,AAJS14] identifies equivalent executions in order to verify a sufficiently large subset. It is orthogonal to IRS and can be used in conjunction, as we demonstrate via symbolic traces. IRS differs from other verification techniques that handle thread scheduling explicitly in ensuring a safe program execution as soon as a single symbolic trace is found.
In addition to scheduling, a source of non-determinism are relaxed memory models in modern architectures. In [BM08], a memory monitoring approach is proposed to make sure that sequential consistency is maintained during the execution of a program. Fang et al. [FLM03] present an automated memory fence insertion technique to enforce SC using instrumentation at the source code level. In both cases, the program can be safely verified under the assumption that SC holds with a reduced state space. Similarly to IRS, these approaches restrict the amount of non-determinism. However, in contrast to IRS, they are not able to dynamically adapt the amount of non-determinism and are restricted to non-determinism due to relaxed memory access. Slightly related, synchronization synthesis, for example presented by Gupta et al. [GHR + 15], automatically inserts locks and other synchronization primitives that are more powerful than fences in that also scheduler-related non-determinism can be eliminated. However, this technique may introduce deadlocks into a program [GHR + 15], hence it is unsuitable for IRS, where we have to rely on the fact that a verified schedule does not limit the program's functionality.

Conclusion
Iteratively Relaxed Scheduling enables to adjust both the amount of schedulerrelated non-determinism and the size of the relevant part of a program's state space to be verified. This paper discusses issues of how to efficiently implement IRS in terms of execution time overhead, i.e., how to efficiently encode and enforce scheduling constraints. Furthermore, we formalize the requirements on verifiers for IRS. Support for non-terminating programs is left for future work.
Our experimental results show that iteratively relaxing scheduling constraints can reduce execution time overhead. Thereby, we give evidence that IRS indeed allows to adjust both the verification delay and the incurred execution time overhead in order to find a sweet spot. Interestingly, we found cases in which a much earlier reduction of execution time overhead is obtained by choosing favorable scheduling constraints, which suggests that execution time performance does not simply rely on the number of scheduling constraints but to a large extend also on their structure.