Legio: Fault Resiliency for Embarrassingly Parallel MPI Applications

Due to the increasing size of HPC machines, the fault presence is becoming an eventuality that applications must face. Natively, MPI provides no support for the execution past the detection of a fault, and this is becoming more and more constraining. With the introduction of ULFM (User Level Fault Mitigation library), it has been provided with a possible way to overtake a fault during the application execution at the cost of code modifications. ULFM is intrusive in the application and requires also a deep understanding of its recovery procedures. In this paper we propose Legio, a framework that lowers the complexity of introducing resiliency in an embarrassingly parallel MPI application. By hiding ULFM behind the MPI calls, the library is capable to expose resiliency features to the application in a transparent manner thus removing any integration effort. Upon fault, the failed nodes are discarded and the execution continues only with the non-failed ones. A hierarchical implementation of the solution has been also proposed to reduce the overhead of the repair process when scaling towards a large number of nodes. We evaluated our solutions on the Marconi100 cluster at CINECA, showing that the overhead introduced by the library is negligible and it does not limit the scalability properties of MPI. Moreover, we also integrated the solution in real-world applications to further prove its robustness by injecting faults.


I. INTRODUCTION
T HE high demands of computational science applications are leading the evolution of the current high-performance systems. This increased the complexity of HPC systems to satisfy the need for more performance. As a result, the computation capabilities are growing and will reach the exascale performances (10 18 FLOPS) in the next years [1], [2]. This evolution is introducing new challenges in the field since problems that were overlooked before are now limiting the performance of the systems. Among these problems, there is system reliability.
Modern HPC architectures are featuring millions of cores and components, and the probability that at least one of them is the victim of a fault rises with these numbers. The mean time between failures of current systems is measured in days [3], and probably in the future systems will be measured in minutes [4]. With this high frequency of faults, the MTBF of the system can be lower than the application run-time. This implies that applications must feature some sort of reliability management to reach the end of the execution. Without any explicit management, an application would have to be restarted several times up to when it is capable to reach the end of the computation without any problem. Most applications based on MPI [5], R. Rocco, D. Gadioli and G. Palermo are with the Dipartimento di Elettronica, Informazione e Bioingegneria (DEIB), Politecnico di Milano, Milan, 20133 Italy the de-facto standard for intra-process communication, lack reliability management since the standard assumes that the application executes in a controlled environment, where all the system components work properly. This problem has been solved mainly by leveraging Checkpoint-and-Restart (C/R) techniques, but with the reduction of the MTBF new solutions are needed, because the time needed for the checkpoint can easily exceed the MTBF value [6].
To avoid relying purely on C/R, during the years many publications developed several MPI implementations featuring reliability methodologies, such as MPICH-V [7], rMPI [8], or FT-MPI [9]. These efforts try to introduce reliability methodologies directly in MPI, creating new functionalities in the existing standard. While remarkable, they received only limited support and did not solve entirely and efficiently the problem. The last effort among those is the User-Level Fault Mitigation (ULFM) [10] library: it's a collection of functions that allow the user to repair and continue its MPI execution. This work is receiving a lot of attention, mainly due to the focus on the integration in the MPI standard: the next version of MPI (4.0) will focus on reliability, and ULFM is one of the candidates to be introduced in the standard.
Various efforts (such as Fenix [11], CPPC [12], LFLR [13]) have been developed on top of ULFM. This comes from the fact that ULFM by itself does not specify a way to recover the execution, it just provides methods for handling the fault and repair the involved structures. These frameworks couple ULFM with a method to restore the execution (typically C/R based) and create an all-in-one tool improving the reliability of an MPI application.
While these frameworks enhanced the reliability of an MPI application, their usage is not transparent and the application code has to be adapted accordingly. This solution is acceptable when designing a new application, but becomes problematic when targeting an already developed one.
This aspect is limiting the impact of those frameworks and led us towards the development of a solution that does not need changes in the application code. In this work, we limit our attention to embarrassingly parallel MPI application, a very common and scalable type of parallel program that reduces to the minimum the interactions between the processes. Embarrassingly parallel application are also envisioned to be among the first ones capable to fully exploit an exascale system. Typically, they use MPI I/O to maximize the data transfer between computation nodes and file system, while avoiding as much as possible explicit synchronization between them.
In this paper we present Legio 1 , a framework that introduces fault resiliency in embarrassingly parallel MPI applications. It shares many aspects with the previous frameworks, such as the usage of ULFM, but focuses more on the transparency of the integration. Since embarrassingly parallel applications can continue their execution even if some processes do not provide any result, we opted for fault resiliency. Upon noticing an error, the failed processes are discarded and the execution continues only with the non-failed ones. This approach is also faster compared to the standard C/R proposed in the other frameworks, but impacts the correctness of the application result: an acceptable trade-off for applications producing an approximate result, like for example Monte Carlo solvers [14], or high-throughput in-silico virtual screening applications [15].
Legio supports most used MPI calls in embarrassingly parallel applications together with one-sided communication and file support, features not yet included in ULFM. We also provide an alternative solution, capable of constructing a networking layer transparent to the application to reduce the impact of a fault to a few processes. We evaluate Legio on the Marconi100 cluster at CINECA [16] to measure the introduced overhead. Those analyses demonstrated that the proposed framework introduces fault resiliency with only a very limited impact on the performance of the application.
To summarize, the contributions of this paper are the following: • We propose the Legio framework able to transparently introduce fault resiliency in embarrassingly parallel applications; • We implemented an alternative organization of MPI communicators to improve scalability; • We experimentally evaluate the overheads and performance impact of the proposed solutions considering both the single MPI calls and full applications; The remainder of the paper is organized as follows. Section II analyzes the previous works that tried to solve the problem and introduces some definitions and knowledge useful for the following sections. Section III covers the initial exploration of the ULFM behaviour in presence of faults. Section IV exposes the design process of the Legio framework. Section V analyzes the hierarchical alternative of the framework. Section VI goes through the experimental evaluation of our work by showing the overhead at the MPI call and applicationlevel. Section VII discuses some potential improvements of the produced implementations. Lastly, Section VIII concludes the paper.

