<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Comparative Debugging of Parallel DVMH-programs</article-title>
      </title-group>
      <contrib-group>
        <aff id="aff0">
          <label>0</label>
          <institution>Keldysh Institute of Applied Mathematics</institution>
          ,
          <addr-line>Miusskaya sq., 4, 125047, Moscow</addr-line>
          ,
          <country country="RU">Russia</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Lomonosov Moscow State University</institution>
          ,
          <addr-line>GSP-1, Leninskie Gory, 119991, Moscow</addr-line>
          ,
          <country country="RU">Russia</country>
        </aff>
      </contrib-group>
      <fpage>0000</fpage>
      <lpage>0003</lpage>
      <abstract>
        <p>DVM-system is designed for the development of parallel programs of scientific and technical calculations in C-DVMH and Fortran-DVMH languages. These languages use a single parallel programming model (DVMH model) and are extensions of the standard C and Fortran languages with parallelism specifications, written in the form of directives to the compiler. The DVMH model makes it possible to create efficient parallel programs for heterogeneous computing clusters, in the nodes of which accelerators (graphic processors or Intel Xeon Phi coprocessors) can be used as computing devices along with universal multi-core processors. The article describes the method of debugging parallel programs in DVM-system, as well as new features of DVMdebugger.</p>
      </abstract>
      <kwd-group>
        <kwd>Automation of Development of Parallel Programs</kwd>
        <kwd>Automation of Debugging of Parallel Programs</kwd>
        <kwd>DVM-system</kwd>
        <kwd>Accelerator</kwd>
        <kwd>GPU</kwd>
        <kwd>Fortran</kwd>
        <kwd>С</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>Classic debugging approaches may not always be helpful when it comes to parallel
programming. A step-by-step study of the executing process at certain breakpoints or
debug prints are hardly applicable to real scientific and engineering parallel software
systems designed for continuous execution for hours or even days.</p>
      <p>Parallel algorithms are usually much more complicated than sequential solutions of
the same problems. Moreover, the parallel code may contain atypical for sequential
debugging errors associated with the incorrect use of synchronization primitives and
functions that provide parallelism.</p>
      <p>The following factors affect the complexity of debugging parallel programs:
 the necessity to track the status of several (or even many) parallel
processes/threads;
 the difficulty of reproducing errors caused by non-deterministic
execution;
 the debugging tools influence on the execution process (different
execution time of the operators, additional internal synchronizations).</p>
      <p>Copyright © 2020 for this paper by its authors.</p>
      <p>Use permitted under Creative Commons License Attribution 4.0 International (CC BY 4.0).</p>
      <p>
        To debug parallel programs, automated methods have been developed. Such
methods allow to find most errors in the program in automatic mode with minimal
involvement of the programmer. One of these methods is the dynamic correctness
control. This method is used in many debugging tools for multithreaded programs, such
as: Helgrind [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], DRD [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ], Intel Parallel Inspector [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]. In the DVM-system, this
method is used to debug parallel programs made for heterogeneous clusters.
      </p>
      <p>
        Another automated debugging method is the comparative debugging of parallel
programs. The main principle of this method is to compare the execution process of
two programs, by controlling the values of variables at certain controlled points.
Comparison can be carried out either between simultaneously running programs, or
using trace files, which store all the necessary data about operations and variable
values at controlled points. This debugging method was implemented in the Guard [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]
and Wizard [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ] debuggers. The term "comparative debugging" was introduced in the
articles describing these tools. Around the same time, this method was also
implemented in the debugger of the DVM-system.
      </p>
      <p>In the Guard and Wizard debuggers, the controlled points at which the variable
values are compared are setting by the user. In contrast, in the DVM-debugger,
comparison points are setting automatically.</p>
      <p>This article briefly describes the approaches for DVMH-programs debugging,
pictures the problems that had arose during the use of DVM-system comparative
debugging implementation, and suggests new methods to overcome these problems.
2</p>
    </sec>
    <sec id="sec-2">
      <title>Approaches for Debugging Parallel DVMH programs</title>
      <p>
        To identify errors that lead to incorrect calculations, the DVM-system [
        <xref ref-type="bibr" rid="ref6 ref7 ref8">6-8</xref>
        ] contains
