\documentclass[twocolumn]{article}
% \documentclass{article}

\setlength{\oddsidemargin}{-0.5in}
\setlength{\evensidemargin}{-0.5in}
\setlength{\topmargin}{0.0in}
\setlength{\headheight}{0in}
\setlength{\headsep}{0in}
\setlength{\textwidth}{7.0in}
\setlength{\textheight}{9.5in}
\setlength{\parindent}{0in}
\setlength{\parskip}{0.05in}
\setlength{\columnseprule}{0.3pt}

\setlength\columnsep{25pt}

\usepackage{fancyvrb}
\usepackage{relsize}
\usepackage{hyperref}

\usepackage{listings}
\usepackage{amsmath}

\begin{document}

\lstset{xleftmargin=5mm,framexleftmargin=10mm,basicstyle=\footnotesize}

Name: \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

Directions: {\bf \Large Work only on this sheet} (on both sides, if
needed).  MAKE SURE TO COPY YOUR ANSWERS TO A SEPARATE SHEET FOR SENDING
ME AN ELECTRONIC COPY LATER.

{\bf Important note:}  Remember that in problems calling for R code, you
are allowed to use any built-in R function, e.g. {\bf choose()}, {\bf
sum()}, {\bf combn()} etc.  

{\bf 1.} There are various high-level threads access systems other than
OpenMP.  One of them is a language called Cilk++, developed at MIT and
purchased by Intel.  Judging from the names of the Cilk++ constructs below,
give names of OpenMP or pthreads constructs that should roughly
correspond.

\begin{itemize}

\item [(a)] (5) {\bf cilk\_for}

\item [(b)] (5) {\bf cilk::reducer\_opadd}

\item [(c)] (5) {\bf cilk::mutex}

\item [(d)] (5) {\bf cilk\_spawn} (a dictionary definition of {\it spawn}:
``to produce or create something'')

\end{itemize}

{\bf 2.} (10) Explain briefly why R's {\bf snow} library would be a poor
choice---essentially an impossible one---for pipelined parallel
algorithms such as in our MPI example, Sec. 1.3.3.2.

{\bf 3.} Consider the in-place matrix transposition code in Sec.
4.3.4.

\begin{itemize}

\item [(a)] (10) Fill in the blank:  Since each thread works on
completely separate elements of the matrix, there ``should'' not be a
lot of cache coherency transactions.  But there probably will be, due to
the problem of \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_.

\item [(b)] (10) Give a potential improvement to one (1) line of the code.

\end{itemize}

{\bf 4.} (10) Consider the Dijkstra example, pp.71ff.  Suppose that in
the end, shortest distances from vertex 0 to vertex i are roughly
correlated with i, i.e. vertices with larger values of i tend to be
further from 0.  Comment on performance issues that would likely arise.
Cite certain variables and/or lines so that it is clear that you
understand the issues, but be brief.  As usual, you are limited to a
single, hopefully not very long, line.

{\bf 5.} (40) The function below is written in R, but could be applied to
any scheduling situation; it is merely an analytical tool.  The call
form is {\bf statictime(tasktms,nth)}, where we have {\bf nth} threads,
and {\bf tasktms} are the task times, assumed here to be known in
advance.  

Say for instance we have 6 tasks, needing times {\bf tasktms[1]} through
{\bf tasktms[6]}, and 2 threads.  We would have some kind of parallel
{\bf for} loop, iterating {\bf i} through 1 to 6; one thread would
handle some values of {\bf i}, and the other thread would handle the
others.

Here we assume the {\bf static} scheduling algorithm used by OpenMP, and
the function will return the time needed to complete all the tasks.
Fill in the blanks.

\vskip 1in

\begin{lstlisting}
statictime <- function(tasktms,nth) {
   n <- length(tasktms)
   a1ton <- 1:n
   endtimes <- vector(length=nth)
   for (i in 1:nth) {
      # determine which tasks thread i will handle
      if (i != nth) {
         this1does <- 
            # blank (a)
      } else 
         this1does <- 
            # blank (b)
      # blank (c)
   }
   # blank (d)
}
\end{lstlisting}


\onecolumn

\newpage

{\bf Solutions:}

{\bf 1.a} OMP {\bf for} pragma

{\bf 1.b} OMP {\bf reduction} clause, with '+'

{\bf 1.c} {\bf pthread\_mutex\_lock()}

{\bf 1.d}  {\bf pthread\_create()}

{\bf 2.}  It would be impossible to get parallelism this way, without
direct communication between the workers.

{\bf 3.a} false sharing

{\bf 3.b} One could try special scheduling, say {\bf dynamic}, on line
12.

{\bf 4.} Entry of the vertices into the {\bf nondone} array will roughly
occur in order of i, so that soon the low-numbered threads have little
or no work to do in line 54.

{\bf 5.} The problem was in part incorrectly specified, as it assumed
(without saying so) a chunk size of 1.  The code below is written under
that assumption.

In actuality, the default for {\bf static} scheduling is to divide the
iterations in approximately equal-sized chunks.  In our situation here,
we could fill blank (a) with

\begin{lstlisting}
((i-1) * floor(n/nth) + 1):(i * floor(n/nth)
\end{lstlisting}

and do something similar for blank (b).

This does not affect the answers to blanks (c) and (d).

\begin{lstlisting}
statictime <- function(tasktms,nth) {
   n <- length(tasktms)
   a1ton <- 1:n
   endtimes <- vector(length=nth)
   for (i in 1:nth) {
      # determine which tasks thread i will handle
      if (i != nth) {
         this1does <- 
            which(a1ton %% nth == i)   
      } else 
         this1does <- 
            which(a1ton %% nth == 0)   
      endtimes[i] <- sum(tasktms[this1does])
   }
   max(endtimes)
}

\end{lstlisting}

\end{document}

source("umul.R")

c2 <- makeCluster(2)