II. BACKGROUND AND RELATED WORK
ULFM [10] can be listed among one of the most relevant efforts in the field. It specifies a set of functions to enable fault tolerance in MPI applications. The main ULFM features that we use in our approach are the following: (a) the possibility to set a communicator as out of order (revoked), (b) the possibility to remove failed processes from a communicator and obtaining a working one, (c) the possibility to agree on a result even in presence of faults, and (d) the possibility to identify failed processes.
Many frameworks have been built on top of ULFM functionalities by adding different recovery strategies. In particular, the integration of a C/R framework with ULFM provides an all-in-one framework to manage the insurgence of faults in a generic MPI application [11]- [13], [17], [18]. These solutions opted for the recovery of a consistent state: by loading a previous checkpoint, the execution restarts from a valid point. They usually provide a simple interface to the user but require changes in the application code. While obtaining a similar result to our proposed solutions, these frameworks do not pursue transparency and, rather than opting for fault resiliency, they recreate the failed processes. These characteristics provide the possibility to create a more flexible solution, working with any MPI application, at the cost of application intrusiveness and performance penalty.
A completely different perspective is the one presented when applying algorithm-based fault tolerance [19], which exploits the possibility to re-compute the data of a failed process using the information of the others. This solution is very application-specific since it leverages data redundancy to implement a resilient method with reduced overhead. Examples are shown in the context of matrix-multiplication and LU factorization kernels, but cannot be taken into consideration for a generic MPI program. In particular, ABFT should not be exploitable in embarrassingly parallel applications, like the one we are targeting with Legio, due to the high data independence across the processes.
A method tackling transient fault has been presented in SLIM (session layer intermediary) [20]. The solution reduces the impact of transient faults by repeating the operations. Despite SLIM works for any MPI application, it cannot be considered a valid solution in case of permanent faults.
An effort that shares many concepts with the approach we are proposing has been presented in [14]. It uses the functionalities introduced by ULFM to manage the presence of faults in a Monte Carlo application, a typical embarrassingly parallel MPI application. The authors implemented the resiliency by removing the faulty processes from the execution and continuing only with the non-failed ones. The concept behind this solution is similar to the one proposed in this paper. However, it has been achieved by directly modifying the application code since the focus of the authors was on a specific application. With Legio, we are proposing to generalize this approach by implementing a transparent framework capable to tackle all the embarrassingly parallel applications.

