Friday, April 26, 2013

Raspberry Pi work Picked up by the Raspberry Pi Foundation

The Raspberry Pi Foundation has picked up Dave Soriano's Chemical Ecology work.  The article and video can be seen here.  I have setup a Pi for him that connects to our wireless network and streams his work to Bambuser.com using some of the information I have made available here on my blog.  The Raspberry Pi is great for this work because Pitt's wireless infrastructure requires 802.1x authentication, which most web cams do not provide.  A wireless card and a little configuration with the wpa supplicant were a great solution.  Great work Dave!

Wednesday, April 17, 2013

Flipping Coins: A demonstration of the PERL MPI Libraries

The Parallel::MPI module for PERL allows a programmer to take advantage of the Message Passing Interface (MPI) to perform parallel programming operations.  While studying this library, I wrote the following simple routine to both udnerstand and demonstrate MPI functions within perl.  I present it here as a brief tutorial in the use of the Parallel::MPI module.  This script was run on a cluster of 2 to 32 Raspberry Pi's.

The basic premise is flipping a coin a million times.  Except instead of flipping a coin, I generate a random value between 0 and 1.  If the value is less than or equal to .5 is is a head, if larger it is a tail.  As a serial operation, this could take quite a while.  However, if we parallelize this process, each member will take a subset of the one million flips (one million devided by the number of nodes) and report back the its results when done.  The master node then tallies up the number of heads and tails reported by each node to produce a final result.  In a perfect world, this should be 50% heads and 50% tails, but as the random function is not completely random, these values will vary and we calculate an error based on that.


First we begin by loading the Parallel::MPI model and Sys::Hostname.  The latter allows us to retrieve the hostname of the node executing the code, which can be beneficial for debugging purposes.

#!/usr/bin/perl
# Initialize the Libraries
use Parallel::MPI qw(:all);
use Sys::Hostname;

 Next we initialize the MPI Library.
MPI_Init();
Now we initialize some variables.  MPI_COMM_WORLD is a communication string that all nodes use for communicating with one another.  This can be called whatever you would like, but MPI_COMM_WORLD is what is referenced in the documentation.  These variables are xecuted on each node and hold node specific information. 
  • $numprocs holds the total number of nodes in the cluster.  
  • $myid holds the id within the cluster starting with 0.  The last value of $myid will be 1 less than the number of nodes.  
  • $name stores the node name.
# Get the number of nodes in the cluster
$numprocs = MPI_Comm_size(MPI_COMM_WORLD);
# Determine each members ID
$myid =     MPI_Comm_rank(MPI_COMM_WORLD);
# Determine each members hostname
$name = hostname;

print "Process $myid of $numprocs on $name\n";
Node 1 starts the timer using the MPI_Wtime function and is used later in combination with the end time to determine the total time required to process the problem.  This is helpful in demonstrating the benefits of adding a node to the cluster.  
if ($myid==0) {$startwtime = MPI_Wtime();}
Now we need to initialize some variables.
  • $iterations holds the number of times we will flip the coin.
  • $heads stores the number of heads.
  • $tails stores the number of tails.
$iterations=1000000;
$heads=0;

$tails=0;

We now generate a counter ($i) that increments by the number of nodes ($numprocs) and increases until the number of iterations ($iterations) is reached.  What this means is that for a cluster of four computers, node 0 will start at 0 and at its next iteration $i will be 4, then 8, and so on.  Similarly node 1 will start at 1 and $i will be 5 at the second iteration, then 9 and so on.  Each node will continue this way until the value of $iterations (one million) is reached.  For each iteration, $x is assigned a random value between 0 and 1.  If $x is less then .5 the number of heads on this node is incremented by one.  If it is larger than or equal to .5 the number of tails is incremented by 1.
for ($i=$myid;$i<$iterations;$i+=$numprocs) {
 $x=rand();
 if ($x<=.5) {
  $heads=$heads+1;
 } else {$tails=$tails+1;}

}
For debugging purposes I print the Node id and number of heads and tails it computed.
print "Heads on $myid: $heads Tails on $myid: $tails\n\n";