various special tools for automating the debugging process. Such errors can be
detected by executing a DVMH-program in the dynamic correctness control mode and/or
by starting computations on one or several processors in a comparing mode with the
reference results obtained during its sequential execution.
      </p>
      <p>
        The use of automated debugging methods requires the instrumentation of a parallel
program: insertion of special calls to the debugger that allow to control and process
execution of a program. There are two approaches for such instrumentation: binary
code instrumentation and source code instrumentation. Helgrind, DRD, Intel Parallel
Inspector are based on binary instrumentation. But the use of high-level programming
models (such as OpenMP [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ]), can lead to certain difficulties with that approach.
      </p>
      <p>For example, instrumentation utility must restore the parallelism specifications
from binary code of the program in order to be able to generate errors in the context
of the source code of that program. To make this possible, the instrumentation utility
must know the internal logic of the compiler. If both compiler and debugger are made
by the same developer (e.g. Intel), then such recovery can be implemented. But when
the compiler is developed by one company (e.g. Microsoft), and the debugger is by
another (e.g. Intel), then recovering of parallelism specifications can be difficult. This
problem can be avoided by using the source code instrumentation.</p>
      <p>
        Debugging instrumentation of programs in DVM-system is performed by
CDVMH [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] and Fortran-DVMH [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] compilers, which add calls to DVM-debugger
functions at the following points of the program:
 beginning of a sequential or parallel cycle;
 completion of a sequential or parallel cycle;
 beginning of a new iteration of a cycle;
 accessing a variable for reading;
 before accessing a variable for writing;
 after accessing a variable for writing.
      </p>
      <p>
        In addition, the debugger functions are also performed while executing calls to the
Lib-DVMH library [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ].
      </p>
      <p>Dynamic correctness control of DVMH-directives is based on an analysis of the
sequence of calls to Lib-DVMH functions and accesses to variables. Dynamic control
is allowing to detect the following types of errors:
 undeclared data dependency in a parallel loop;
 incorrect use of private and reduction variables;
 undeclared access to non-local elements of a distributed array;
 incorrect work with shadow edges of reduction arrays modification of
non-local elements of a distributed array in the sequential part of the
program;
 going out of bounds in distributed array;
 writing data to the remote access buffer.</p>
      <p>It should be mentioned that not all errors can be determined by the dynamic
correctness control. For example, external procedures and functions without any source
code cannot be analyzed. The comparative debugging method can be used in order to
check such programs. This method will be discussed in detail in the next section.
3</p>
    </sec>
    <sec id="sec-3">
      <title>Comparative Debugging of DVMH-programs</title>
      <p>The intermediate results comparison implemented in DVM-system allows to detect
errors in parallel programs that arise due to incorrect DVMH instructions, as well as
program errors that do not appear in sequential execution and were not detected by
the dynamic control method.</p>
      <p>The general scheme of comparative debugging method is as follows:
1. Getting a reference trace (./dvm trc command in console interface). Trace
contains: readings and modifications of variables, the beginning of each
loop iteration, the beginning and end of parallel and sequential loops, the
beginning of each parallel task, the beginning and end of the task group.
The source for reference trace can be either the sequential execution of the
same program or parallel execution (e.g. the trace recorded on the
different computing cluster where the error does not occur);
2. Automatic comparison of program execution results with previously
accumulated reference trace (./dvm dif command). All integer numbers is
compared strictly and real numbers are compared with a given absolute
&lt;line&gt;}
&lt;line&gt;}
&lt;line&gt;}
and relative accuracy. Information on the all discrepancies is reported to
user.
&lt;trace context info (OS architecture, working directories)&gt;
MODE = &lt;NONE | MINIMAL | MODIFY | FULL&gt;
&lt;SL | PL | TR&gt; &lt;structure number&gt; (&lt;parent structure number&gt;)
[&lt;loop rank&gt;] {&lt;file&gt;, &lt;line&gt;} = &lt;NONE | MINIMAL | MODIFY | FULL&gt;,
(&lt;dimension&gt;:&lt;first iteration&gt;, &lt;last iteration&gt;, &lt;loop step&gt;), …
EL: &lt;structure number&gt;
…
&lt;SL | PL | TR&gt; &lt;structure number&gt; (&lt;parent structure number&gt;)
[&lt;loop rank&gt;] {&lt;file&gt;, &lt;line&gt;} = &lt;NONE | MINIMAL | MODIFY | FULL&gt;,
(&lt;dimension&gt;:&lt;first iteration&gt;, &lt;last iteration&gt;, &lt;loop step&gt;), …
EL: &lt;structure number&gt;
END_HEADER</p>
      <p>Reference trace file is created for each process and has a text format. This file