III. PRELIMINARY ANALYSES
In this section, we will discuss some issues of the ULFM implementation of the MPI standard in presence of faults [18], [21]. Before proceeding with the analysis, we want to provide some definitions of key terms for the remaining part of the paper: • A process notices a fault when it receives the error code MPIX_ERR_PROC_FAILED after an MPI call; • A faulty communicator is a communicator in which at least a participating process is failed, but no process noticed it yet; • A failed communicator is a communicator in which (at least) a participating process noticed the presence of a fault; Using these definitions, we sum up our considerations on the MPI standard in points to better refer to them in the next sections. P.1 Some MPI functions work in faulty and failed communicators. Some remarkable functions that expose this behaviour are MPI_Comm_rank and MPI_Comm_size, but also many operations that deal with MPI_Groups. These operations are labelled as local in the MPI standard and do not require communication to complete successfully. P.2 Point-to-point communication works in a faulty communicator, as long as the processes involved in it are not failed. They do not work in a failed communicator. P.3 Collective communications will not work in a failed communicator but may partially work in a faulty communicator. This behaviour comes from the fact that only some of the processes may notice the fault, while the others can complete without problems. In particular, the MPI_Bcast operation exposes this behaviour, unlike MPI_Reduce, MPI_Barrier, and MPI_AllReduce. This behaviour will be called the "Broadcast Notification Problem" (BNP) from now on. P.4 File and remote memory access operations are not supported by ULFM and are likely to fail in a faulty environment (rather than raising an error, they throw a segmentation fault making the execution impossible to recover). P.5 Communicator management functions like MPI_Comm_dup or MPI_Comm_split will not work in a faulty communicator. This includes also all the Inter-communicator related ones. These points are used in the next Sections to justify some of the choices done while designing the proposed framework.

IV. THE LEGIO FRAMEWORK DESIGN AND ARCHITECTURE
The basic idea behind the Legio framework is that it has to provide fault resiliency functionalities in embarrassing parallel applications without code intrusiveness. The proposed solution consists of the substitution of the MPI structures used (and created) by the application with others managed by Legio. This way, when a fault happens, it affects only the Legio structures, making the repair process easier and controllable by the framework. The MPI structures that are involved in the Legio repair process are communicators, windows, and files.
To achieve our purpose, we designed a library that behaves like an intermediary between the application and the MPI implementation. To achieve that position we exploit the profiling interface provided by the MPI standard (PMPI), which allows us to intercept every MPI call made in the parallel program. Originally thought for profiling, it can be used to inject code of different types around the target MPI call. In our work, we used PMPI to introduce fault resiliency using ad-hoc code and ULFM methods.
The structure substitution introduces many problems that must be addressed, all referring to the possible differences between the original and the substitute. For what concerns communicator substitution, the ranks of the processes may raise some problems: the application is expecting its rank not to change during the execution, but we may have to change the communicator due to faults and, as a consequence, ranks. Our solution must be able to transparently map ranks from the original structure to the substitute one. Therefore, when a failed process is involved in the communication, either by being the root of a collective call or by participating in a pointto-point operation, there are two possible courses of action. We can ignore the failure, for example when the failed process was gathering data from the others, or we can stop the application execution, for example when the failed process is spreading important data. The choice is done at compile-time and we provided ways to the user to configure this behaviour to better fit the application.
The presence of a fault is checked after the execution of the operation with the substitute structures: if it is confirmed, then the structures must be repaired and the operation must be repeated. Since ULFM supports communicator repair only if all the processes participate in the procedure, the error checking routine is not performed in non-collective calls. The error checking routine suffers from the BNP (property P.3): to avoid the problem we perform an agreement operation that combines the results obtained by all the processes into a single one equal for all.
While communicators management is enough to support many MPI functions, there are many more that do not base on them. All the operations referred to in property P.1 are left unchanged, while others need some additional structures. File operations and one-sided communication ones, in particular, leverage other structures not yet supported by ULFM so any fault may cause the program to behave indefinitely (property P.4). Any operation that uses one of these structures must be sure of the absence of faults because we cannot repair those structures and the execution would stop. The solution adopted up to now faces the problem of having to ensure that the substitute structure is fault-free before executing the operation. To achieve this requirement, we added a call to a barrier operation before the actual function: this way the eventual presence of a fault will be recognised by the barrier and it will be possible to proceed with the repair.
These solutions allow us to support most of the MPI calls, but are not sufficient for some others: common functions like the gather and scatter operations rely on the value of the rank to provide correct behaviour, and simply running them on a substitute communicator would produce a wrong result. We decided to implement those functions as a combination of others that do not suffer from the same problem.
By following these concepts, we managed to create an implementation of our library that features support for many MPI operations 2 . This solution is transparent: the application needs no strict code change to support the library because it is integrated only in the linking phase. However, the application developers must be aware that an MPI operation may be skipped, due to the rank translation problem. Therefore, they must perform all the operations required to avoid undefined behaviour, such as buffer initialization. We evaluated our solution to measure the overhead it introduces and its ability to handle faults: we will present the results in a later section.

