<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[:••: dotclusters]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://dotclusters.io/</link><image><url>https://dotclusters.io/favicon.png</url><title>:••: dotclusters</title><link>https://dotclusters.io/</link></image><generator>Ghost 5.33</generator><lastBuildDate>Sat, 25 Apr 2026 00:33:49 GMT</lastBuildDate><atom:link href="https://dotclusters.io/blog/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Understanding Paxos Consensus]]></title><description><![CDATA[<p>In distributed systems, it is often essential to make sure that all nodes in a cluster share the same information about the system&#x2019;s state. We can use commitment protocols (e.g. 2PC, 3PC) to synchronize nodes, although reliance on a centralized unit of control makes this approach susceptible</p>]]></description><link>https://dotclusters.io/paxos/</link><guid isPermaLink="false">643d7aeeaec01d04abdcc614</guid><dc:creator><![CDATA[Robert Sander]]></dc:creator><pubDate>Fri, 18 Feb 2022 16:59:00 GMT</pubDate><content:encoded><![CDATA[<p>In distributed systems, it is often essential to make sure that all nodes in a cluster share the same information about the system&#x2019;s state. We can use commitment protocols (e.g. 2PC, 3PC) to synchronize nodes, although reliance on a centralized unit of control makes this approach susceptible to failures. Moreover, commits can stall indefinitely when nodes become unresponsive. Paxos allows any node to act as the transaction coordinator. It can achieve progress even if nodes fail and messages get lost. The algorithm uses the Synod consensus at its core, with <code>acceptors</code>, <code>proposers</code> and <code>learners</code> communicating with each other. Below, we will take an incremental approach to build-up the complete machinery of the algorithm.</p><h4 id="synod-algorithm">Synod Algorithm</h4><p>The Synod algorithm provides the core consensus mechanism in Paxos. It uses a voting-based procedure to ensure consistent application of changes to the state of the system. The proposer node submits change requests, which are committed only if a majority of acceptors agree to apply them. Once accepted, all nodes should be able to see the change. The voting procedure must enforce a set of restrictions because nodes and networks are susceptible to arbitrary failures. To illustrate the constraints imposed by the Synod algorithm, let us consider a scenario with a cluster of 6 nodes, where node <code>A</code> acts as a proposer and nodes <code>B-F</code> function as acceptors.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_system-4.svg" class="kg-image" alt loading="lazy" width="551" height="361"></figure><h5 id="r1-unique-identifiers">R1 | Unique Identifiers</h5><p>The proposer can send a value to a set of acceptors, which can accept the submitted change. Once a large enough set of acceptors agrees on the proposed value, the system will update its state. Previous commits might be overwritten in this procedure, leading us to the first requirement imposed by the algorithm:</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><strong>R1</strong> | Each proposal must have a unique identifier.</div></div><p>Using <code>(sequence_id, node_id)</code> tuples provides a distinct identifier for each proposed value. If two node submit a proposal with the same <code>sequence_id</code>, then we can order them based on the <code>node_id</code>:</p><p>(13, Adam) &lt; (14, Benny) &lt; (14, Susan)</p><p>An alternative approach is to use slotted timestamps, with each node using its own pre-allocated range.</p><h5 id="r2-quorums-must-overlap">R2 | Quorums Must Overlap</h5><p>To explain the second rule enforced by the Synod algorithm, let us consider a proposal that needs a quorum of 2 votes to pass. The proposed value is committed if, for example, nodes <code>B</code> and <code>C</code> accept the proposal issued by <code>A</code>, even if nodes <code>D</code>, <code>E</code>, <code>F</code> are temporarily unavailable. Now, if nodes <code>A</code>, <code>B</code>, <code>C</code> suddenly fail, and <code>D</code>, <code>E</code>, <code>F</code> become available; it is possible that <code>D</code>, <code>E</code>, <code>F</code> never learn about the changes committed previously.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_rule2_problem-15.svg" class="kg-image" alt loading="lazy" width="752" height="251"></figure><p>In order to prevent such scenarios, we must make sure that there is an overlap between nodes participating in any two voting procedures.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><strong>R2</strong> | The quorums of any two votes must have at least one node in common.</div></div><p>In the example above, information can propagate if we require that at least one node from the initial vote is available during the second ballot:</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_rule2_solution.svg" class="kg-image" alt loading="lazy" width="751" height="251"></figure><p>We always satisfy the requirement imposed by rule <code>R2</code>, if we require quorums to be formed by majorities only. Two majorities reach consensus at some point due to overlap</p><h5 id="r3-choice-is-permanent">R3 | Choice is Permanent</h5><p>With constraints <code>R1</code> and <code>R2</code> in place, we can order changes to the system&#x2019;s state, and make sure that information can spread between nodes. However, because information might spread at arbitrary rates, there is one more issue to consider. Let us suppose that node <code>A</code> has proposed a change <code>x=53</code>, which was accepted by a quorum of <code>C</code>, <code>D</code>, <code>E</code>, <code>F</code>. Now, assume that responses from acceptors get delayed, and proposer <code>B</code> issues another proposal <code>x=1</code> in the meantime. If nodes <code>C</code>,<code>D</code>, <code>E</code>, <code>F</code> all accept &#xA0;<code>B</code>&apos;s change, the value committed in the system might have already changed when <code>A</code> receives the acceptance corresponding to its vote.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_rule3_problem-1.svg" class="kg-image" alt loading="lazy" width="751" height="202"></figure><p>Therefore, to make the system converge into a unified state, we must impose one more requirement:</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><strong>R3</strong> | If a proposal with value <code>v</code> is chosen, then every higher numbered proposal issued by any proposer has value <code>v</code>.</div></div><p>Because of rule <code>R2</code>, if a value was committed before, there will always be at least one node with that value in the current quorum. Considering the order requirement from rule <code>R1</code>, we can rephrase <code>R3</code>:</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text"><strong>R3</strong> | For any <code>v</code> and <code>n</code>, if a proposal with value <code>v</code> and number <code>n</code> is issued, then there is a set <code>S</code> consisting of a majority of acceptors such:<br>&#x2003;- no acceptor in <code>S</code> accepted any proposal numbered less than <code>n</code>, OR<br>&#x2003;- <code>V</code> is the value of the highest-numbered proposal among all proposals numbered less than <code>n</code>, accepted by an acceptor in <code>S</code>.</div></div><p>Applying constraint <code>R3</code> to our example, we can see the system converging into a consistent state:</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_rule3_solution-2.svg" class="kg-image" alt loading="lazy" width="751" height="291"></figure><p>Once a value is committed, the proposer must stick with it in future ballots. This is how consensus on a value <u>propagates</u> to other nodes, and no inconsistencies can arise.</p><!--kg-card-begin: markdown--><h5 id="proposer-algorithm">Proposer Algorithm</h5>
<p>Considering constraints <code>R1</code>-<code>R3</code> of the synod algorithm, we can derive a description of the proposer node, with its operation divided into two  stages:</p>
<ul>
<li>
<p><strong>Prepare Phase</strong>  - a proposer chooses a new proposal number <code>n &gt; lastBallot</code>, updates <code>lastBallot=n</code>, and sends a request <code>Prepare(n)</code> to some set of acceptors, asking to respond with <code>LastVoted(n&apos;, v, promise)</code> containing:</p>
<ul>
<li>
<p><code>n&apos;</code> - the proposal with the highest number less than <code>n</code> that each acceptor accepted, if any.</p>
</li>
<li>
<p><code>v</code> - the value corresponding to proposal <code>n&apos;</code>.</p>
</li>
<li>
<p><code>promise</code> - a promise not to accept a proposal numbered less than <code>n</code>. This makes sure that <code>n&apos;</code> does not become invalid, between the time when the proposer gets the <code>LastVoted()</code>, and the time it issues a proposal to the acceptor.</p>
</li>
</ul>
<p>If the proposer cannot get the required responses, it will time-out and can retry with another identifier.</p>
</li>
<li>
<p><strong>Accept Phase</strong> - if the proposer receives the requested responses from a majority of the acceptors during the prepare phase, then it can issue a proposal with number <code>n</code> and value <code>v</code>, where:</p>
<ul>
<li><code>v</code> is the value of the highest-numbered proposal among the responses <u>OR</u></li>
<li><code>v</code> is any value selected by the proposer if the responders reported no proposals</li>
</ul>
<p>The proposer writes the proposal into memory [important for failure recovery], and sends out a <code>Accept(n, v)</code> to all acceptors. When the proposer receives a majority of <code>Voted(n)</code> messages concerning a particular proposal, it records <code>v</code> in its memory. If the proposer times out while waiting for the <code>Voted(n)</code> messages, it can retry by issuing a proposal with a new identifier.</p>
</li>
</ul>
<h5 id="acceptor-algorithm">Acceptor Algorithm</h5>
<p>The acceptor can receive the <code>Prepare(n)</code> and <code>Accept(n, v)</code> requests from the proposer, and is free to respond or ignore any of them without affecting consistency:</p>
<ul>
<li><strong>Prepare Phase</strong> - the acceptor can receive <code>Prepare(n)</code>  with a sequence number <code>n</code> which can fall in one of two ranges:
<ul>
<li>If <code>n</code>  is greater than that of any <code>Accept()</code> it has already voted for [<code>n &gt; lastAccept</code>], the acceptor updates <code>lastPrepare = n</code> and  responds with  <code>LastVoted(n&apos;, v, promise)</code> which includes:
<ul>
<li><code>n&apos;</code> - the highest-numbered proposal it accepted <code>n&apos; = lastAccept</code>, or <code>null</code></li>
<li><code>v</code> - the value corresponding to <code>n&apos;</code></li>
<li><code>promise</code> - a promise not to accept any requests  <code>&lt; n </code></li>
</ul>
</li>
<li>If <code>n</code> is smaller than <code>lastAccept</code> on the acceptor, than it should ignore the <code>Prepare()</code> request since it won&apos;t vote for a corresponding <code>Accept()</code> request anyways. To improve performance, it can inform the proposer about its state, such that the proposer can abandon the proposal early on.</li>
</ul>
</li>
<li><strong>Accept Phase</strong> - the acceptor can accept a proposal numbered <code>n</code> if it has not responded to a <code>Prepare()</code> with a higher identifier in the meantime. This can be ensured if the condition  <code>n == lastPrepare</code> is true. If it decides to accept, it records the vote in its memory, updates <code>lastAccepted = n</code>, and sends a <code>Voted(n)</code> message to the proposer and all learners.</li>
</ul>
<!--kg-card-end: markdown--><h5 id="learner-algorithm">Learner Algorithm</h5><p>After acceptors decide to vote for a proposal, they additionally send a <code>Voted(n)</code> message to all learner nodes. Learners know the number of acceptors in a system, such that they can update their state depending on the number of votes. Due to message loss, there might be cases where learners do not discover a committed value. They can prompt the proposer for a proposal to guarantee that a value was committed in these cases.</p><blockquote><strong>Note</strong><br>Issuing proposals for uncommitted value, commits the value if successful.<br><br>Issuing new proposals for an already committed value does not affect the state - consensus is always on value, not on the proposal id.</blockquote><h5 id="complete-system">Complete System</h5><p>Until now, we have discussed constraints <code>R1</code>-<code>R3</code> and the function of <code>proposers</code>, <code>acceptors</code> and <code>learners</code>. As a next step, let us look at an example illustrating operation of the Synod consensus, involving proposers <code>A</code>, <code>B</code>, acceptors <code>C</code>, <code>D</code>, <code>E</code>, and a learner <code>F</code>.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_complete_system-1.svg" class="kg-image" alt loading="lazy" width="751" height="331"></figure><ol><li>Node <code>A</code> proposes a value of <code>x=7</code>, which times-out because it is accepted only by <code>C</code>, with acceptor <code>D</code> down, and <code>E</code> unreachable.</li><li><code>B</code> proposes a value of <code>x=55</code>, but it also times-out since only acceptor <code>E</code> is available.</li><li>Proposer <code>A</code> learns from acceptors <code>C</code> and <code>E</code> that the latest value any of them voted for is <code>x=55</code>, which becomes the only value that <code>A</code> can propose now [ see <code>R3</code>]. A proposal for <code>x=55</code> is issued by <code>A</code>, and is accepted by both <code>C</code> and <code>E</code>. This is picked-up by the learner, which can update its internal state.</li><li>Proposer <code>B</code> learns that acceptor <code>D</code>, which just became available, has not voted for anything yet. This does not have much influence on the behavior of the system, since <code>C</code> and <code>E</code> already voted for <code>x=55</code>. Therefore, <code>B</code> can only issue a proposal for <code>x=55</code>, which is accepted by all nodes.</li></ol><blockquote>A Paxos node can take on multiple roles, acting as <code>proposer</code>, <code>learner</code> and/or <code>acceptor</code> all at once.</blockquote><h5 id="consistency">Consistency</h5><p>Message loss cannot corrupt the state of the system, since it can only prevent an action from happening. Receiving multiple copies of a message can cause an action to be repeated. &#xA0;This also has no effect on the consistency, as sending several <code>Voted(n)</code> messages has the same effect as sending just one. The only way for consistency to be affected is if a proposer has to resend the same change under new ballots because of some failure on its side. However, the proposer prevents this issue by storing the information about <code>lastBallot</code> to memory, so it can recover to its original state.</p><h5 id="progress">Progress</h5><p>The algorithm discussed up to this point ensures consistency of the system&#x2019;s state. However, we can construct a scenario where two proposers repeatedly send proposals with increasing identifiers. None of those requests is ever chosen, because acceptors will drop any proposal with identifiers lower than the last one received [see <code>R3</code>].</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_progress.svg" class="kg-image" alt loading="lazy" width="764" height="341"></figure><p>To guarantee progress, we need to ensure that contention cannot occur. One potential solution is to designate a distinguished node as the only proposer in the system. If the distinguished proposer can communicate with most of the acceptors, it will eventually be able to issue a proposal with an identifier high enough to be accepted. To pinpoint which node should act as the proposer, a leader election algorithm can be used. In systems where multiple proposers are needed, we can limit contention using back-off techniques.</p><h4 id="from-synod-to-paxos">From Synod to Paxos</h4><p>A single run of the Synod algorithm aims to reach consensus on a single value <code>v</code>. Once nodes agree on a certain proposal, the system cannot progress to another value. Paxos generalizes that approach to an arbitrary number of arguments by implementing a sequence of separate instances of the Synod algorithm for each value <code>v</code><sub>k</sub>. To illustrate the operation of the full <code>Paxos</code> algorithm, we start with a system in the following state:</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_system_full-1.svg" class="kg-image" alt loading="lazy" width="871" height="421"></figure><blockquote><strong>Note</strong><br>The entry <code>Ek</code> is not the same as the identifier <code>IDk</code>.<br>&#x2003;- <code>Ek</code> corresponds to the k&apos;th change applied to the state of the system<br>&#x2003;- <code>Vk</code> / <code>IDk</code> are the latest value and id corresponding to the execution of <code>Ek</code>&apos;s synod consensus </blockquote><p>Let&apos;s suppose node <code>A</code> issues proposals for entries <code>E32</code>, <code>E33</code>, <code>E34</code>, and <code>E35</code> without awaiting them to complete. Because of several failures, it might happen that <code>E32</code> and <code>E35</code> reach consensus, while <code>E33</code> and <code>E34</code> time out.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_system_full_timing-7.svg" class="kg-image" alt loading="lazy" width="551" height="361"></figure><p>Now, let us imagine that the node <code>A</code> fails and node <code>B</code> is elected as the new proposer. In a distributed state machine, the operation related to the state at entry <code>Ek+1</code> might depend on all previous entries. We must therefore make sure that all entries up to <code>Ek</code> reached consensus before the proposer can move on to process <code>Ek+1</code>. Therefore, <code>B</code> must synchronize its state up to the last entry, which was seen by the system. To do so, it finds the first entry for which it does not know the status, i.e. <code>E32</code>. To determine the state of the whole system, <code>B</code> executes the prepare phase of the Synod algorithm for all uncertain entries from <code>E32</code> onwards. Based on the information it receives from acceptors, node <code>B</code> concludes that:</p><ul><li>Entry <code>E32</code> was successfully committed, such that it must be introduced into <code>B</code>&apos;s ledger.</li><li>For entries <code>E33</code> and <code>E34</code> there is no value committed in the system. Because there are committed entries after <code>E34</code>, node <code>B</code> identifies <code>E33</code> and <code>E34</code> as <u>gaps</u> and fills in a dummy value into those positions.</li><li>Entry <code>E35</code> was successfully committed and is already available in <code>B</code>&apos;s memory.</li><li>No values were committed for entries from <code>E36</code> onwards, which is where <code>B</code> can start processing new requests.</li></ul><p>After <code>B</code> has determined the state of the system, it executes the accept phase for entries <code>E32</code>-<code>E35</code>. This brings the system into the following state:</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/paxos_system_full_timing_final.svg" class="kg-image" alt loading="lazy" width="552" height="362"></figure><p>From this point onward, proposer <code>B</code> can issue proposals by executing the accept phase of the Synod algorithm beginning at <code>E36</code>. Since it is the only proposer in the system, it can be sure that execution of the prepare phase is redundant at this stage.</p><blockquote><strong>Optimization</strong><br>A new proposer must query acceptors about the status of all unknown entries. To improve the performance of the system, we could implement a dedicated command for this task. If acceptors can report the state of a range of entries at a time, we reduce the number of needed queries.</blockquote><h5 id="addingremoving-nodes">Adding/Removing Nodes</h5><p>When a node joins a cluster, it can initialize its state based on a state dump fetched from centralized storage. It becomes a learner afterwards, synchronizing its state similarly to a newly elected proposer. Removing nodes is trivial and can be seen as node failure.</p><hr><p><em>[1] Lamport, Leslie. &#x201C;The part-time parliament.&#x201D; ACM Trans. Comput. Syst. 16 (1998): 133-169.</em><br><em>[2] Lamport, Leslie. &#x201C;Paxos Made Simple.&#x201D; (2001).</em></p>]]></content:encoded></item><item><title><![CDATA[A Survey on Common MPSoC Simulators]]></title><description><![CDATA[<p>The increasing complexity of computer architectures can rarely be modeled in an analytical way. Therefore, computer simulation becomes the only viable tool too support design-space exploration, trade-off analysis and performance-forecast during the design process. Such simulations can be very time-consuming, running for weeks or even months to complete. With the</p>]]></description><link>https://dotclusters.io/a-survey-on-common-mpsoc-simulators/</link><guid isPermaLink="false">643ec597aec01d04abdcc63b</guid><dc:creator><![CDATA[Robert Sander]]></dc:creator><pubDate>Mon, 02 Mar 2020 16:33:00 GMT</pubDate><content:encoded><![CDATA[<p>The increasing complexity of computer architectures can rarely be modeled in an analytical way. Therefore, computer simulation becomes the only viable tool too support design-space exploration, trade-off analysis and performance-forecast during the design process. Such simulations can be very time-consuming, running for weeks or even months to complete. With the introduction of multi-core/many-core systems the situation only got worse: a rising complexity of the simulated target did not go in hand with the performance of the host where the process was executed. In order to reduce the time required to perform an accurate and detailed simulation, several approaches were developed over the years. </p><h4 id="simulator-classification">Simulator Classification</h4><p>On the highest level, we can classify simulators based on their scope, level of detail and input type. Looking at the classification based on <strong><u>scope</u></strong> first, two subgroups can be listed:</p><ul><li><strong>Full-System Simulators </strong>can boot a complete operating system. They support interrupts, IOs, privileged modes and peripheral components. This yields a very detailed representation of the whole software-stack used in modern computers. The provided level of detail does not come without cost however. Full-system simulators are often slow and require device-timing models and large disk-images. </li><li><strong>Application-Level Simulators </strong>are much simpler and more lightweight compared to full-system ones. They are faster, because workloads are run directly on the simulator without an operating-system in between. If a system-call is performed by an application running on such a tool, it is redirected to the underlying OS for handling. This makes application-level simulators not the best choice for workloads that perform many system-calls during their execution. </li></ul><!--kg-card-begin: markdown--><p>The second classification is based on the level of detail obtained by different platforms. We can enumerate 3 major groups here:</p>
<ul>
<li><strong>Functional Simulators</strong> model capabilities of target architectures, and have an emulator-like behavior. They don&#x2019;t focus on all micro-architectural details, and do not keep track of the timing for individual operations. Functional simulators trade-off the low level of detail for high simulation speeds.</li>
<li><strong>Timing Simulators</strong> analyze the whole microarchitecture of a processor in a very detailed manner. Timing, IPC, cache performance and transactions on the interconnect are reported to the user as a result. Depending on the strategy used by a given tool, three subtypes can be pointed out:
<ul>
<li><strong>Cycle-level</strong> simulators operate at the resolution of the clock cycle. Although very accurate, this type of simulation is extremely slow and requires lots of memory.</li>
<li><strong>Event-driven</strong> approaches are based on events instead of cycles. This makes it possible to avoid simulating periods where no actions are performed in the processor.</li>
<li><strong>Interval-based</strong> simulation employs a strategy where execution is broken down by miss-events in the instruction flow. A simulation of those events is performed first. After that, timing of the resulting intervals is obtained from specialized analytical models. A balance between accuracy and speed can be obtained in effect.</li>
</ul>
</li>
<li><strong>Timing-Functional Simulators</strong> integrate the previous approaches to improve on flexibility and accuracy simultaneously, by fully decoupling the timing and functional models. Code instrumentation with Dynamic Binary Translation (DBT) makes it possible to delegate most work on the functional part to the simulation host. The produced output is redirected to the simulation target, where it can interact with the timing model.</li>
</ul>
<!--kg-card-end: markdown--><p>The final categorization can be achieved based on the <strong><u>input method</u></strong>: </p><ul><li><strong>Trace-Driven Simulators</strong> make use of trace-files, which are streams of instructions pre-recorded during execution of a benchmark. Trace-files consume a lot of disk space and are unable to model speculative execution and runtime environment changes. Because of their static nature, results provided by trace-driven simulators are not accurate enough to be used during the analysis of parallel and timing-dependent applications. Simulators in this group are fast, which makes them a good fit for initial design-space exploration. </li><li><strong>Execution-Driven Simulators</strong> use executables, which are run on the simulation target directly. They don&#x2019;t require as much disk space as trace-driven simulators, but take a lot longer to terminate. They produce results with much higher accuracy, which makes them a good fit for most applications. </li></ul><h4 id="acceleration-techniques">Acceleration Techniques</h4><p>A rising gap between the performance of hosts executing the simulation and the complexity of the simulated targets could be observed over the years. Combined with the rising requirements imposed by benchmarks, a need for accelerated simulation emerged:</p><ul><li><strong>Sampled simulation</strong> is performed on a fraction of instructions being representative for the whole benchmark. Instructions are mainly selected by statistical or targeted sampling. During <u>statistical sampling</u>, parts of the benchmark are picked from the instruction stream at random. <u>Targeted sampling</u> employs an initial analysis, which has an influence on the selection process performed afterwards. The calculation of the architectural starting-state between samples is a major challenge of sampled simulations. If points of interest are far apart, then it can be computationally expensive to fast-forward between the associated states. </li><li><strong>Statistical simulation</strong> collects characteristics of the executed benchmarks at first. The obtained features are used to create instruction traces, which are needed for a subsequent simulation. Although synthetic traces are small in size, they are not accurate enough to make this approach relevant beyond design-space exploration. &#xA0;</li><li><strong>Parallel simulation</strong> &#xA0;takes advantage of modern multi-core architectures. It splits workloads into multiple threads, which can improve the processing speed significantly. One of the main challenges associated with parallel simulation is the synchronization of data-structures between jobs. Trading-off accuracy for speed, synchronization is often performed after multiple intervals. </li><li><strong>Fast-forwarding</strong> provides the ability to move the simulation states between calculated points-of-interest. Time can by saved by skipping the non-important parts of the simulated code.</li></ul><h3 id="mpsoc-simulators">MPSoC Simulators</h3><p>In the following, we take a closer look at six commonly used computer architecture simulators.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/Screenshot-from-2023-04-24-15-16-05-1.png" class="kg-image" alt loading="lazy" width="474" height="183"></figure><h5 id="a-gem5">A. Gem5 </h5><p>Gem5 is a modular full-system, application-level simulator with the ability to model multiple instruction sets: ARM, x86, MIPS, SPARC, ALPHA, PPC, RISC-V. It supports in-order, out-of-order pipelines and can be run on Linux, MacOSx, Solaris and OpenBSD. The tool can keep track of events on a cycle-to-cycle basis, which is exploited within the multiple CPU models offered by the platform. Gem5 is highly extendable and allows to specify custom coherence protocols and interconnection networks. It also supports the widest range of IO devices. </p><h5 id="b-marssx86">B. MARSSx86</h5><p>MARSSx86 is a cycle-level, full-system simulator. It supports in-order and out-of-order pipelines with detailed configurations. The x86 instruction-set is the only ISA supported by the platform. It includes models of single-core and multicore CPUs with detailed configurations for caches and interconnect. In addition, multi-threaded workloads can be used with the tool as well. Similarly to other platforms presented in this paper, MARSSx86 can use fast-forwarding to accelerate simulation.</p><h5 id="c-graphite-sniper">C. Graphite / Sniper</h5><p>Graphite is an application-level, parallel simulator, which can distribute workloads to clusters of servers. It uses integrated timing-functional simulation with timing and functional models decoupled using DBT. The tool supports simulations with hundreds of cores and provides the infrastructure on top of which Sniper was built. The major improvement added to Sniper compared to its predecessor is the notion of interval-based simulation, out-of-order pipelines and support for multilevel, shared cache hierarchies with first-level write-back. It also can work with RISC-V targets, in addition to the x86 support already found in Graphite. Due to the communication overhead added by the shared cache, Sniper is usually slower than its predecessor.</p><h5 id="d-multi2sim">D. Multi2Sim</h5><p>Multi2Sim is an application-level simulator with support for x86, ARM, AMD Evergreen, Nvidia Fermi and MIPS32 instruction-sets. The simulator integrates a functional-block and a timing-based module. The functional part is used to ensure correctness of execution paths taken in the instruction flow. The timing module is based on analytical models which drive the execution. Multi2Sim can be used to model out-of-order cores, but has no support for IO pipelines. CPU-GPU simulations are the main target of this platform.</p><h5 id="e-zsim">E. ZSim</h5><p>ZSim is an application-level, timing-functional simulator with support for the x86 ISA. Its focus are fast simulations of heterogenous, many-core systems with up to 1000 cores. Architectures are simulated using a two-phase parallelisation algorithm that can scale simulation significantly, without much overhead or loss of precision. Dynamic Binary Translation ensures that most work on the timing model is done once, before execution is started. A lightweight virtualization layer provided by the simulator enables the execution of complex workloads that require functionalities offered by an operating system. ZSim is reported to be 3x faster than Sniper and about 4x faster than MARSSx86 or Gem5.</p><figure class="kg-card kg-image-card"><img src="https://dotclusters.io/content/images/2023/04/table-1.png" class="kg-image" alt loading="lazy" width="1542" height="621" srcset="https://dotclusters.io/content/images/size/w600/2023/04/table-1.png 600w, https://dotclusters.io/content/images/size/w1000/2023/04/table-1.png 1000w, https://dotclusters.io/content/images/2023/04/table-1.png 1542w" sizes="(min-width: 720px) 720px"></figure><hr><p><em>[1] Carlson, Trevor E. et al. &#x201C;Sniper: Exploring the level of abstraction for scalable and accurate parallel multi-core simulation.&#x201D;<br>[2] Miller, Jason E. et al. &#x201C;Graphite: A distributed parallel simulator for multicores.&#x201D; <br>[3] S&#xE1;nchez, Daniel, Christoforos E. Kozyrakis. &#x201C;ZSim: fast and accurate microarchitectural simulation of thousand-core systems.&#x201D;<br>[4] Binkert, Nathan L. et al. &#x201C;The gem5 simulator.&#x201D; <br>[5] Patel, Avadh et al. &#x201C;MARSS: A full system simulator for multicore x86 CPUs.&quot;<br>[6] Ubal, Rafael et al. &#x201C;Multi2Sim: A simulation framework for CPU-GPU computing.&#x201D; </em></p>]]></content:encoded></item></channel></rss>