starts with the special header that contains used trace parameters and hierarchy of
loops and task groups (see Fig. 1).</p>
      <p>- reading variable:
RD: [&lt;type of variable&gt;] &lt;name of variable&gt; = &lt;value&gt;; {&lt;file&gt;,
- before modification of variable:
BW: [&lt;type of variable&gt;] &lt;name of variable&gt;; {&lt;file&gt;, &lt;line&gt;}
- after modification of variable:
AW: [&lt;type of variable&gt;] &lt;name of variable&gt; = &lt;value&gt;; {&lt;file&gt;,
- reading reduction variable:</p>
      <p>RV_RD: [&lt;type of variable&gt;] &lt;name of variable&gt; = &lt;value&gt;;
{&lt;file&gt;, &lt;line&gt;}
- before modification of reduction variable:
RV_BW: [&lt;type of variable&gt;] &lt;name of variable&gt;; {&lt;file&gt;,
- after modification of reduction variable:</p>
      <p>RV_AW: [&lt;type of variable&gt;] &lt;name of variable&gt; = &lt;value&gt;;
{&lt;file&gt;, &lt;line&gt;}
- final result of reduction operation:
RV: [&lt;type of variable&gt;] &lt;value&gt;; {&lt;file&gt;, &lt;line&gt;}</p>
      <p>Fig. 2. Trace records format (variables)
- beginning of parallel loop:</p>
      <p>PL: &lt;structure number&gt; (&lt;parent structure number&gt;) [&lt;loop
rank&gt;]; {&lt;file&gt;, &lt;line&gt;}
- beginning of sequential loop:</p>
      <p>SL: &lt;structure number&gt; (&lt;parent structure number&gt;) [&lt;loop rank
(always equals 1)&gt;]; {&lt;file&gt;, &lt;line&gt;}</p>
      <p>- beginning of task group:
TR: &lt;structure number&gt; (&lt;parent structure number&gt;) [&lt;group rank (always
equals 1)&gt;]; {&lt;file&gt;, &lt;line&gt;}
- next loop iteration of parallel task:</p>
      <p>IT: &lt;absolute index of iteration (calculated from values of all
index variables of the cycle) or task number&gt;, (&lt;value of 1st index
variable&gt;,&lt; value of 2nd index variable&gt;,…).</p>
      <p>- end of loop (parallel or sequential):
EL: &lt;structure number&gt;; {&lt;file&gt;, &lt;line&gt;}
- end of the local calculations block in the sequential part of
the program:</p>
      <p>SKP: {&lt;file&gt;, &lt;line&gt;}</p>
      <p>Global trace details level can be set by modifying the value of the MODE
parameter in the trace header. Details level can also be specified for each cycle and task
group of the DVMH-program by setting the corresponding mode in the line that
describes the desired structure in the header.</p>
      <p>The main body of the trace contains a sequence of specific records. These records
determine the dynamic structure of the program: the sequence of statements during
the concrete execution of the program. Fig. 2 and 3 provide a complete list of events
that are recorded in the trace.</p>
      <p>#define L 3
int main(int an, char **as)
{
#pragma dvm array distribute[block]
double A[L];
#pragma dvm parallel([i] on A[i])
for (int i = 0; i &lt; L; i++)
{
if (i == 0 || i == L - 1)</p>
      <p>A[i] = 0;
else</p>
      <p>A[i] = 2 + i;
}
return 0;
}</p>
      <p>Fig. 4. C-DVMH example program (file “test.c”)</p>
    </sec>
    <sec id="sec-4">
      <title>Issues with the Current Comparative Debugger</title>
      <p>
        After instrumentation, each operator of debugged program is surrounded by several
calls to debugging library, so it is not surprising that execution time can increase
significantly. For example, in experiments with benchmark programs from the NAS
NPB package [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ], the following results were obtained:
 the slowdown only from debugging instrumentation (i.e. the program was
compiled for debugging, but executed without collecting/comparing the
trace) was around 50–100 times;
 trace file size (several dozens of bytes for each traced operator) turned out
to be completely unacceptable for real programs. The average size of full
trace for benchmark program was measured in terabytes, and the
approximate time for collecting the trace is ~28000 sec. (with an average runtime
of the initial programs of ~5 sec., i.e., a ~4000 times deceleration).
      </p>
      <p>
        Therefore, full comparative debugging turned out to be applicable only on small
"model" data, which are not always available. To overcome this problem, the
following control and optimization tools were developed and implemented in the
DVMsystem debugger [
        <xref ref-type="bibr" rid="ref12">12</xref>
        ]:
 selective tracing: only modifications, only distributed arrays, etc.
(compilation options -d1...-d4);
 local instrumentation, i.e. manual selection of program sections, that will
be instrumented for debugging (directives DEBUG &lt;debug mode&gt; / END
DEBUG);
 preliminary estimation of the trace size by obtaining the trace header, and
its manual correction to disable tracing of certain loops or iterations
(command ./dvm size);
 automatic selection of parallel loops iterations for tracing: “borders” and
“corners” (compilation options -dbif1 and -dbif2);
 generation of two cycle bodies: one without debugger calls, the other is
instrumented; the instrumented loop body is used only on selected
iterations, and the original program is executed on the rest;
 recording the checksums of arrays at the end of the loop instead of tracing
modifications of their elements in the body of the loop (parameter
TraceOptions.CalcChecksums).
      </p>
      <p>Described improvements extend the possibility of applying comparative debugging
to real applications. For example, when processing large amounts of data through
loops, the most probable place for errors occurrence (going out of the array bounds,
uninitialized variables) will be boundary iterations. Moreover, the usual structure of
computational algorithms is causes that an error occurred at the internal iteration of
the loop will propagate to the boundaries. For such tasks, selective tracing and
comparing of boundary iterations can be used (-dbif&lt;level&gt; options), which allows (see
Table 1):
 significantly reduce the size of the trace (100-1000 times);
 significantly reduce the execution time (10-1000 times);
 preserve most coverage of program operators (over 99%).</p>
      <p>Average
execution
time, sec
27915
(7,75 h.)
15
19
105
287</p>
      <p>But, despite all optimizations, use of comparative debugging for scientific and
technical algorithms, especially on real data (rather than on artificially created small
"model" tests) is still very restricted.</p>
      <p>Another problem detected during the practical usage of the debugging system was
the “allowable” mismatch of the real variables values. Most notable case was with
reduction variables. The calculation of the sum of the distributed array elements
changes depending on the the parallel program configuration: firstly local sums are
calculated, and then they are combined in non-deterministic order. Results of such
computations are slightly different (usually in the 1-2 minor digits), but, from the user
point of view, resulting values are be equally valid. Reduction operations create four
problems for comparative debugging (“false alarms”):
 the intermediate values of the reduction variable do not coincide at all,
because only partial sums (maximum values, etc.) are calculated;
 the final value of variable, as mentioned above, may slightly differ
(nondeterminism in the weak sense);
 the difference in one variable can immediately spread to many others (for
example, if the norm of a vector is calculated and then the vector is
normalized);
 if the variable, that was influenced by the difference in the reduction
results, is used as the condition for ending iterations or choosing a branch of
calculations, then comparing programs can diverge at that condition
(nondeterminism in the strong sense).</p>
      <p>These problems were solved by introducing a special reduction processing mode:
 reduction variables are recognized (because they are described in
DVMHdirectives), and trace records of their reading and modification in the body
of the loop are ignored by comparative debugger;
 at the end of the parallel cycle, the final value of the reduction variable
(RV trace record) is added into the trace for further comparison;
 the values of the reduction variables are compared with some accuracy,
which may be less than the accuracy of comparing the values of ordinary
variables. This accuracy can be set by the programmer through a special
configuration parameter;
 during the comparison the actual calculated value of the reduction
variable (after successful comparison with the given accuracy) is replaced by
its value from the “reference” trace to eliminate the potentially dangerous
discrepancy.</p>
      <p>
        The described approach made it possible to suppress the “false alarms” associated
with reduction variables. However, it was further discovered that this problem can
appear not only on reduction computations. Executing a program on different
machines or using different compilation tools can leads to different results of any
arithmetic operation, such as multiplication or division (in 1–2 minor decimal digits of the
mantissa) [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ].
5
      </p>
    </sec>
    <sec id="sec-5">
      <title>New Approaches to Comparative Debugging</title>
      <p>
        Currently, a new version of the comparative debugging system is in development
[
        <xref ref-type="bibr" rid="ref14">14</xref>
        ], aimed to overcome described problems. The new debugger will be based not on
trace files, but on the exchange of debug information between two simultaneously
running instances of the program:
1. program execution will be divided into computational blocks, the order of
which is deterministic for any parallel system configuration;
2. during the execution of the next block, each instance of the debugged
program will be accumulating needed trace records;
3. upon completion of the block, the accumulated traces will be sent to one
process for comparison.
      </p>
      <p>The DVMH parallel model is making it possible to split any program into a
deterministic sequence of blocks split by the boundaries of parallel loops.</p>
      <p>Proposed extension will support all previously implemented optimizations of the
trace size (array checksums and boundary iterations), since all changes made by these
optimizations affect the trace locally, within a specific parallel cycle, and therefore,
within one specific block of the new trace.</p>
      <p>Described approach makes comparative debugging more flexible, allowing the
simultaneous launch of the reference and debugged programs on one multiprocessor
machine and remote debugging – comparing the execution of the reference program
on one machine with an experimental version running on another.</p>
      <p>Splitting a parallel DVMH program into deterministic blocks has one more
advantage – the values of all variables at the block boundary should be identical
regardless of the number of processes and their configuration. Therefore, the block
boundaries can be used as controlled points for comparative debugging, instead of tracing
each operation of reading and modifying variables. In this case, all calculations within
a certain block will be carried out without additional costs for collecting the trace, and
values of all variables that was read and/or modified during its execution will be
collected and compared at the end of block.</p>
      <p>The current implementation of the debugger already includes a special mode based
on a similar principle: all calculations intended for execution on graphics accelerator
can be also simultaneously performed on the central processor and then compared. In
case of discrepancies, the needed information is reported to the user. After that, only
results computed on central processor is used for further computations.</p>
      <p>Enabling and using this comparative debugging mode does not require the user to
make any changes to the program, or even re-compile it. All that is needed is to set
the value of the environment variable DVMH_COMPARE_DEBUG to 1, or use the
./dvm cmph command to start the execution of the program.</p>
      <p>Also, to address the problem of discrepancy between the results of operations with
real numbers, the new version of the debugger includes a mode that extends already
described approach of correcting reduction variables to all results of real operations
(configuration parameter TraceOptions.SubstAllResults). After successfully
comparing a real variable with a reference value from trace, this reference will be substituted
into the running program and used for further calculations.</p>
      <p>This correction approach excludes the possibility of applying the trace size
optimizations described above, since both the array checksums and the boundary iterations
do not cover a significant part of the modifications of variables inside of parallel
cycles. Therefore, in order to ensure the possibility of debugging real scientific and
technical algorithms with this mode, it is recommended to use it in conjunction with
the comparison of simultaneously running programs.
6</p>
    </sec>
    <sec id="sec-6">
      <title>Conclusion</title>
      <p>DVM-system was designed to automate the process of developing parallel programs.</p>
      <p>Parallel programs with DVMH-directives can be efficiently (and without any
additional changes) executed on clusters of various architectures including multi-core
universal processors, graphics accelerators and Intel Xeon Phi coprocessors. This is
achieved through various optimizations that are performed both statically (during
compilation), and dynamically.</p>
      <p>An important advantage of the DVM-system is the powerful tools for debugging
developed DVMH-programs. These tools include the dynamic correctness control and
the comparative debugging. Various instrumentation options were implemented for
optimizing the process of debugging.</p>
      <p>This article presented the problems that arose during the practical use of
comparative debugging implemented in DVM-system, and suggested ways to overcome these
problems.</p>
      <p>Currently, a new version of the comparative debugging system is being developed,
in which both the reference and the debugged program are executed simultaneously
and the comparison of the calculation results is carried out directly in the process of
execution. The new version of the debugging system will help to solve described
problems with accuracy of computations, make the debugging process more flexible
and less demanding to the memory of the computing system.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <surname>Helgrind</surname>
          </string-name>
          <article-title>: a thread error detector</article-title>
          , http://www.valgrind.org/docs/manual/hg-manual.html,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <given-names>DRD</given-names>
            <surname>:</surname>
          </string-name>
          <article-title>a thread error detector</article-title>
          , http://www.valgrind.org/docs/manual/drd-manual.html,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <given-names>Intel</given-names>
            <surname>Inspector</surname>
          </string-name>
          . Memory and Thread Debugger, https://software.intel.com/en-us/intelinspector, last accessed
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <given-names>Guard</given-names>
            <surname>Parallel Relative Debugger</surname>
          </string-name>
          , http://sourceforge.net/projects/guardsoft/,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <surname>Abramson</surname>
            ,
            <given-names>D.A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Sosic</surname>
          </string-name>
          , R.:
          <article-title>Relative Debugging using Multiple Program Versions</article-title>
          .
          <source>In: Intensional Programming I. Sydney: World Scientific</source>
          (
          <year>1995</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <string-name>
            <surname>C-DVMH language</surname>
          </string-name>
          ,
          <article-title>C-DVMH compiler, compilation, execution and debugging of DVMH programs</article-title>
          , http://dvm-system.
          <article-title>org/static_data/docs/CDVMH-reference-en</article-title>
          .pdf,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <string-name>
            <surname>Fortran</surname>
            <given-names>DVMH</given-names>
          </string-name>
          langauge,
          <article-title>Fortran DVMH compiler, compilation, execution and debugging of DVMH programs</article-title>
          , http://dvm-system.
          <article-title>org/static_data/docs/FDVMH-user-guide-en</article-title>
          .pdf,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <article-title>Lib-DVM library</article-title>
          , http://www.keldysh.ru/dvm/dvmhtm1107/eng/sys/libdvm/rtsDDe0.html
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <source>OpenMP Application Programming Interface. Version 5</source>
          .0.
          <string-name>
            <surname>November</surname>
          </string-name>
          ,
          <year>2018</year>
          , https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-
          <volume>5</volume>
          .0.pdf,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <article-title>The OpenACC Application Programming Interface</article-title>
          .
          <source>Version 2</source>
          .6.
          <string-name>
            <surname>November</surname>
          </string-name>
          ,
          <year>2017</year>
          , https://www.openacc.org/sites/default/files/inline-files/OpenACC.2.6.final.pdf,
          <source>last accessed</source>
          <year>2019</year>
          /11/21.
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>11. NAS Parallel Benchmarks, http://www.nas.nasa.gov/publications/npb.html</mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          12.
          <string-name>
            <surname>Krukov</surname>
            ,
            <given-names>V.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Kudryavtsev</surname>
          </string-name>
          , М.:
          <article-title>Automated debugging of parallel programs</article-title>
          .
          <source>Vychisl. Metody Programm</source>
          .,
          <volume>7</volume>
          (
          <issue>4</issue>
          ),
          <fpage>102</fpage>
          -
          <lpage>110</lpage>
          (
          <year>2006</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          13.
          <string-name>
            <surname>Monniaux</surname>
            ,
            <given-names>D.</given-names>
          </string-name>
          :
          <article-title>The pitfalls of verifying floating-point computations</article-title>
          .
          <source>ACM Transactions on Programming Languages and Systems (TOPLAS)</source>
          , ACM,
          <volume>30</volume>
          (
          <issue>3</issue>
          ), pp.
          <volume>12</volume>
          (
          <year>2008</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          14.
          <string-name>
            <surname>Ermichev</surname>
            ,
            <given-names>A.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Krjukov</surname>
            ,
            <given-names>V.</given-names>
          </string-name>
          :
          <article-title>Razvitie metoda sravnitel'noj otladki DVMH-programm</article-title>
          . In:
          <article-title>Nauchnyj servis v seti Internet: trudy XIX Vserossijskoj nauchnoj konferencii</article-title>
          , pp.
          <fpage>150</fpage>
          -
          <lpage>156</lpage>
          , Moscow, IPM im. M.V.
          <string-name>
            <surname>Keldysha</surname>
          </string-name>
          (
          <year>2017</year>
          ), https://doi.org/10.20948/abrau-2017-15.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>