V. THE HIERARCHICAL EXTENSION
The ULFM standard requires that all the repair procedures involve all the processes, limiting the development of local recovery solutions where each process could repair itself independently [11], [18]. This is a well-known issue, analyzed by the same authors, that leads to worse than linear scaling when we increase the number of nodes involved in the computation. Given the modern trend to increase the experiment size, the impact of this limit increases as well.
To solve this issue, we propose an alternative and novel solution that avoids the MPIX_Comm_shrink usage on the entire communicator. In particular, we developed a hierarchical approach. At first, we split the target communicator into a set of disjoint sub-communicators (local comms). Then, we create a new communicator (global comm) that contains one process (named master) per sub-communicator. The master process of a sub-communicator is the one with the lowest rank. Figure 1 shows the topology of the hierarchical approach. This solution has some major properties: (a) the number of communicators created scales linearly with the number of processes; (b) each process can reach anyone else in the network (if not directly, via forwarding), and (c) there is only one path from a process to another one that crosses the minimum amount of nodes. The new communicator resembles a star topology, avoiding any communication across different local comms outside the global comm. On the main hand, this feature reduces the impact of a fault: only the processes directly communicating with the failed one will have to participate in the recovery, while the others can continue their execution seamlessly. On the other hand, it complicates the repair procedure which depends on the role of the process.
When the faulty node is not a master, then the repair procedure is bounded within the local comm. Otherwise, the framework needs to assign the master role to a new process and include it in the global comm. In particular, every time the user creates a communicator (of size s), Legio creates local comms of max size k. The framework assigns each process to a local comm according to its rank r i.e. a process will be assigned to the i-th local comm (local comm i) if i = r/k. Moreover, we define local comm (i+1) as the successor of local comm (i), while we define local comm (i-1) as its predecessor. We consider the last local comm the predecessor of the first local comm. The assignment of a process to a local comm is final.
Due to property P.5, when Legio manipulates a communicator, it must be fault-free. Therefore, the framework needs to create additional communicators to complete the repair procedure, named POVs (short for Partially OVerlapped). Each POV includes all the processes of a local comm and the master of the successor. Thus, Legio creates a POV for each local comm. Legio uses these communicators only for the repairing procedure. Figure 2 highlights two POV communicators in the example depicted in Figure 1. Figure 3 summarizes the required steps when we repair a failure on a master. The failure is noticed only by the processes in its local comm and by the ones in the global comm. However, the failed process belongs to four different communicators and all of them must exclude the failed process to proceed. The local comm, its POV, and the global comm can shrink to exclude the failed master process. However, the master of the predecessor needs to notify the processes in its POV before shrinking, since they were unable to notice it directly. In this phase of the repair procedure, the processes in the local comm of the failed master can communicate with the other processes only by using their POV through the master of the successor. Legio uses this connection to include the new master node, i.e. the process with lower rank among the ones in the local comm of the failed master, to the global comm. Then, it can use the global comm to update also the predecessor POV.
Even if this procedure is composed of several steps, it reduces the cost of the repair operations because it lowers its complexity. If we refer to S(x) as the computational cost of the shrinking operation over x processes, we can define the shrink complexity as follows: Fig. 3. Overview of the repair procedure when a master fails. The communicators and processes follows the notation rules of the previous images. The red cross highlights the failed node. The exclamation marks highlight the nodes that notice the failure. The arrows that originate from a process represent the inclusion of the process in a communicator. The arrow color represents the target communicator. The arrow border color represents the communicator used to perform the operation. The slim black arrow represents the propagation of the failure notification.
(1) where s is the size of the entire communicator and we assume for simplicity that it is multiple of the maximum size of the local comms k. For the master fault case, the three terms refer to the shrinking of the local comm (S(k)), the two POVs (2S(k + 1)), and the global comm (S(s/k)). The complexity depends on the role of the process, as described previously, and on the value s. When s increases, the complexity of the hierarchical approach improves with respect to S(s), i.e. shrinking the entire communicator. In particular, there might be a minimum value of s such that the hierarchical approach will be less expensive than the normal one (for some value of k). Formally: To answer this question we need the complexity of S. Even if we do not have a formal definition, the authors of Fenix [11], [18] have empirically estimated a more than linear complexity. Under the assumption that all the processes have an equal probability of failure, Equation 3 and Equation 4 provide the relationship between the communicator size and the value of k that minimizes the overall repair complexity for the linear and quadratic case respectively. The actual relationship lies between these two bounds. Fig. 4. The propagation steps in one-to-all and all-to-one operations. In both cases the root process is the one with rank 2.
Even if we consider the linear case when s > 11 the hierarchical approach has a lower complexity. However, the split nature of the network introduces communication overheads since not all the processes are directly connected. This forced us to rethink the way each operation is performed, eventually splitting the execution across the smaller communicators. In particular, we divided the supported operations in various classes, that share the same data movement characteristics: • One-to-one operations are the simplest ones since they involve only two processes. Following property P.2 and the fact that they do not need the error-checking part, we decided to run them on the entire communicator. • One-to-all operations (like MPI_Bcast) involve all the processes and may cause repair. The data must go from a process to all the others, needing some sort of propagation. To execute the operation, we run it on the different parts in sequence: firstly in the local comm of the root, then in the global comm, and lastly in all the other local comms in parallel. Figure 4 shows the direction of the information within the network. • All-to-one operations (like MPI_Reduce) are similar to one-to-all but the data travels in the opposite direction. We followed the same propagation plan as in one-to-all but in reverse order, as shown in Figure 4. • All-to-all operations (like MPI_Allreduce) move data from and to all the processes within the network. We decided to represent them as a combination of an all-toone and a one-to-all operation executed sequentially. • Comm-creator operations generate new communicators.
We cannot execute the operation on a local comm or global comm since there is the need for a unique communicator. These operations are executed on the entire communicator and may cause inefficient repairs. Nonetheless, the trade-off may be acceptable since their frequency is usually lower than the other operations. • File operations do not involve data movement between processes directly: we can use this property to make each process execute the operation on their local comm without the need for any propagation mechanism. • Local only operations are executed by a process on its structures: no data movement is needed, so it is possible to execute the operation on the local comm as done in file operations. We decided not to support the one-sided communication functions since their implementation in a fragmented network as the one used in this hierarchical approach is not trivial.
The implementation of this solution exposes to the user two knobs: the maximum size of the local comms and a threshold value for using the hierarchical communicator. Since this solution is an alternative to shrinking the entire communicator, we evaluated both solutions in the experimental campaign.