Now check the ID of the node.  If this is not Node 0, we will populate an array (@info) with the total number of heads calculated by this nodes ($heads) as the first element of the array and the total number of tails ($tails) as the second.  The MPI_Send function is the utilized to send this information to Node 0.  The syntax is as follows: MPI_SEND(VALUE,Number of values,Data_type,Node to send to,Communication Tag, Communication label). So in this code I am sending @info as the value, @info contains 2 values, they are of MPI_INT data type, are being sent to Node 0, with a tag of 1, on the MPI_COMM_WORLD communication label.
if ($myid!=0) {
  @info[0]=$heads;
  @info[1]=$tails;
  MPI_Send(\@info,2,MPI_INT,0,1,MPI_COMM_WORLD);
Now we set $headcnt equal to the number of heads calculated by Node 0 and $tailcnt equal to the number of tails calculated by Node 0.  These values will be added to the totals calculated by other nodes shortly. For Node 0 we set $x at 1 and increase $x by 1 until we reach the number of nodes in the cluster ($numprocs).  For each value of $x, Node 0 issues an MPI_Recv, to receive the data sent from the section of code above.  The syntax here is MPI_Recv(value, number of values, data type,node number,tag, communication label).  So below we are storing the received values in @info, are receiving 2 values, data type is MPI_INT, receiving from the node number currently stored in $x, tag is 1, and communication label is MPI_COMM_WORLD.  Once the values are received we add them to the current totals for $headcnt and $tailcnt respectively.
else {
    $headcnt=$heads;
    $tailcnt=$tails;
    for($x=1;$x<$numprocs;$x++) {
    MPI_Recv(\@info,2,MPI_INT,$x,1,MPI_COMM_WORLD);
    $headcnt=$headcnt+@info[0];
    $tailcnt=$tailcnt+@info[1];
  }
}
Now that the calculations have completed MPI_Wtime() is used to get a current timestamp.  This will be used to calculated elapsed time later on.  MPI_Barrier is called to halt processing until all nodes complete communication, and MPI_Finalize ends the MPI session.
$endwtime = MPI_Wtime();
MPI_Barrier(MPI_COMM_WORLD);
MPI_Finalize();
Now on Node 0, we calculate the elapsed time and store it in $time, calculate the percent error for heads and tails and the print the results.  As additional members are added to the cluster, the overall time to complete the processing will be seen to decrease.
if ($myid==0) {
  $time=$endwtime-$startwtime;
  $headerror=abs(($headcnt-$iterations/2)/$headcnt*100);
  $tailerror=abs(($tailcnt-$iterations/2)/$tailcnt*100);
  print "Heads Count: $headcnt Tails Count: $tailcnt\n";
  print "Head Error: $headerror% Tail Error: $tailerror%\n";
  print "Time: $time\n\n";
}

The above script is calle dusing the mpiexec program via a command similar to the following:

mpiexec -f ~/mpi_testing/machinefile -np 2 ~/scripts/flip.pl 1

  • ~/mpi_testing/machinefile is a list of ip addresses of all participating nodes.  One address per line.
  • -np 2 states to use two nodes for the calculation
  • ~/scripts/flip.pl is the path to the program to be run. 
Sample output can be seen below:

I hope this script helps to demonstrate and clarify some of the MPI functions and uses within the Parallel::MPI PERL module.

Wednesday, April 3, 2013

Raspberry Pi Thin Client for Apache VCL (Virtual Computing Lab)

Apache VCL is a broker for remote access to virtual computing resources.  The system allows a user to reserve a virtual computer and remotely access it via the RDP protocol.  When a reservation is made, the VCL server connects to a VMware server, configures a virtual machine based on the image selected by the user and assigns it to the user for the requested period.

Currently, students in the CIST program at Pitt-Bradford utilize their personal computers to access this virtual lab under a pilot program developed by Aaron Bryant.  With my current research into the Raspberry Pi and its uses, I wanted to see if it could be utilized as a thin client for the Apache VCL system.  I was not surprised to find that a thin client image for the Raspberry Pi was already underway at the Raspberry Pi Thin Client Project.  I have taken their image and modified it to produce a thin client kiosk allowing a student to log into the VCL web interface, reserve a machine, and access it all in about two minutes (including the minute it takes the VCL system to provision the virtual machine).  Once the remote desktop session to the reserved virtual machine is initiated, the experience is the same as if the session was started from a standard desktop computer.

I currently have USB redirection working and am working on printer redirection over the RDP protocol.  The major challenge I faced was getting the browser to automatically open the RDP file to initiate the connection.  I was unable to find a Remote Desktop application for linux that could be associated with and automatically open the file (if you know of one, please let me know).  Instead I wrote a PERL script to parse the RDP file and feed the necessary information to rdesktop and its various switches.  I ran into a bit of difficulty with the username and password, but finally after opening the file in a hex editor, I discovered there were non-printable characters at the end of each line and was able to strip them from the string using a regular expression for the hex values of these characters.

Once the image is finalized,  I will post full instructions along with PERL script to parse the RDP file.