grams is MPI (MPI Forum, 1993). There are more
solutions that have proved their value with great suc-
cess, but even in the case these useful tools are com-
patible with our programming language and running
environment, more inconvenients still can appear.
An obstacle that dramatically increases the com-
plexity to adapt sequential programs appears when
global variables are extensively used in legacy appli-
cations. In these situations, if using multiple threads
running at different instructions of the same process,
it is quite complicated to ensure the correct access
to these variables and avoid race conditions. When
correct access order is not ensured, applications are
said to be non-thread-safe. This is quite common
in large legacy applications that have been growing
for years while increasing its funcionality. An ex-
ample of this, with more than 10 years of evolu-
tion, is the R language interpreter. A different prac-
tical obstacle appears when observing the mainte-
nance lifecycle of legacy applications. After years
of proved utility it is logical to expect a long life
span. Introducing an external dependency on a piece
of software that later on may get discontinued can
cause serious problems in the future. Another legal
obstacle is found between incompatible software li-
censes. For example, many open-source tools are
published using the GNU General Public License
GPL (GNU Software Foundation, Inc., 2007). Al-
though partially solved with the Lesser GPL license,
the former prevents the usage of these GPL licensed
tools together with propietarysoftware licenses which
were commonly adopted by earlier legacy applica-
tions. Finally, a pragmatic problem comes with the re-
quired skills to perform such transformations or adap-
tations. It is common for scientists to program their
own applications. Although when implementing their
algorithms, they produce high quality applications,
without specific background on software engineering
and parallel computing, this process of transforma-
tion, due to the lack of knowledge and experience, is
very cumbersome and error-prone.
In this paper we expose our research experiences
creating a solution to support multicore systems in
the R language. The outcome is an add-on R pack-
age called
R/parallel
(Vera et al., 2008). Its con-
ception initiates after the need of providing parallel
support for the R language interpreter, a non-thread-
safe C coded legacyapplication. The next sections de-
scribe the reasons and motivations that have directed
our design decisions and implementation details in or-
der to allow other developers, with equivalent needs
and conditions, to adopt a similar solution. Besides
of providing a technical description of an explicit par-
allelism method to enable the usage of multicore pro-
cessors and assist other legacy application maintain-
ers, we also describe with more detail our extension of
the R language interpreter, including the experimental
results that have allowed us to validate our implemen-
tation. This second contribution also provides assis-
tance to enable parallel computing, but in this case
providing a simple parallelization method that any R
user, using an implicit parallelism method, and with-
out aditional programming skills, can use to run his or
her R scripts.
2 DESIGN CONSIDERATIONS
The design of a solution to provide parallel computing
capabilities in single thread legacy applications like
the R language interpreter is constrained by the prob-
lems exposed previously in the introduction section.
Language interpreters are a good example of pro-
grams that have evolve considerably over time. Their
implementations can be grouped into two different
approaches observing how they handle the global
variablesshared between differentconcurrentthreads:
share all or share nothing. The share all approach
has the advantage that any variable is directly ac-
cessible at any time. However, since the access has
to be controlled continuously with global locks, its
performance falls down with an increasing number
of parallel threads. The second approach, in con-
trast, shares nothing unless explicitly defined. This
imposes more work for the programmer but results
in better scalability. This approach has been used
by many language interpreters like python, erlang
or perl. In fact, the perl implementation of threads
switched from the share all to the share nothing ap-
proach in version 5.8.0 (The Perl Foundation, 2002)
to overcome the poor performance of its earlier im-
plementations. With this second implementation the
scalability is dramatically increased although the se-
quential access to shared variables is still a bottleneck.
The interpreter implementations, besides of
choosing a share nothing approach, can be classified
into two additional groups. One group implements
dedicated user level threads to manage the shared re-
sources, also known as green threads, while the other
delegates its control to native system calls at kernel
level, known as native threads. The first option has
the advantage, on single processor computers, that
since the controlling thread has specific knowledge
about their own family threads, its expected perfor-
mance should be greater than if managed by general
purpose kernels, which have no knowledge about the
future requirements of the threads being scheduled.
However, the common disadvantage, since all user-
TOWARDS THE EVOLUTION OF LEGACY APPLICATIONS TO MULTICORE SYSTEMS - Experiences Parallelizing
R
251