VI. EXPERIMENTAL EVALUATION
To prove the validity of our solutions, we conducted some experiments using different benchmarks. The purpose of these experiments was to quantify and evaluate the impact of the Legio library usage on various applications. We conducted these experiments on the Marconi100 cluster at CINECA, featuring nodes with 2 x IBM POWER9 AC922 16 cores 3.1 GHz processors and 256 GB of RAM. In all the experiments done we adopted an MPI configuration featuring 32 processes per node, 1 process per physical core. The Legio library has been configured considering the maximum size of the local comms set to the closest optimal value following the relation obtained with the linear complexity hypothesis (Equation 3).
The experiments can be divided into two groups, different for their purpose and the information they produce: the first ones involve the per-operation measurement of the overhead introduced, while the second group consists of more general applications in which we will analyze the overall impact of the library. For the first group, we used mpiBench [22] to measure the overhead of the library when increasing the communication load and we used an ad-hoc code to evaluate the same parameters when increasing the network size.
The experiments involving mpiBench were run on a 32 processes network and we analyzed the time needed to complete broadcast and reduce operations under increasing message sizes. The mpiBench application will repeat the calls 1000 times for each message size and for each of the three versions: at first, we linked the initial Legio implementation, then the hierarchical solution, and lastly we just compiled the application with ULFM without additional libraries. Figures 5  and 6 show the average values of the execution times for each call.
It is possible to see how the three values share similar behaviours in terms of growths: this implies that our solutions do not damage the scalability of the MPI library with the increase of the message size.
The experiments involving the ad-hoc code have a different structure: we time each call and we compare it with the same call without the use of any Legio feature. Each call is repeated 100 times, to reduce the impact of measurement noise. Figures 7, 8, and 9 show the results obtained. We also evaluated the cost of the repair procedure by injecting a fault and completing an operation. Figure 10 shows the results of this latter analysis: from that, it's possible to see that the nonlinearity of the shrink theorized by [18] is not present in our tests. Despite this fact, the average time to repair on a 256 core machine is lower in the hierarchical case, since the probability for a master node to fail are contained (1/8). Using the ad-hoc code we checked also the overhead for file operations: those are more influenced by the load of the file-system rather than other aspects, so we omit those results for simplicity.
The second group contains experiments run on two embarrassingly parallel applications. The first application is part of   two molecules. In this context, we have a target molecule and a database of smaller molecules that we need to evaluate to find the most promising ones. We use the "C" size workload to run the NAS application, and the measurements refer to the successive execution of 40 runs. We use a database with 113K molecules to test the docking application. We ran both of them in various configurations in terms of the number of MPI processes and MPI implementation. In particular, we use 32, 64, 128, and 256 processes and choose between one of our implementations or only ULFM. We repeat experiments in each configuration 10 times, extracting all the execution times. The results of these executions can be seen in Figures 11 and 12: it is easy to see that the overhead is negligible and the usage of Legio does not impact heavily the execution times.
Those experiments validate our approach since they respect The current implementation of Legio relies on the fact that the MPI application can produce useful results even if a failed process can be removed from the full set. In several embarrassing parallel applications, this is true, but there is a fraction of them that does not fulfill this hypothesis. In this direction, we already evaluated the possibility to introduce a C/R feature in the library thus obtaining the possibility to recover failed processes transparently.
As discussed in Section II, many other efforts combined C/R frameworks with ULFM ( [11]- [13], [17], [18]). However, none of them focus towards the transparency. All these efforts base on application-level C/R frameworks which allow the application to explicitly specify what should be saved and when to do so during the check-pointing phase. An alternative to application-level C/R frameworks are those working at system-level. System-Level C/R frameworks implement a transparent approach at the cost of a large overhead for both check-pointing (all the system status has to be saved) and restart phase.
Legio has in transparency one of its key features, thus forcing us towards system-level C/R frameworks. However, considering the type of application we are targeting, the characteristic that we want to take out from a C/R framework is not to restart the entire application, but only the failed processes. The possibility to restart only a part of the network is not a common feature in system-level C/R frameworks. Usually, these frameworks are designed to consider the absence of fault mitigation mechanisms inside the application, so they assume that in case of fault all the processes must be restarted. Moreover, they tend not to split the checkpoint information of the various processes because they would lose significance without all the others. The restart part may also lead to problems: without knowing the details about the application, it may be difficult to load a system-level checkpoint on a process created by the application.
However, among all the efforts produced in literature, recently we found in MANA [24] a support in that direction. It provides system-level checkpointing (no application intrusiveness), the possibility to migrate processes (implying the division of the data per process), and flexibility on MPI versions upon restart. Our idea is to exploit the per-process data checkpointing offered by MANA to actually restore only the failed process. While everything seems ready for the integration, MANA is still designed for global recovery and the steps towards local recovery are part of our on-going work.

VIII. CONCLUSION
This paper presents Legio, a framework designed to offer resiliency to embarrassing parallel MPI applications. The work makes the absence of intrusiveness in the target application one of the key elements. Indeed, the library makes use of the PMPI interface to wrap the MPI call and to implement all the required actions to manage failed processes. ULFM has been used as a base for the implementation of Legio.
In the paper, an extension towards a hierarchical implementation has been done to reduce the overhead of the repair process in case of a large number of nodes involved. Within the document, also a theoretical analysis of when to apply the hierarchical version has been discussed.
The experimental evaluations considering both per-MPI-call and application-level evaluations demonstrate the efficiency of the implemented framework, proving how the solution can be used in embarrassingly parallel applications without affecting the overall performance.
Overall, the problem of dealing with faults in an MPI application is still complex and needs additional efforts. The proposed solution is very specific both in the target application and the recovery policy (fault resiliency), and it does not apply to a generic MPI application. Nonetheless, embarrassingly parallel applications are intrinsically scalable and are compatible with the future exascale architectures, and in those systems, fault tolerance will be even more important.