<?xml version="1.0" encoding="UTF-8"?><?xml-model type="application/xml-dtd" href="https://jats.nlm.nih.gov/publishing/1.3/JATS-journalpublishing1-3.dtd"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.3 20210610//EN" "https://jats.nlm.nih.gov/publishing/1.3/JATS-journalpublishing1-3.dtd">
<article xmlns:ali="http://www.niso.org/schemas/ali/1.0/" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" specific-use="Marcalyc 1.3" dtd-version="1.3" article-type="research-article" xml:lang="en">
<front>
<journal-meta>
<journal-id journal-id-type="index">7261</journal-id>
<journal-title-group>
<journal-title specific-use="original" xml:lang="es">Avances en Ciencias e Ingenierías</journal-title>
<abbrev-journal-title abbrev-type="publisher" xml:lang="es">ACI Avances en Ciencias e Ingenierías</abbrev-journal-title>
</journal-title-group>
<issn pub-type="ppub">1390-5384</issn>
<issn pub-type="epub">2528-7788</issn>
<issn-l>1390-5384</issn-l>
<publisher>
<publisher-name>Universidad San Francisco de Quito</publisher-name>
<publisher-loc>
<country>Ecuador</country>
<email>avances@usfq.edu.ec</email>
</publisher-loc>
</publisher>
</journal-meta>
<article-meta>
<article-id pub-id-type="art-access-id" specific-use="redalyc">726182578008</article-id>
<article-categories>
<subj-group subj-group-type="heading">
<subject>Artículos</subject>
</subj-group>
</article-categories>
<title-group>
<article-title xml:lang="en">Empirical evaluation of parallel implementations of MergeSort</article-title>
<trans-title-group>
<trans-title xml:lang="es">Evaluación empírica de implementaciones paralelas de MergeSort</trans-title>
</trans-title-group>
</title-group>
<contrib-group>
<contrib contrib-type="author" corresp="yes">
<name name-style="western">
<surname>Solsona</surname>
<given-names>José E.</given-names>
</name>
<xref ref-type="corresp" rid="corresp1"/>
<xref ref-type="aff" rid="aff1"/>
<email>solsona@ort.edu.uy</email>
</contrib>
<contrib contrib-type="author" corresp="no">
<name name-style="western">
<surname>Nesmachnow</surname>
<given-names>Sergio</given-names>
</name>
<xref ref-type="aff" rid="aff2"/>
</contrib>
</contrib-group>
<aff id="aff1">
<institution content-type="original">Universidad ORT, Montevideo, Uruguay.</institution>
<country country="UY">Uruguay</country>
<institution-wrap>
<institution content-type="orgname">Universidad ORT</institution>
<institution-id institution-id-type="ror">https://ror.org/03ypykr22</institution-id>
</institution-wrap>
</aff>
<aff id="aff2">
<institution content-type="original">Universidad de la República, Montevideo, Uruguay.</institution>
<country country="UY">Uruguay</country>
<institution-wrap>
<institution content-type="orgname">Universidad de la República</institution>
<institution-id institution-id-type="ror">https://ror.org/030bbe882</institution-id>
</institution-wrap>
</aff>
<author-notes>
<corresp id="corresp1">
<email>solsona@ort.edu.uy</email>
</corresp>
</author-notes>
<pub-date pub-type="epub-ppub">
<season>Enero</season>
<year>2025</year>
</pub-date>
<volume>17</volume>
<issue>1</issue>
<fpage>1</fpage>
<lpage>17</lpage>
<history>
<date date-type="received" publication-format="dd mes yyyy">
<day>20</day>
<month>11</month>
<year>2024</year>
</date>
<date date-type="accepted" publication-format="dd mes yyyy">
<day>09</day>
<month>12</month>
<year>2024</year>
</date>
<date date-type="pub" publication-format="dd mes yyyy">
<day>08</day>
<month>05</month>
<year>2025</year>
</date>
</history>
<permissions>
<copyright-statement>Los autores conservan los derechos de autor y garantizan a la revista el derecho de ser la primera publicación del trabajo bajo una licencia Creative Commons Atribución-NoComercial 4.0 Internacional.</copyright-statement>
<copyright-year>2025</copyright-year>
<copyright-holder>Revista ACI Avances en Ciencias e Ingenierías</copyright-holder>
<ali:free_to_read/>
<license xlink:href="https://creativecommons.org/licenses/by-nc/4.0/">
<ali:license_ref>https://creativecommons.org/licenses/by-nc/4.0/</ali:license_ref>
<license-p>Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial 4.0 Internacional.</license-p>
</license>
</permissions>
<abstract xml:lang="en">
<title>Abstract</title>
<p>Sorting algorithms are a fundamental piece in the development of computer systems. MergeSort is a well-known sorting algorithm, much appreciated due to its efficiency, relative simplicity, and other features. This article presents an empirical evaluation of parallel versions of MergeSort, applying shared and distributed memory, on a high-performance computing infrastructure. The main result indicates that parallelization of recursive invocations combined with a parallel merge operation offers better speedup than just parallelization of recursive invocations. Moreover, better speedup was achieved in a shared memory environment.</p>
</abstract>
<trans-abstract xml:lang="es">
<title>Resumen</title>
<p>Los algoritmos de ordenamiento son una pieza fundamental en el desarrollo de sistemas informáticos. MergeSort es un algoritmo de ordenamiento muy conocido, muy apreciado por su eficiencia, relativa simplicidad y otras características. Este artículo presenta una evaluación empírica de versiones paralelas de MergeSort, aplicando memoria compartida y distribuida, en una infraestructura computacional de alto rendimiento. El resultado principal indica que la paralelización de invocaciones recursivas combinada con una operación de mezcla paralela ofrece una mejor aceleración que la paralelización de invocaciones recursivas por sí sola. Además, se logró una mejor aceleración en un entorno de memoria compartida.</p>
</trans-abstract>
<kwd-group xml:lang="en">
<title>Keywords</title>
<kwd>High Performance Computing</kwd>
<kwd>Parallel sorting</kwd>
</kwd-group>
<kwd-group xml:lang="es">
<title>Palabras clave</title>
<kwd>Computación de alto rendimiento</kwd>
<kwd>Ordenamiento paralelo</kwd>
</kwd-group>
<counts>
<fig-count count="10"/>
<table-count count="6"/>
<equation-count count="4"/>
<ref-count count="8"/>
</counts>
<custom-meta-group>
<custom-meta>
<meta-name>redalyc-journal-id</meta-name>
<meta-value>7261</meta-value>
</custom-meta>
</custom-meta-group>
</article-meta>
</front>
<body>
<sec>
<title>
<bold>INTRODUCTION</bold>
</title>
<p>Sorting algorithms are a fundamental piece in the development of computer systems and information processing. In particular, MergeSort is a general-purpose sorting algorithm based on element comparison <xref ref-type="bibr" rid="redalyc_726182578008_ref1">[1]</xref>. Although it is reasonable to assume that the basic sorting operation of performing a comparison has low computational cost, sorting large volumes of data in the Big Data era would require long execution times using sequential sorting implementations. Therefore, it is natural to explore adapting existing algorithms to leverage the parallel processing capabilities provided by modern hardware.</p>
<p>In this line of work, this article presents an empirical evaluation of parallel versions of the MergeSort algorithm in high-performance computing environments. The developed parallel versions of MergeSort are based on shared and distributed memory, following different parallelization schemes, using the OpenMP interface and the Message Passing Interface (MPI) library. The evaluation was carried out on a problem instance of size elements, considering up to 39 computing resources.</p>
<p>The main results of the empirical evaluation indicate that in the shared memory implementation parallelization of recursive invocations combined with a parallel merge operation offers better speedup than just parallelization of recursive invocations, as suggested by theoretical analysis. For the distributed memory implementation, a functional decomposition approach performed better than a straightforward master-slave approach. However, the functional decomposition approach did not result in better performance results than a hybrid implementation combining distributed and shared memory. Overall, the best speedup was achieved in the shared memory implementations.</p>
</sec>
<sec>
<title>
<bold>PROBLEM DESCRIPTION</bold>
</title>
<p>Since the cost of MergeSort coincides with the lower bound, MergeSort is said to be optimal. There are other optimal sorting algorithms (e.g., HeapSort), but implementations of MergeSort have the property of stability, as equal elements maintain their position. This property, together with its relative simplicity, makes MergeSort attractive for several applications.</p>
<sec>
<title>
<bold>Classical MergeSort</bold>
</title>
<p>MergeSort is a general-purpose sorting algorithm based on element comparison and the divide-and-conquer strategy <xref ref-type="bibr" rid="redalyc_726182578008_ref2">[2]</xref>. On a conceptual level, MergeSort operates as follows on a vector of <italic>n</italic> elements:</p>
<p>
<bold>1. </bold>Divide the vector into <italic>n</italic> parts, each with a single element, which are considered ordered.</p>
<p>
<bold>2. </bold>Merge the parts producing new ordered vectors until only one ordered vector remains as the final result.</p>
<p>MergeSort is presented in <xref ref-type="fig" rid="gf15">Algorithm 1</xref>. Sequential MergeSort., following the version by Cormen et al. <xref ref-type="bibr" rid="redalyc_726182578008_ref3">[3]</xref>. Being an algorithm based on the divide-and-conquer strategy, its most natural description is recursive. Assuming an initial vector <italic>A=</italic>(<italic>a</italic>
<sub>1</sub>
<italic>,…,a<sub>n</sub>
</italic>) , the result is obtained by invoking <italic>MergeSort</italic> (<italic>A,</italic>1<italic>,A.len</italic>) , where <italic>A.len = n , l</italic> (<italic>left</italic>) stands for the initial position, and <italic>r</italic> (<italic>right</italic>) stands for the final position.</p>
<p>
<fig id="gf15">
<label>
<bold>Algorithm 1</bold>
</label>
<caption>
<title>Sequential MergeSort.</title>
</caption>
<alt-text>Algorithm 1 Sequential MergeSort.</alt-text>
<graphic xlink:href="726182578008_gf16.png" position="anchor" orientation="portrait">
<alt-text>Algorithm 1 Sequential MergeSort.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf15">Algorithm 1</xref>. </bold>Sequential MergeSort.</p>
<p>The division of the problem is performed by two recursive invocations of the procedure MergeSort on the left part <italic>A</italic>[l<italic>,…,m</italic>] and the right part <italic>A</italic>[<italic>m+</italic>1<italic>,…,r</italic>] of the vector, respectively. The division is performed while there are at least two elements, since otherwise the vector is already sorted. After the division, the conquer action is carried out through the Merge operation to merge the parts <italic>A</italic>[l<italic>,…,m</italic>] and <italic>A</italic>[<italic>m+</italic>1<italic>,…,r</italic>] already ordered. The usual way to implement this operation follows the intuitive idea of how to mix two decks of cards already sorted where the smallest cards appear on top. The basic step consists of comparing two cards taken from each deck where we choose and remove the smallest one to build a new deck. We repeat the step until one of the decks runs out of cards in which case the remaining cards will go to the end of the new deck. The sequential merge operation is presented in <xref ref-type="fig" rid="gf16">Algorithm 2</xref>. Sequential merge operation.. The presented version differs slightly from the one by Cormen et al. <xref ref-type="bibr" rid="redalyc_726182578008_ref3">[3]</xref> since it does not use sentinels, just to simplify the presentation.</p>
<p>
<fig id="gf16">
<label>
<bold>Algorithm 2</bold>
</label>
<caption>
<title>Sequential merge operation.</title>
</caption>
<alt-text>Algorithm 2 Sequential merge operation.</alt-text>
<graphic xlink:href="726182578008_gf17.png" position="anchor" orientation="portrait">
<alt-text>Algorithm 2 Sequential merge operation.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf16">Algorithm 2</xref>. </bold>Sequential merge operation.</p>
<p>The computational complexity of MergeSort considers the number of comparisons performed when shuffling as the representative operation of the execution time cost. In general, mixing in MergeSort requires no more than <italic>n</italic>–1 comparisons for a vector of elements. The total cost is the sum of the cost of ordering two halves plus the cost of merging them. Therefore, in the worst case (and also in the average case) the cost of MergeSort is <italic>T</italic>(<italic>n</italic>) = 2 <italic>T</italic>(<italic>n</italic>/2)+Θ(<italic>n</italic>) = Θ(<italic>n log n</italic>).</p>
<p>Regarding memory cost, the typical implementation of MergeSort is not considered an in-place algorithm since the merge operation requires space Θ(<italic>n</italic>) for an auxiliary vector (vector <italic>T</italic> in <xref ref-type="fig" rid="gf16">Algorithm 2</xref>. Sequential merge operation.).</p>
<p>Since the cost of MergeSort coincides with the lower bound, MergeSort is said to be optimal. There are other optimal sorting algorithms (e.g., HeapSort), but implementations of MergeSort have the property of stability, as equal elements maintain their position. This property, together with its relative simplicity, makes MergeSort attractive for several applications.</p>
</sec>
</sec>
<sec>
<title>
<bold>RELATED WORK</bold>
</title>
<p>Several parallel implementations have been proposed for MergeSort. Rolfe <xref ref-type="bibr" rid="redalyc_726182578008_ref4">[4]</xref> proposed an approach for implementing a parallel MergeSort in a distributed memory environment using MPI. The proposed algorithm did not consider a strategy for parallelization of the mixing operation. The experimental performance evaluation was not systematic. Few executions were reported, showing that a better speedup is obtained when the processes are executed within the same machine. This finding emphasizes the importance of considering communication overhead when assessing the performance of parallel implementations. Radensky <xref ref-type="bibr" rid="redalyc_726182578008_ref5">[5]</xref> presented MergeSort implementations using OpenMP and MPI. However, the parallelization of the merge operation was not considered. The experimental evaluation showed that better performance was computed by the shared-memory implementation using OpenMP. Duvanenko <xref ref-type="bibr" rid="redalyc_726182578008_ref6">[6]</xref> implemented a parallel MergeSort using the Microsoft PPL and Intel TBB libraries. Performance gains were reported for problem instances larger than 10<sup>5</sup> on a quad core machine. Axtmann et al. <xref ref-type="bibr" rid="redalyc_726182578008_ref7">[7]</xref> studied how to scale MergeSort generalizations efficiently across a significant number of resources. The research aimed at addressing the challenges associated with handling large-scale applications by optimizing the communication aspects of the sorting algorithms.</p>
<p>The analysis of related works indicates that there is a better understanding of the sorting problem in theory than in practice. In this article, the distributed memory implementations follow a similar approach to Radensky <xref ref-type="bibr" rid="redalyc_726182578008_ref5">[5]</xref>, while the hybrid implementation incorporates parallel merging at the shared-memory level.</p>
<sec>
<title>
<bold>Parallelization of MergeSort</bold>
</title>
<p>This section describes strategies for the developed parallel MergeSort versions.</p>
</sec>
<sec>
<title>
<bold>Overall parallel approaches</bold>
</title>
<p>MergeSort follows a divide-and-conquer strategy, and the natural technique for parallelization is domain decomposition. All parallel versions of MergeSort follow the strategy of executing in parallel on different partitions of the input vector.</p>
<p>Specific instructions are applied for creating threads (fork) or processes (spawn), assuming a dynamic multithreading environment following the style presented by Cormen et al. <xref ref-type="bibr" rid="redalyc_726182578008_ref3">[3]</xref>. Communications and synchronizations are performed using sync and join instructions in the shared memory implementations, or via explicit message passing (Send and Receive) in the distributed memory implementations.</p>
<p>The intuitive semantics of spawn <italic>f</italic>(<italic>x</italic>
<sub>1</sub>
<italic>,...,x<sub>n</sub>
</italic>) indicate that the execution of <italic>f</italic>(<italic>x</italic>
<sub>1</sub>
<italic>,...,x<sub>n</sub>
</italic>) can take place in a new thread of execution, and there is no need to wait for its completion to proceed. Similarly, the intuitive semantics of sync instructs the current thread of execution to wait until all previously created threads have finished their execution. Some parallel programming platforms offer similar instructions to express nested parallelism, but the implementations use them as a means to convey the expected solution at an abstract level.</p>
<p>From a theoretical perspective, there is a lower bound for the comparison ordering problem in the parallel paradigm. Considering <italic>n</italic> processing units to sort <italic>n</italic> elements, no algorithm using the available <italic>n</italic> processors can achieve a sorting time less than a constant multiple of <italic>n</italic> comparisons in the worst case.</p>
</sec>
<sec>
<title>
<bold>First version: Parallelizing recursive invocations</bold>
</title>
<p>The first parallel version of MergeSort (MergeSortPv1) is based on parallelizing only recursive invocations. This version uses the sequential merge algorithm described in <xref ref-type="fig" rid="gf16">Algorithm 2</xref>. Sequential merge operation.. <xref ref-type="fig" rid="gf3">Algorithm 3</xref>. Parallel MergeSort (parallel recursive invocations). presents the pseudocode of MergeSortPv1.</p>
<p>
<fig id="gf3">
<label>
<bold>Algorithm 3</bold>
</label>
<caption>
<title>Parallel MergeSort (parallel recursive invocations).</title>
</caption>
<alt-text>Algorithm 3 Parallel MergeSort (parallel recursive invocations).</alt-text>
<graphic xlink:href="726182578008_gf4.png" position="anchor" orientation="portrait">
<alt-text>Algorithm 3 Parallel MergeSort (parallel recursive invocations).</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf3">Algorithm 3</xref>. </bold>Parallel MergeSort (parallel recursive invocations).</p>
<p>The execution cost of MergeSortPv1 on a single processor matches the execution cost of MergeSort. Ideally, for an unlimited number of processing units, recursive invocations can execute in parallel, but the merge operation imposes a linear cost. The ideal parallelizability of this approach is given by Eq.<xref ref-type="disp-formula" rid="e1">(1)</xref>where <italic>TP<sub>i</sub>
</italic> is the execution time on a parallel machine with processing units.</p>
<p>
<disp-formula id="e1">
<label>(1)</label>
<alternatives><mml:math id="mN106B6" xmlns:mml="http://www.w3.org/1998/Math/MathML">     <mml:mfrac>         <mml:msub>             <mml:mi>TP</mml:mi>             <mml:mn>1</mml:mn>         </mml:msub>         <mml:msub>             <mml:mi>TP</mml:mi>             <mml:mi>&#x221E;</mml:mi>         </mml:msub>     </mml:mfrac>     <mml:mo>=</mml:mo>     <mml:mfrac>         <mml:mrow>             <mml:mi>&#x398;</mml:mi>             <mml:mo>(</mml:mo>             <mml:mi>n</mml:mi>             <mml:mo>log</mml:mo>             <mml:mi>n</mml:mi>             <mml:mo>)</mml:mo>         </mml:mrow>         <mml:mrow>             <mml:mi>&#x398;</mml:mi>             <mml:mo>(</mml:mo>             <mml:mi>n</mml:mi>             <mml:mo>)</mml:mo>         </mml:mrow>     </mml:mfrac>     <mml:mo>=</mml:mo>     <mml:mi>&#x398;</mml:mi>     <mml:mo>(</mml:mo>     <mml:mo>log</mml:mo>     <mml:mi>n</mml:mi>     <mml:mo>)</mml:mo> </mml:math>
<graphic xlink:href="726182578008_ee2.png" position="anchor" orientation="portrait">
<alt-text/>
</graphic>
</alternatives>
</disp-formula>
</p>
</sec>
<sec>
<title>
<bold>Second version: Parallelizing the merge operation</bold>
</title>
<p>The second version of parallel MergeSort (MergeSortPv2) is based on parallelizing the merge operation to improve the degree of parallelism of the first version of parallel MergeSort. In the previous version, the merge operation is the main limitation for parallelization, since it is inherently sequential. Thus, a new merging algorithm is used (MergeP, presented in <xref ref-type="fig" rid="gf17">Algorithm 4</xref>. Parallel merge operation.), which also applies the divide-andconquer strategy and is, therefore, also naturally parallelizable.</p>
<p>At a conceptual level, MergeP operates on two ordered vectors <italic>A</italic> and <italic>B</italic> (where <italic>A.len≥ B.len</italic>  is assumed, without loss of generality) as follows:</p>
<p>
<bold>1.  </bold>Divide <italic>A </italic>into two parts  <italic>A</italic>
<sub>1</sub> and <italic>A</italic>
<sub>2</sub>.</p>
<p>
<bold>2.  </bold>Let <italic>x</italic> be the first element of <italic>A</italic>
<sub>2</sub>. A binary search is performed on <italic>B</italic> to find the position h where x should be inserted into <italic>B</italic>. Then <italic>B</italic> is partitioned over <italic>h</italic>, generating two parts <italic>B</italic>
<sub>1</sub> and <italic>B</italic>
<sub>2</sub>.</p>
<p>
<bold>3.  </bold>
<italic>A</italic>
<sub>1</sub> is merged with <italic>B</italic>
<sub>1</sub> resulting in the first sorted half, and <italic>A</italic>
<sub>2</sub> is merged with <italic>B</italic>
<sub>2</sub> resulting in the second sorted half.</p>
<p>
<fig id="gf17">
<label>
<bold>Algorithm 4</bold>
</label>
<caption>
<title>Parallel merge operation.</title>
</caption>
<alt-text>Algorithm 4 Parallel merge operation.</alt-text>
<graphic xlink:href="726182578008_gf18.png" position="anchor" orientation="portrait">
<alt-text>Algorithm 4 Parallel merge operation.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf17">Algorithm 4</xref>. </bold>Parallel merge operation.</p>
<p>
<xref ref-type="fig" rid="gf6">Figure 1</xref>. Description of the logic in MergeP. shows an intuitive scheme of how the result <italic>C</italic> is constructed from the input vectors <italic>A</italic> and <italic>B</italic> in <xref ref-type="fig" rid="gf17">Algorithm 4</xref>. Parallel merge operation..</p>
<p>
<fig id="gf6">
<label>Figure 1</label>
<caption>
<title>Description of the logic in MergeP.</title>
</caption>
<alt-text>Figure 1  Description of the logic in MergeP.</alt-text>
<graphic xlink:href="726182578008_gf7.png" position="anchor" orientation="portrait">
<alt-text>Figure 1  Description of the logic in MergeP.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf6">Figure 1</xref>. </bold>Description of the logic in MergeP.</p>
<p>The cost of executing MergeP on a single processor is asymptotically equal to the sequential version. However, assuming an unlimited number of process units, the cost is logarithmic rather than linear, i.e., Θ(log<sup>2</sup>
<italic>n</italic>), assuming that the search for position is performed in a binary way.</p>
<p>Thus, in the parallel version of MergeSort using MergeP instead of Merge, the cost on a single processor matches the cost of MergeSortPv1, but on an ideal machine the cost is Θ(log<sup>3</sup>
<italic>n</italic>). The ideal parallelizability of this approach is given by Eq. In comparison, the theory suggests that the second proposed version has the property of scaling better over additional computing resources, ignoring any overhead associated with parallelism..</p>
<p>
<disp-formula id="e4">
<label>(2)</label>
<alternatives><mml:math id="mN1086E" xmlns:mml="http://www.w3.org/1998/Math/MathML">     <mml:mfrac>         <mml:msub>             <mml:mi>TP</mml:mi>             <mml:mn>1</mml:mn>         </mml:msub>         <mml:msub>             <mml:mi>TP</mml:mi>             <mml:mi>&#x221E;</mml:mi>         </mml:msub>     </mml:mfrac>     <mml:mo>=</mml:mo>     <mml:mfrac>         <mml:mrow>             <mml:mi>&#x398;</mml:mi>             <mml:mo>(</mml:mo>             <mml:mi>n</mml:mi>             <mml:mo>log</mml:mo>             <mml:mi>n</mml:mi>             <mml:mo>)</mml:mo>         </mml:mrow>         <mml:mrow>             <mml:mi>&#x398;</mml:mi>             <mml:mo>(</mml:mo>             <mml:msup>                 <mml:mo>log</mml:mo>                 <mml:mn>3</mml:mn>             </mml:msup>             <mml:mi>n</mml:mi>             <mml:mo>)</mml:mo>         </mml:mrow>     </mml:mfrac>     <mml:mo>=</mml:mo>     <mml:mi>&#x398;</mml:mi>     <mml:mo>(</mml:mo>     <mml:mfrac>         <mml:mi>n</mml:mi>         <mml:mrow>             <mml:msup>                 <mml:mo>log</mml:mo>                 <mml:mn>2</mml:mn>             </mml:msup>             <mml:mi>n</mml:mi>         </mml:mrow>     </mml:mfrac>     <mml:mo>)</mml:mo> </mml:math>
<graphic xlink:href="726182578008_ee4.png" position="anchor" orientation="portrait">
<alt-text/>
</graphic>
</alternatives>
</disp-formula>
</p>
<p>(2)</p>
<p>In comparison, the theory suggests that the second proposed version has the property of scaling better over additional computing resources, ignoring any overhead associated with parallelism.</p>
</sec>
<sec>
<title>
<bold>Implementation details</bold>
</title>
<p>This section describes the implementation details of the developed sequential and parallel versions of MergeSort. The code is publicly available on GitHub, <underline>https://github.com/josedusol/parallel-merge-sort</underline>.</p>
</sec>
<sec>
<title>
<bold>Sequential implementation</bold>
</title>
<p>
<underline>MergeSort.c</underline> is the classic implementation of MergeSort in the C language, following <xref ref-type="fig" rid="gf15">Algorithm 1</xref>. Sequential MergeSort.. The best implementations of MergeSort typically apply another stable sorting algorithm (e.g. InsertionSort) for small inputs, taking advantage of improved efficiency on those inputs. This hybrid approach is not applied in the developed implementation, to guarantee a fair comparison with the developed parallel implementations of MergeSort.</p>
</sec>
<sec>
<title>
<bold>Shared memory implementations</bold>
</title>
<p>The shared memory implementations of MergeSort were developed using the C language and the OpenMP application programming interface (API). Two approaches provided by the OpenMP API were studied for the execution of code segments in parallel:</p>
<p>
<bold>1.  </bold>sections directive. Each recursive invocation is placed in a different section. Because there is an implicit synchronization barrier at the end of this directive, the merge operation is inserted after. This alternative is only applicable if the nested parallelism option OMP_NESTED is explicitly activated.</p>
<p>
<bold>2.  </bold>task directive, available from OpenMP v3.0 onward. This is the best alternative to support unstructured parallelism, such as the one arising from parallel recursion. In this case, each recursive invocation is a different task. For the merge operation, it is necessary to also use taskwait which explicitly indicates the precedence between the split and merge tasks.</p>
<p>Preliminary experiments showed that task/taskwait allowed for computing better performance results. Thus, this approach was adopted for deployments.</p>
<p>
<underline>MergeSortPv1_omp.c</underline> implements the MergeSortPv1 algorithm. The merge operation in the algorithm assumes that a new temporal vector is used for each invocation. However, a more efficient approach is to create a single vector before starting the sort and pass its address as a parameter to the involved routines. By doing so, the overhead associated with the initializing and releasing memory in each invocation is avoided. The overhead reduction implies that the same vector is used concurrently by different threads, accessing different portions during the merge process, without any risk of data races.</p>
<p>
<underline>MergeSortPv2_omp.c</underline> implements the MergeSortPv2 algorithm, following the version presented by Cormen et al. <xref ref-type="bibr" rid="redalyc_726182578008_ref3">[3]</xref>. The algorithm receives the original array <italic>A</italic> and an additional output array <italic>B</italic> to store the resulting values. However, it assumes that a new temporal vector <italic>T</italic> is used in each invocation. This vector is passed as the extra output array to the recursive calls, and the parallel merge operation is performed on <italic>T</italic>, storing the result in <italic>B</italic>. This approach has overhead due to initializing and releasing memory in each invocation, similar to the merge phase in the previous algorithm MergeSortPv1. To avoid this overhead and eliminate the need for additional vectors, a solution is to swap the roles of vectors <italic>A</italic> and <italic>B</italic> at each level of the recursion. In fact, without this optimization, the speedup achieved by this implementation is only marginally higher than that of the MergeSortPv1_omp.c implementation.</p>
<p>In both implementations, creating OpenMP tasks at each level of the recursion introduces an overhead that degrades the expected performance gains, even though creating a task does not mean creating a new operating system thread. To mitigate this negative factor, one approach is to limit the application of parallelism based on either the size of the input vector or the depth of the recursion. The developed implementations apply the restriction based on the size of the input vector.</p>
<p>On the one hand, in the implementation of MergeSortPv1_omp.c, MergeSort is invoked sequentially for sizes smaller than a threshold value CUT_OFF. On the other hand,  there are two different levels of recursion to control in MergeSortPv2_omp.c: initially, MergeSort is executed sequentially for sizes less than a threshold value CUT_ OFF_1, and the sequential Merge is called for the total sizes (i.e., the sum of the sizes of two vectors) less than a threshold value CUT_OFF_2.</p>
<p>The optimal values for thresholds CUT_OFF, CUT_OFF_1, and CUT_OFF_2 are platformdependent and are determined through empirical testing and experimentation. These values are chosen in an ad-hoc manner to achieve the best performance on the specific computing platform.</p>
</sec>
<sec>
<title>
<bold>Distributed memory implementations</bold>
</title>
<p>The distributed memory implementations of MergeSort were developed using the C language and the MPI library. Three implementations were developed, applying a straightforward master-slave approach, a functional decomposition approach, and a hybrid approach combining distributed and shared memory for efficient computation. The developed implementations are described next.</p>
<p>
<underline>MergeSortPv0_mpi.c</underline> is a distributed memory implementation of MergeSort based on worksharing. A master-slave hierarchical architecture is applied. The master evenly divides the input vector and distributes chunks using MPI_Scatter among the available processes so that each process performs a local sequential sorting in the assigned chunk. The processes return the sorted parts to the master process using MPI_ Gather, and the master performs a final sequential sort. Although this implementation does not correspond exactly to the theoretical algorithms MergeSortPv1 and MergeSortPv2, it is the most direct and elementary parallelization of the problem using MPI, and therefore it is interesting to consider it for simplicity as a baseline for the comparison of efficiency results.</p>
<p>
<underline>MergeSortPv1_mpi.c</underline> is an implementation of the MergeSortPv1 algorithm, applying a functional decomposition technique <xref ref-type="bibr" rid="redalyc_726182578008_ref5">[5]</xref>.</p>
<p>A virtual tree of processes that represents the tree of recursive calls is built. At each level, different processes work in parallel either to divide or to merge. The depth of the process tree is limited by the number of available processes. The base case in the construction of the tree is to invoke MergeSort sequentially for the leave nodes of the tree. <xref ref-type="fig" rid="gf8">Figure 2</xref>. Virtual tree of four processes to sort vector . presents a scheme of the functional decomposition technique when using four processes on a vector of eight elements. The dashed lines indicate that the process retains the first half of the vector, and the bi-directional arrows indicate that the process should send the second half of the vector to an auxiliary process. The four lists of size 2 on the leaves of the tree are ordered sequentially. Asynchronous communications are performed, using MPI_Isend, to properly overlap data transmission and computation. Then, the process receives the ordered half from the auxiliary process using a standard MPI_Recv routine.</p>
<p>
<fig id="gf8">
<label>Figure 2</label>
<caption>
<title>Virtual tree of four processes to sort vector.</title>
</caption>
<alt-text>Figure 2  Virtual tree of four processes to sort vector.</alt-text>
<graphic xlink:href="726182578008_gf9.png" position="anchor" orientation="portrait">
<alt-text>Figure 2  Virtual tree of four processes to sort vector.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf8">Figure 2</xref>. </bold>Virtual tree of four processes to sort vector.</p>
<p>
<underline>MergeSortPv2_hyb.c</underline> is a hybrid implementation of the MergeSortPv2 algorithm using MPI and OpenMP. The data splitting phase is implemented using MPI, as performed in MergeSortPv1_mpi.c, and the merge operation is implemented using OpenMP, as performed in MergeSortPv2_omp.c. Additionally, OpenMP is also used in the base case of the virtual process tree. Parallelism restrictions with the values CUT_OFF_1 and CUT_OFF_2 are also applied to mitigate the overhead associated with threads creation and management in OpenMP.</p>
</sec>
<sec>
<title>
<bold>Experimental evaluation</bold>
</title>
<p>This section describes the empirical analysis of the developed parallel MergeSort implementations.</p>
</sec>
</sec>
<sec>
<title>
<bold>METHODOLOGY</bold>
</title>
<p>The experimental evaluation was performed over a large vector of size with random integers. The memory required to store the vector was roughly 3 GB. Every experiment was repeated five times to avoid fluctuating execution times. If applicable, outliers were detected and discarded. The overall execution time was the average of non-discarded execution times.</p>
<p>
<bold>Evaluation of shared memory implementations. </bold>For shared memory implementations, the main configurable parameter is the number of threads to use, set by the environment variable OMP_NUM_THREADS. The experiments studied the performance using a number of threads in the range of 1 to 39. The number of threads is always matched to the number of CPU cores available. The execution time (walltime) is measured using the omp_get_wtime function.</p>
<p>
<bold>Evaluation of distributed memory implementations.</bold> The distributed memory implementations are executed through mpiexec/mpirun. The main configurable parameter is np, indicating the number of processes for execution. The experiments studied the performance using a number of processes in the range of 1 to 16. In particular, for the MergeSortPv0_imp.c implementation, only those numbers of processes that divide the size of the vector were used (1, 2, 4, 5, 8, 10, and 16). On the other hand, for the hybrid implementation MergeSortPv2_hyb.c, four CPU cores are always requested per process, and OpenMP is configured to use four threads. Additionally, the hybrid implementation was executed in a distributed manner in two different nodes. The walltime is measured using the MPI_Wtime function. To make this measurement meaningful, a barrier (MPI_Barrier) was included before and after performing the sort, taking the initial time after the first barrier and the final time after the second barrier.</p>
<sec>
<title>
<bold>Performance evaluation metrics</bold>
</title>
<p>The execution time is used as the main metric for performance evaluation. The performance evaluation of parallelism is focused on strong scalability, i.e., how the execution time varies when using a different number of processing units for a fixed input size. The goal is to reduce the execution time.</p>
<p>The traditional approach applying the algorithmic speedup is applied to evaluate performance. Speedup computes the ratio of the execution time of a baseline sequential implementation <italic>T<sub>S</sub>
</italic> and the execution time of the parallel algorithm using N compute resources <italic>TP<sub>N</sub>
</italic> (Eq. <xref ref-type="disp-formula" rid="e5">(3)</xref>In this case, the sequential algorithm is MergeSort.c, described before. Computational efficiency is the normalized version of the speedup (Eq. Development and execution platform).</p>
<p>
<disp-formula id="e5">
<label>(3)</label>
<alternatives><mml:math id="mN10A7C" xmlns:mml="http://www.w3.org/1998/Math/MathML">     <mml:msub>         <mml:mi>S</mml:mi>         <mml:mi>N</mml:mi>     </mml:msub>     <mml:mo>=</mml:mo>     <mml:mfrac>         <mml:msub>             <mml:mi>T</mml:mi>             <mml:mi>S</mml:mi>         </mml:msub>         <mml:msub>             <mml:mi>TP</mml:mi>             <mml:mi>N</mml:mi>         </mml:msub>     </mml:mfrac> </mml:math>
<graphic xlink:href="726182578008_ee6.png" position="anchor" orientation="portrait">
<alt-text/>
</graphic>
</alternatives>
</disp-formula>
</p>
<p>(3)</p>
<p>
<disp-formula id="e6">
<label>(4)</label>
<alternatives><mml:math id="mN10AB9" xmlns:mml="http://www.w3.org/1998/Math/MathML">     <mml:msub>         <mml:mi>E</mml:mi>         <mml:mi>N</mml:mi>     </mml:msub>     <mml:mo>=</mml:mo>     <mml:mfrac>         <mml:msub>             <mml:mi>S</mml:mi>             <mml:mi>N</mml:mi>         </mml:msub>         <mml:mi>N</mml:mi>     </mml:mfrac> </mml:math>
<graphic xlink:href="726182578008_ee8.png" position="anchor" orientation="portrait">
<alt-text/>
</graphic>
</alternatives>
</disp-formula>
</p>
<p>(4)</p>
</sec>
<sec>
<title>
<bold>Development and execution platform</bold>
</title>
<p>The proposed algorithms were developed in the C language, using the GCC v8 compiler. Initial local developments were performed using the MPICH v3.2 implementation of MPI, and the final development was performed using the OpenMPI implementation of MPI.</p>
<p>The experimental evaluation was performed on the high-performance computing infrastructure of National Supercomputing Center, Uruguay (ClusterUY) <xref ref-type="bibr" rid="redalyc_726182578008_ref8">[8]</xref>. Each computing node has two Intel Xeon Gold 6138 CPUs with 20 cores each and 128 GB of RAM. Nodes are connected by 10 Gbps Ethernet. Executions were performed without using hyperthreading.</p>
</sec>
<sec>
<title>
<bold>Efficiency results</bold>
</title>
<p>This subsection reports on the efficiency results of the developed parallel versions of MergeSort. For OpenMP-based implementations, the following values were determined in preliminary experiments to mitigate overheads: CUT_OFF = 800 in MergeSortPv1_ omp.c and the hybrid implementation MergeSortPv2_hyb.c, and CUT_OFF_1=800, CUT_OFF_2=80000 in MergeSortPv2_omp.c and the hybrid implementation MergeSortPv2_hyb.c.</p>
<p>
<bold>Shared-memory implementations.</bold>
<xref ref-type="table" rid="gt1">Table 1</xref> reports the average execution times of the shared memory implementations using OpenMP. For reference, the average execution time of the sequential implementation MergeSort.c for n=10<sup>9</sup> w was 318.67s. <xref ref-type="fig" rid="gf11">Figure 3</xref> graphically presents the evolution of execution times.</p>
<p>
<bold>
<xref ref-type="table" rid="gt1">Table 1</xref>. </bold>Execution time (s) for different numbers of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</p>
<p>
<table-wrap id="gt1">
<label>Table 1</label>
<caption>
<title>Execution time (s) for different numbers of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</title>
</caption>
<alt-text>Table 1  Execution time (s) for different numbers of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt2.png" position="anchor" orientation="portrait">
<alt-text>Table 1  Execution time (s) for different numbers of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
</graphic>
<table style="width:312.6pt;margin-left:-.4pt;border-collapse:collapse;" id="gt2-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt 1.6pt 1.75pt 0cm;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 1.6pt 1.75pt 0cm;height:29.5pt">
<bold>1</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 1.6pt 1.75pt 0cm;height:29.5pt">
<bold>2</bold>
</td>
<td style="background-color: #E4322B; width:74.7pt;   padding:2.0pt 1.6pt 1.75pt 0cm;height:29.5pt" colspan="2">
<bold>computing   resource 4  8</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;padding:2.0pt 1.6pt 1.75pt 0cm;   height:29.5pt">
<bold>s 16</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 1.6pt 1.75pt 0cm;height:29.5pt">
<bold>32</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">MergeSortPv1_omp</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">274.96</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">153.68</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">115.14</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">83.49</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;height:14.0pt">65.66</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">47.42</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">MergeSortPv2_omp</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">231.69</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">124.86</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">83.48</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">49.43</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">27.85</td>
<td style="width:37.35pt;border:none;padding:2.0pt 1.6pt 1.75pt 0cm;   height:14.0pt">17.59</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<fig id="gf11">
<label>Figure 3</label>
<caption>
<title>Execution time of shared memory OpenMP MergeSort implementations.</title>
</caption>
<alt-text>Figure 3  Execution time of shared memory OpenMP MergeSort implementations.</alt-text>
<graphic xlink:href="726182578008_gf12.png" position="anchor" orientation="portrait">
<alt-text>Figure 3  Execution time of shared memory OpenMP MergeSort implementations.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf11">Figure 3</xref>. </bold>Execution time of shared memory OpenMP MergeSort implementations.</p>
<p>Tables <xref ref-type="table" rid="gt2">2</xref> and <xref ref-type="table" rid="gt3">3</xref> report the speedup and efficiency values computed for the shared memory implementations using OpenMP. <xref ref-type="fig" rid="gf12">Figure 4</xref> graphically presents the graphs of speedup and efficiency as a function of the number of threads.</p>
<p>
<bold>
<xref ref-type="table" rid="gt2">Table 2</xref>. </bold>Speedup for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</p>
<p>
<table-wrap id="gt2">
<label>Table 2</label>
<caption>
<title>Speedup for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</title>
</caption>
<alt-text>Table 2 Speedup for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt3.png" position="anchor" orientation="portrait">
<alt-text>Table 2 Speedup for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
</graphic>
<table style="width:312.6pt;margin-left:-.4pt;border-collapse:collapse;" id="gt3-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>1</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>2</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:74.7pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt" colspan="2">
<bold>speedup <italic>S</italic>4  <italic>S</italic>8</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>16</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>32</sub>
</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">MergeSortPv1_omp</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">1.16</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">2.07</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">2.77</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">3.82</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">4.85</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">6.72</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">MergeSortPv2_omp</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">1.38</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">2.55</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">3.82</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">6.45</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">11.44</td>
<td style="width:37.35pt;border:none;padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">18.11</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<bold>
<xref ref-type="table" rid="gt2">Table 3</xref>. </bold>Efficiency for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</p>
<p>
<table-wrap id="gt3">
<label>Table 3</label>
<caption>
<title>Efficiency for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</title>
</caption>
<alt-text>Table 3  Efficiency for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt4.png" position="anchor" orientation="portrait">
<alt-text>Table 3  Efficiency for different number of computing resources (threads) for shared memory MergeSort implementations using OpenMP.</alt-text>
</graphic>
<table style="width:312.6pt;margin-left:-.4pt;border-collapse:collapse;" id="gt4-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>1</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>2</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:74.7pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt" colspan="2">
<bold>efficiency <italic>E</italic>4  <italic>E</italic>8</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>16</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.7pt 5.75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>32</sub>
</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">MergeSortPv1_omp</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">1.16</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">1.04</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">0.69</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">0.48</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;height:14.0pt">0.30</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">0.21</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">MergeSortPv2_omp</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">1.38</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">1.28</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">0.95</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">0.81</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">0.72</td>
<td style="width:37.35pt;border:none;padding:2.0pt 5.75pt 1.7pt 5.75pt;   height:14.0pt">0.57</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<fig id="gf12">
<label>Figure 4</label>
<caption>
<title>Speedup and efficiency for the shared memory MergeSort implementations using OpenMP. The dotted line is the linear speedup.</title>
</caption>
<alt-text>Figure 4  Speedup and efficiency for the shared memory MergeSort implementations using OpenMP. The dotted line is the linear speedup.</alt-text>
<graphic xlink:href="726182578008_gf13.png" position="anchor" orientation="portrait">
<alt-text>Figure 4  Speedup and efficiency for the shared memory MergeSort implementations using OpenMP. The dotted line is the linear speedup.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf12">Figure 4</xref>. </bold>Speedup and efficiency for the shared memory MergeSort implementations using OpenMP. The dotted line is the linear speedup.</p>
<p>The results of the performance analysis indicate that the MergeSortPv1_omp.c implementation showed a high speedup when using a small number of threads (≤3). However, as the number of threads increased, the implementation deviated from the theoretically optimal performance given by the linear speedup. Using four threads, the efficiency dropped below 0.7. Moreover, when using more than 20 threads, the speedup tended to stagnate. This result aligns with Amdahl's Law, which suggests that sequential work becomes a limiting factor despite the availability of additional processing units. For the considered implementation, the limiting factor is the linear-cost merge operation, which acts as the bottleneck of the implementation.</p>
<p>In contrast, the MergeSortPv2_omp.c implementation demonstrated a remarkable speedup with consistent growth. Unlike the previous implementation, it showed no signs of stagnation and achieved the maximum speedup value when using the largest number of threads (39). However, it is anticipated that this upward trend will diminish or even reverse as the number of threads further increases. The efficiency of this implementation only dropped below 0.7 when using more than 20 threads.</p>
<p>
<bold>Distributed-memory implementations. </bold>
<xref ref-type="table" rid="gt4">Table 4</xref> reports the average execution times of the distributed memory implementations of MergeSort using MPI. <xref ref-type="fig" rid="gf13">Figure 5</xref> graphically presents the evolution of execution times.</p>
<p>
<bold>
<xref ref-type="table" rid="gt4">Table 4</xref>. </bold>Execution time (s) for different number of computing resources (processes) for distributed memory MPI MergeSort implementations.</p>
<p>
<table-wrap id="gt4">
<label>Table 4</label>
<caption>
<title>Execution time (s) for different number of computing resources (processes) for distributed memory MPI MergeSort implementations.</title>
</caption>
<alt-text>Table 4  Execution time (s) for different number of computing resources (processes) for distributed memory MPI MergeSort implementations.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt5.png" position="anchor" orientation="portrait">
<alt-text>Table 4  Execution time (s) for different number of computing resources (processes) for distributed memory MPI MergeSort implementations.</alt-text>
</graphic>
<table style="width:275.25pt;margin-left:18.3pt;border-collapse:collapse;" id="gt5-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.75pt 5.75pt;height:29.5pt">
<bold>1</bold>
</td>
<td style="background-color: #E4322B; width:112.05pt;   padding:2.0pt 5.75pt 1.75pt 5.75pt;height:29.5pt" colspan="3">
<bold>computing resources 2  4  8</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 5.75pt 1.75pt 5.75pt;height:29.5pt">
<bold>16</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">MergeSortPv0_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">236.06</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">286.17</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">222.13</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">201.62</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">211.97</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;height:14.0pt">MergeSortPv1_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">281.88</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">287.91</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">221.54</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">159.27</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">117.59</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">MergeSortPv2_hyb</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">254.05</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">264.01</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">73.97</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">54.68</td>
<td style="width:37.35pt;border:none;padding:2.0pt 5.75pt 1.75pt 5.75pt;   height:14.0pt">41.29</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<fig id="gf13">
<label>Figure 5</label>
<caption>
<title>Execution times for distributed memory MPI MergeSort implementations.</title>
</caption>
<alt-text>Figure 5  Execution times for distributed memory MPI MergeSort implementations.</alt-text>
<graphic xlink:href="726182578008_gf14.png" position="anchor" orientation="portrait">
<alt-text>Figure 5  Execution times for distributed memory MPI MergeSort implementations.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf13">Figure 5</xref>. </bold>Execution times for distributed memory MPI MergeSort implementations.</p>
<p>Tables <xref ref-type="table" rid="gt5">5</xref> and <xref ref-type="table" rid="gt6">6</xref> report the speedup and efficiency of the distributed memory MergeSort implementations using MPI. <xref ref-type="fig" rid="gf14">Figure 6</xref> graphically presents the speedup and efficiency as a function of the number of computing resources/processes.</p>
<p>
<bold>
<xref ref-type="table" rid="gt5">Table 5</xref>. </bold>Speedup of distributed memory MPI MergeSort implementations.</p>
<p>
<table-wrap id="gt5">
<label>Table 5</label>
<caption>
<title>Speedup of distributed memory MPI MergeSort implementations.</title>
</caption>
<alt-text>Table 5 Speedup of distributed memory MPI MergeSort implementations.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt6.png" position="anchor" orientation="portrait">
<alt-text>Table 5 Speedup of distributed memory MPI MergeSort implementations.</alt-text>
</graphic>
<table style="width:275.25pt;margin-left:18.3pt;border-collapse:collapse;" id="gt6-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 2.25pt 1.7pt 2.25pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>1</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 2.25pt 1.7pt 2.25pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>2</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:29.5pt">
<bold>speedup <italic>S</italic>
<sub>4</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 2.25pt 1.7pt 2.25pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>8</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt 2.25pt 1.7pt 2.25pt;height:29.5pt">
<bold>
<italic>S</italic>
<sub>16</sub>
</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">MergeSortPv0_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">1.35</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">1.11</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">1.43</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">1.58</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.50</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;height:14.0pt">MergeSortPv1_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.13</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.11</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.44</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">2.00</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">2.71</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">MergeSortPv2_hyb</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.25</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">1.21</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">4.31</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">5.83</td>
<td style="width:37.35pt;border:none;padding:2.0pt 2.25pt 1.7pt 2.25pt;   height:14.0pt">7.72</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<bold>
<xref ref-type="table" rid="gt6">Table 6</xref>. </bold>Efficiency of distributed memory MPI MergeSort implementations.</p>
<p>
<table-wrap id="gt6">
<label>Table 6</label>
<caption>
<title>Efficiency of distributed memory MPI MergeSort implementations.</title>
</caption>
<alt-text>Table 6  Efficiency of distributed memory MPI MergeSort implementations.</alt-text>
<alternatives>
<graphic xlink:href="726182578008_gt7.png" position="anchor" orientation="portrait">
<alt-text>Table 6  Efficiency of distributed memory MPI MergeSort implementations.</alt-text>
</graphic>
<table style="width:275.25pt;margin-left:18.3pt;border-collapse:collapse;" id="gt7-526564616c7963">
<thead style="display:none;">
<tr style="display:none;">
<th style="display:none;"/>
</tr>
</thead>
<tbody>
<tr style="height:29.5pt">
<td style="background-color: #E4322B; width:88.5pt;padding:2.0pt .75pt 1.7pt .75pt;   height:29.5pt">
<bold>implementation</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt .75pt 1.7pt .75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>1</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt .75pt 1.7pt .75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>2</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;padding:2.0pt .75pt 1.7pt .75pt;   height:29.5pt">
<bold>efficiency <italic>E</italic>
<sub>4</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt .75pt 1.7pt .75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>8</sub>
</bold>
</td>
<td style="background-color: #E4322B; width:37.35pt;   padding:2.0pt .75pt 1.7pt .75pt;height:29.5pt">
<bold>
<italic>E</italic>
<sub>16</sub>
</bold>
</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">MergeSortPv0_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">1.35</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">0.56</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">0.36</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">0.10</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.09</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;height:14.0pt">MergeSortPv1_mpi</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">1.13</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.55</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.36</td>
<td style="width:37.35pt;border-top:none;border-left:   none;border-bottom:solid #181717 1.0pt;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.25</td>
<td style="width:37.35pt;border:none;border-bottom:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.17</td>
</tr>
<tr style="height:14.0pt">
<td style="width:88.5pt;border:none;border-right:solid #181717 1.0pt;      padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">MergeSortPv2_hyb</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">1.25</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.60</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">1.08</td>
<td style="width:37.35pt;border:none;border-right:solid #181717 1.0pt;         padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.73</td>
<td style="width:37.35pt;border:none;padding:2.0pt .75pt 1.7pt .75pt;   height:14.0pt">0.48</td>
</tr>
</tbody>
</table>
</alternatives>
</table-wrap>
</p>
<p>
<fig id="gf14">
<label>Figure 6</label>
<caption>
<title>Speedup and efficiency for distributed memory MergeSort implementations using MPI. The dotted line is the linear speedup.</title>
</caption>
<alt-text>Figure 6  Speedup and efficiency for distributed memory MergeSort implementations using MPI. The dotted line is the linear speedup.</alt-text>
<graphic xlink:href="726182578008_gf15.png" position="anchor" orientation="portrait">
<alt-text>Figure 6  Speedup and efficiency for distributed memory MergeSort implementations using MPI. The dotted line is the linear speedup.</alt-text>
</graphic>
</fig>
</p>
<p>
<bold>
<xref ref-type="fig" rid="gf14">Figure 6</xref>. </bold>Speedup and efficiency for distributed memory MergeSort implementations using MPI. The dotted line is the linear speedup.</p>
<p>The results of the performance analysis indicate that the speedup achieved by the MergeSortPv0_mpi.c implementation was notably poor. Comparatively, the MergeSortPv1_mpi.c implementation demonstrated a slightly improved speedup, but its growth rate remained quite slow. On the other hand, the hybrid implementation MergeSortPv2_hyb.c, despite initially exhibiting unexpectedly poor performance when using only two processes, showed a better performance overall as the number of processes increased. This is a relevant result since the hybrid implementation was executed on different computing nodes, implying that the other developed implementations had not experienced significant inter-node communication costs.</p>
<p>When comparing the two groups of implementations, it is evident that superior results were achieved using OpenMP. In fact, the best-performing MPI-based implementation was the hybrid approach that combined MPI with OpenMP. Both groups had specific cases where superlinear speedup was achieved, i.e., the performance improvement exceeded the expected linear scaling. Overall, the utilization of OpenMP has proven to be more effective in terms of performance, and the presence of almost linear speedup values highlights the potential efficiency gains achievable through parallelization.</p>
</sec>
</sec>
<sec>
<title>
<bold>CONCLUSIONS AND FUTURE WORK</bold>
</title>
<p>This article presented an empirical evaluation of parallel versions of MergeSort, applying shared memory and distributed memory approaches.</p>
<p>The standard MergeSort algorithm has inherent parallelizability, primarily because of the independence of its recursive calls. Both theoretical analysis and experimental evidence suggest that even greater advantages are achievable by recognizing the parallel nature of the merging operation, besides the recursive calls in MergeSort.</p>
<p>The empirical analysis of the developed parallel implementations demonstrated that the most favorable performance results were obtained when using a shared memory implementation using OpenMP, in line with previous results from related works. Regarding distributed memory implementations, the best performance results were achieved by a hybrid implementation executing on different computing nodes.</p>
<p>The main lines for future work are related to extending the empirical evaluation and analyzing the scalability for larger and different types of inputs, and analyzing methods for finding the best values of CUT_OFF_1 and CUT_OFF_2 parameters. In turn, a specific parallelization technique can be applied for distributed memory implementations to process the virtual process tree, adapted to parallelize the merge operation.</p>
</sec>
<sec>
<title>
<bold>AUTHOR CONTRIBUTIONS</bold>
</title>
<p>José Solsona conceived the research and conducted the experiment. Sergio Nesmachnow contributed to the manuscript.</p>
</sec>
<sec>
<title>
<bold>CONFLICT OF INTEREST</bold>
</title>
<p>The authors declare no conflict of interest related to the publication of this article. All authors have read and approved the final manuscript and consent to its publication.</p>
</sec>
</body>
<back>
<ref-list>
<title>
<bold>REFERENCES</bold>
</title>
<ref id="redalyc_726182578008_ref1">
<label>[1]</label>
<mixed-citation publication-type="book">[1] Knuth, D. E. (1997). <italic>The art of computer programming, volume 3: Sorting and searching </italic>(2nd ed.). Addison–Wesley.</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Knuth</surname>
<given-names>D. E.</given-names>
</name>
</person-group>
<source>The art of computer programming, volume 3: Sorting and searching</source>
<year>1997</year>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref2">
<label>[2]</label>
<mixed-citation publication-type="book">[2] Katajainen, J., &amp; Träff, J. L. (1997). Algorithms and complexity. In<italic> Proceedings of the 3rd Italian Conference on Algorithms and Complexity.</italic>
</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Katajainen</surname>
<given-names>J.</given-names>
</name>
<name>
<surname>Träff</surname>
<given-names>J. L.</given-names>
</name>
</person-group>
<source>Proceedings of the 3rd Italian Conference on Algorithms and Complexity.</source>
<year>1997</year>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref3">
<label>[3]</label>
<mixed-citation publication-type="book">[3] Cormen, T. H., Leiserson, C. E., Rivest, R. L., &amp; Stein, C. (2009). <italic>Introduction to algorithms</italic> (3rd. ed.). The MIT Press.</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Cormen</surname>
<given-names>T. H.</given-names>
</name>
<name>
<surname>Leiserson</surname>
<given-names>C. E.</given-names>
</name>
<name>
<surname>Rivest</surname>
<given-names>R. L.</given-names>
</name>
<name>
<surname>Stein</surname>
<given-names>C.</given-names>
</name>
</person-group>
<source>Introduction to algorithms</source>
<year>2009</year>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref4">
<label>[4]</label>
<mixed-citation publication-type="journal">[4] Rolfe, T. J. (2010). A specimen of parallel programming: Parallel merge sort implementation. <italic>ACM Inroads, 1</italic>(4), 72–79. <ext-link ext-link-type="uri" xlink:href="http://doi.org/10.1145/1869746.1869767">http://doi.org/10.1145/1869746.1869767</ext-link>
</mixed-citation>
<element-citation publication-type="journal">
<person-group person-group-type="author">
<name>
<surname>Rolfe</surname>
<given-names>T. J.</given-names>
</name>
</person-group>
<article-title>A specimen of parallel programming: Parallel merge sort implementation.</article-title>
<source>ACM Inroads</source>
<year>2010</year>
<volume>1</volume>
<issue>4</issue>
<fpage>72</fpage>
<lpage>79</lpage>
<comment>
<ext-link ext-link-type="uri" xlink:href="http://doi.org/10.1145/1869746.1869767">http://doi.org/10.1145/1869746.1869767</ext-link>
</comment>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref5">
<label>[5]</label>
<mixed-citation publication-type="book">[5] Radenski, A. (2011). Shared memory, message passing, and hybrid merge sorts for standalone and clustered SMPs. In <italic>Proceedings of the 2011 International Conference on Parallel and Distributed Processing Techniques and Applications (PDPTA’11)</italic> (pp. 367–373).</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Radenski</surname>
<given-names>A.</given-names>
</name>
</person-group>
<source>Proceedings of the 2011 International Conference on Parallel and Distributed Processing Techniques and Applications (PDPTA’11)</source>
<year>2011</year>
<fpage>367</fpage>
<lpage>373</lpage>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref6">
<label>[6]</label>
<mixed-citation publication-type="webpage">[6] Duvanenko, V. (2011). Parallel merge sort. <ext-link ext-link-type="uri" xlink:href="https://duvanenko.tech.blog/2018/01/13/parallel-merge-sort">https://duvanenko.tech.blog/2018/01/13/parallel-merge-sort</ext-link>/</mixed-citation>
<element-citation publication-type="webpage">
<person-group person-group-type="author">
<name>
<surname>Duvanenko</surname>
<given-names>V.</given-names>
</name>
</person-group>
<source>Duvanenko Tech Blog</source>
<year>2011</year>
<comment>
<ext-link ext-link-type="uri" xlink:href="https://duvanenko.tech.blog/2018/01/13/parallel-merge-sort">https://duvanenko.tech.blog/2018/01/13/parallel-merge-sort</ext-link>
</comment>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref7">
<label>[7]</label>
<mixed-citation publication-type="book">[7] Axtmann, M., Bingmann, T., Sanders, P., &amp; Schulz, C. (2015). Practical massively parallel sorting. In <italic>Proceedings of the 27th ACM symposium on Parallelism in Algorithms and Architectures</italic> (pp. 13–23). <ext-link ext-link-type="uri" xlink:href="https://doi.org/10.1145/2755573.2755595">https://doi.org/10.1145/2755573.2755595</ext-link>
</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Axtmann</surname>
<given-names>M.</given-names>
</name>
<name>
<surname>Bingmann</surname>
<given-names>T.</given-names>
</name>
<name>
<surname>Sanders</surname>
<given-names>P.</given-names>
</name>
<name>
<surname>Schulz</surname>
<given-names>C.</given-names>
</name>
</person-group>
<source>Proceedings of the 27th ACM symposium on Parallelism in Algorithms and Architectures</source>
<year>2015</year>
<fpage>13</fpage>
<lpage>23</lpage>
<comment>
<ext-link ext-link-type="uri" xlink:href="https://doi.org/10.1145/2755573.2755595">https://doi.org/10.1145/2755573.2755595</ext-link>
</comment>
</element-citation>
</ref>
<ref id="redalyc_726182578008_ref8">
<label>[8]</label>
<mixed-citation publication-type="book">[8]    Nesmachnow, S., &amp; Iturriaga, S. (2019). Cluster-UY: Collaborative scientific high performance computing in Uruguay. In M. Torres &amp; J. Klapp (Eds.), <italic>Supercomputing </italic>(pp. 188–202). Springer. <ext-link ext-link-type="uri" xlink:href="https://doi.org/10.1007/978-3-030-38043-4_16">https://doi.org/10.1007/978-3-030-38043-4_16</ext-link>
</mixed-citation>
<element-citation publication-type="book">
<person-group person-group-type="author">
<name>
<surname>Iturriaga</surname>
<given-names>S.</given-names>
</name>
<collab>    Nesmachnow, S</collab>
</person-group>
<source>Supercomputing</source>
<year>2019</year>
<fpage>188</fpage>
<lpage>202</lpage>
<comment>
<ext-link ext-link-type="uri" xlink:href="https://doi.org/10.1007/978-3-030-38043-4_16">https://doi.org/10.1007/978-3-030-38043-4_16</ext-link>
</comment>
</element-citation>
</ref>
</ref-list>
</back>
</article>