1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.21">
<TITLE> S-Lang PVM Module Reference: Examples</TITLE>
<LINK HREF="pvm-4.html" REL=next>
<LINK HREF="pvm-2.html" REL=previous>
<LINK HREF="pvm.html#toc3" REL=contents>
</HEAD>
<BODY>
<A HREF="pvm-4.html">Next</A>
<A HREF="pvm-2.html">Previous</A>
<A HREF="pvm.html#toc3">Contents</A>
<HR>
<H2><A NAME="s3">3.</A> <A HREF="pvm.html#toc3">Examples</A></H2>
<P>This section presents examples of two alternate methods of
using the PVM module. The source code for these examples is
included in the <CODE>PVM</CODE> module source code distribution
in the <CODE>examples</CODE> subdirectory. The first method uses PVM
library routines to manage a simple distributed application.
The second method uses the higher-level master-slave
interface. This interface can provide a high degree of
tolerance to failure of slave machines which proves useful in
long-running distributed applications.</P>
<H2><A NAME="ss3.1">3.1</A> <A HREF="pvm.html#toc3.1">Example 1: A Simple <I>Hello World</I> Program</A>
</H2>
<P>In programming language tutorials, the first example is
usually a program which simply prints out a message such as
<I>Hello World</I> and then exits. The intent of such a trivial
example is to illustrate all the steps involved in writing and
running a program in that language.</P>
<P>To write a <I>Hello World</I> program using the PVM module, we will
write two programs, the master (
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_master</A>), and the
slave (
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_slave</A>). The master process will spawn a
slave process on different host and then wait for a message
from that slave process. When the slave runs, it sends a
message to the master, or parent, and then exits. For the
purpose of this example, we will assume that the PVM consists
of two hosts, named <CODE>vex</CODE> and <CODE>pirx</CODE>, and that the
slave process will run on <CODE>pirx</CODE>.</P>
<H3>The <CODE>hello_master</CODE> program</H3>
<P>First, consider the master process,
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_master</A>.
Conceptually, it must specify the full path to the slave
executable and then send that information to the slave host
(<CODE>pirx</CODE>). For this example, we assume that the
master and slave executables are in the same directory and
that the master process is started in that directory. With
this assumption, we can construct the path to the slave
executable using the <CODE>getcwd</CODE> and <CODE>path_concat</CODE>
functions. We then send this information to the slave host
using the <CODE>pvm_spawn</CODE> function:
<BLOCKQUOTE><CODE>
<PRE>
path = path_concat (getcwd(), "hello_slave");
slave_tid = pvm_spawn (path, PvmTaskHost, "pirx", 1);
</PRE>
</CODE></BLOCKQUOTE>
The first argument to <CODE>pvm_spawn</CODE> specifies the full path
to the slave executable. The second argument is a bit mask
specifying options associated with spawning the slave process.
The <CODE>PvmTaskHost</CODE> option indicates that the slave process
is to be started on a specific host. The third argument gives
the name of the slave host and the last argument indicates how
many copies of this process should be started. The return
value of <CODE>pvm_spawn</CODE> is an array of task identifiers for
each of the slave processes; negative values indicate that an
error occurred.</P>
<P>Having spawned the
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_slave</A> process on <CODE>pirx</CODE>,
the master process calls the <CODE>pvm_recv</CODE> function to
receive a message from the slave.
<BLOCKQUOTE><CODE>
<PRE>
bufid = pvm_recv (-1, -1);
</PRE>
</CODE></BLOCKQUOTE>
The first argument to <CODE>pvm_recv</CODE> specifies the task
identifier of the slave process expected to send the message
and the second argument specifies the type of message that is
expected. A slave task identifier <CODE>-1</CODE> means that a
message from any slave will be accepted. Similarly, a message
identifier of <CODE>-1</CODE> means that any type of message will be
accepted. In this example, we could have specified
the slave task id and the message identifier explicitly:
<BLOCKQUOTE><CODE>
<PRE>
bufid = pvm_recv (slave_tid, 1);
</PRE>
</CODE></BLOCKQUOTE>
When a suitable message is received, the contents of the
message are stored in a PVM buffer and <CODE>pvm_recv</CODE> returns
the buffer identifier which may be used by the PVM application
to retrieve the contents of the buffer.</P>
<P>Retrieving the contents of the buffer normally requires
knowing the format in which the information is stored. In this
case, because we accepted all types of messages from the
slave, we may need to examine the message buffer to find out
what kind of message was actually recieved. The
<CODE>pvm_bufinfo</CODE> function is used to obtain information
about the contents of the buffer.
<BLOCKQUOTE><CODE>
<PRE>
(,msgid,) = pvm_bufinfo (bufid);
</PRE>
</CODE></BLOCKQUOTE>
Given the buffer identifier, <CODE>pvm_bufinfo</CODE> returns the
number of bytes, the message identifier and the task identifer
sending the message.</P>
<P>Because we know that the slave process sent a single object of
<CODE>Struct_Type</CODE>, we retrieve it by calling the
<CODE>pvm_recv_obj</CODE> function.
<BLOCKQUOTE><CODE>
<PRE>
variable obj = pvm_recv_obj();
vmessage ("%s says %s", obj.from, obj.msg);
</PRE>
</CODE></BLOCKQUOTE>
This function is not part of the PVM package but is a higher
level function provided by the <CODE>PVM</CODE> module. It
simplifies the process of sending <B>S-lang</B> objects between hosts
by handling some of the bookkeeping required by the lower
level PVM interface. Having retrieved a <B>S-lang</B> object from
the message buffer, we can then print out the message.
Running
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_master</A>, we see:
<BLOCKQUOTE><CODE>
<PRE>
vex> ./hello_master
pirx says Hello World
</PRE>
</CODE></BLOCKQUOTE>
Note that before exiting, all PVM processes should call the
<CODE>pvm_exit</CODE> function to inform the <CODE>pvmd</CODE> daemon of
the change in PVM status.
<BLOCKQUOTE><CODE>
<PRE>
pvm_exit();
exit(0);
</PRE>
</CODE></BLOCKQUOTE>
At this point, the script may exit normally.</P>
<H3>The <CODE>hello_slave</CODE> program</H3>
<P>Now, consider the slave process,
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/hello_master">hello_slave</A>.
Conceptually, it must first determine the location of its
parent process, then create and send a message to that
process.</P>
<P>The task identifier of the parent process is obtained using
the <CODE>pvm_parent</CODE> function.
<BLOCKQUOTE><CODE>
<PRE>
variable ptid = pvm_parent();
</PRE>
</CODE></BLOCKQUOTE>
For this example, we will send a message consisting of a
<B>S-lang</B> structure with two fields, one containing the name of
the slave host and the other containing the string
<CODE>"Hello World"</CODE>.</P>
<P>We use the <CODE>pvm_send_obj</CODE> function to send this this
message because it automatically handles packaging all the
separate structure fields into a PVM message buffer and also
sends along the structure field names and data types so that
the structure can be automatically re-assembled by the
receiving process. This makes it possible to write code which
transparently sends <B>S-lang</B> objects from one host to
another. To create and send the structure:
<BLOCKQUOTE><CODE>
<PRE>
variable s = struct {msg, from};
s.msg = "Hello World";
s.from = getenv ("HOST");
pvm_send_obj (ptid, 1, s);
</PRE>
</CODE></BLOCKQUOTE>
The first argument to <CODE>pvm_send_obj</CODE> specifies the task
identifier of the destination process, the second argument is
a message identifier which is used to indicate what kind of
message has been sent. The remaining arguments contain the
data objects to be included in the message.</P>
<P>Having sent a message to the parent process, the slave process
then calls <CODE>pvm_exit</CODE> to inform the <CODE>pvmd</CODE> daemon
that its work is complete. This allows <CODE>pvmd</CODE> to notify
the parent process that a slave process has exited. The slave
then exits normally.</P>
<H2><A NAME="ss3.2">3.2</A> <A HREF="pvm.html#toc3.2">Example 2: Using the Master-Slave Interface</A>
</H2>
<P>The <CODE>PVM</CODE> module provides a higher level interface to
support the master-slave paradigm for distributed
computations. The symbols associated with this interface have
the <CODE>pvm_ms</CODE> prefix to distinguish them from those
symbols associated with the PVM package itself.</P>
<P>The <CODE>pvm_ms</CODE> interface provides a means for handling
computations which consist of a predetermined list of tasks
which can be performed by running arbitrary slave processes
which take command-line arguments. The interface provides a
high degree of robustness, allowing one to add or delete hosts
from the PVM while the distributed process is running and also
ensuring that the task list will be completed even if one or
more slave hosts fail (e.g. crash) during the computation.
Experience has shown that this failure tolerance is
surprisingly important. Long-running distributed computations
experience failure of one or more hosts with surprising
frequency and it is essential that such failures do not
require restarting the entire distributed computation from the
beginning.</P>
<P>Scripts using this interface must initialize it by loading
the <CODE>pvm_ms</CODE> package via, e.g.
<BLOCKQUOTE><CODE>
<PRE>
require ("pvm_ms");
</PRE>
</CODE></BLOCKQUOTE>
As an example of how to use this interface, we examine the
scripts
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">master</A> and
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">slave</A>.</P>
<H3>The <CODE>master</CODE> program</H3>
<P>The
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">master</A> script first builds a list of tasks each
consisting of an array of strings which provide the command
line for each slave process that will be spawned on the PVM.
For this simple example, the same command line will be
executed a specified number of times. First, the script
constructs the path to the
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">slave</A> executable,
(<CODE>Slave_Pgm</CODE>), and then the command line (<CODE>Cmd</CODE>), that
each
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">slave</A> instance will invoke. Then the array of
tasks is constructed:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
variable pgm_argvs = Array_Type[N];
variable pgm_argv = [Slave_Pgm, Cmd];
pgm_argvs[*] = pgm_argv;
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>The distribution of these tasks across the available PVM is
automatically handled by the <CODE>pvm_ms</CODE> interface. The
interface will simultaneously start as many tasks as possible
up to some maximum number of processes per host. Here we
specify that a maximum of two processes per host may run
simultaneously and then submit the list of tasks to the PVM:</P>
<P>
<BLOCKQUOTE><CODE>
<PRE>
pvm_ms_set_num_processes_per_host (2);
exit_status = pvm_ms_run_master (pgm_argvs);
</PRE>
</CODE></BLOCKQUOTE>
</P>
<P>As each slave process is completed, its exit status is
recorded along with any messages printed to <CODE>stdout</CODE>
during the execution. When the entire list of tasks is
complete, an array of structures is returned containing status
information for each task that was executed. In this example,
the
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">master</A> process simply prints out this information.</P>
<H3>The <CODE>slave</CODE> program</H3>
<P>The
<A HREF="http://space.mit.edu/cxc/software/slang/modules/pvm/examples/master">slave</A> process in this example is relatively simple.
Its command line arguments provide the task to be completed.
These arguments are then passed to <CODE>pvm_ms_run_slave</CODE>
<BLOCKQUOTE><CODE>
<PRE>
pvm_ms_run_slave (__argv[[1:]]);
</PRE>
</CODE></BLOCKQUOTE>
which spawns a subshell, runs the specified command,
communicates the task completion status to the parent process
and exits.</P>
<HR>
<A HREF="pvm-4.html">Next</A>
<A HREF="pvm-2.html">Previous</A>
<A HREF="pvm.html#toc3">Contents</A>
</BODY>
</HTML>
|