//******************************************************************************
//
// File: HybridTeam.java
// Package: edu.rit.pj
// Unit: Class edu.rit.pj.HybridTeam
//
// This Java source file is copyright (C) 2010 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
// software; you can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// PJ is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************
package edu.rit.pj;
import edu.rit.mp.IntegerBuf;
import edu.rit.util.Range;
import java.io.IOException;
/**
* Class HybridTeam provides a team of threads, distributed across the processes
* of a cluster parallel program, for executing a {@linkplain WorkerRegion} in
* parallel.
*
* A hybrid team uses a communicator for message passing. The communicator is
* specified as a constructor argument; if not specified, the world communicator
* is used. Every process that is part of the communicator must create the
* hybrid team. In class HybridTeam, there are one or more worker threads per
* process; typically, the number of threads in each process equals the number
* of CPUs on the node executing the process. (To get just one worker thread per
* process, use class {@linkplain WorkerTeam}.) Every worker thread in every
* process has a unique index, going from index 0 for the first thread in the
* first process to index K−1 for the last thread in the last
* process, where K is the total number of worker threads in all the
* processes. In process rank 0, there is an additional master thread.
*
* When a hybrid team is constructed, the processes in the communicator send
* messages amongst themselves to make every process aware of the number of
* worker threads in each process. These messages use a tag of
* Integer.MIN_VALUE. If an I/O error occurs during this message
* passing, the constructor throws an IOException.
*
* To execute a worker region, create a HybridTeam object; create an instance of
* a concrete subclass of class {@linkplain WorkerRegion}; and pass this
* instance to the hybrid team's execute() method. For further
* information, see class {@linkplain WorkerRegion}.
*
* @author Alan Kaminsky
* @version 18-Nov-2009
*/
public class HybridTeam
extends WorkerTeam
{
// Hidden data members.
// Array of lowest worker indexes, indexed by process rank.
int[] lowestIndex;
// Exported constructors.
/**
* Construct a new hybrid team with the default number of threads per
* process and using the world communicator for message passing. If the
* "pj.nt" Java property is specified, that property gives the
* default number of threads per process, which must be an integer greater
* than or equal to 1. If the "pj.nt" Java property is not
* specified, the default number of threads in each process is the value
* returned by the Runtime.availableProcessors() method. You can
* specify the default number of threads per process on the Java command
* line like this:
*
* java -Dpj.nt=4 . . .
*
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if the "pj.nt" property value
* is not an integer greater than or equal to 1.
* @exception IOException
* Thrown if an I/O error occurred.
*/
public HybridTeam()
throws IOException
{
this (getDefaultThreadCount(), Comm.world());
}
/**
* Construct a new hybrid team with the given number of threads per
* process and using the world communicator for message passing.
*
* @param K Number of threads per process.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if K is less than 1.
* @exception IOException
* Thrown if an I/O error occurred.
*/
public HybridTeam
(int K)
throws IOException
{
this (K, Comm.world());
}
/**
* Construct a new hybrid team with the default number of threads per
* process and using the given communicator for message passing. If the
* "pj.nt" Java property is specified, that property gives the
* default number of threads per process, which must be an integer greater
* than or equal to 1. If the "pj.nt" Java property is not
* specified, the default number of threads in each process is the value
* returned by the Runtime.availableProcessors() method. You can
* specify the default number of threads per process on the Java command
* line like this:
*
* java -Dpj.nt=4 . . .
*
*
* @param comm Communicator to use for message passing.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if the "pj.nt" property value
* is not an integer greater than or equal to 1.
* @exception NullPointerException
* (unchecked exception) Thrown if comm is null.
* @exception IOException
* Thrown if an I/O error occurred.
*/
public HybridTeam
(Comm comm)
throws IOException
{
this (getDefaultThreadCount(), comm);
}
/**
* Construct a new hybrid team with the given number of threads per
* process and using the given communicator for message passing.
*
* @param K Number of threads per process.
* @param comm Communicator to use for message passing.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if K is less than 1.
* @exception NullPointerException
* (unchecked exception) Thrown if comm is null.
* @exception IOException
* Thrown if an I/O error occurred.
*/
public HybridTeam
(int K,
Comm comm)
throws IOException
{
// Construct superclass but don't initialize it yet.
super (false);
// Verify preconditions.
if (K <= 0)
{
throw new IllegalArgumentException
("HybridTeam(): K = "+K+" illegal");
}
if (comm == null)
{
throw new NullPointerException
("HybridTeam(): comm is null");
}
// Communicate with the other processes to determine the number of
// worker threads in each process; store these in lowestIndex.
int size = comm.size();
int rank = comm.rank();
lowestIndex = new int [size + 1];
lowestIndex[rank] = K;
IntegerBuf[] bufs =
IntegerBuf.sliceBuffers
(lowestIndex,
new Range (0, size - 1) .subranges (size));
IntegerBuf myBuf = bufs[rank];
comm.allGather (Integer.MIN_VALUE, myBuf, bufs);
// Scan lowestIndex to determine the lowest worker index in each process
// and the total number of worker threads.
int count = 0;
for (int i = 0; i < size; ++ i)
{
int tmp = lowestIndex[i];
lowestIndex[i] = count;
count += tmp;
}
lowestIndex[size] = count;
// Initialize superclass.
initialize
(/*K */ K,
/*comm */ comm,
/*size */ size,
/*rank */ rank,
/*count*/ count,
/*wlb */ lowestIndex[rank]);
}
// Exported operations.
/**
* Determine the default number of threads per process for a hybrid team. If
* the "pj.nt" Java property is specified, that property gives the
* default number of threads per process, which must be an integer greater
* than or equal to 1. If the "pj.nt" Java property is not
* specified, the default number of threads in each process is the value
* returned by the Runtime.availableProcessors() method. You can
* specify the default number of threads per process on the Java command
* line like this:
*
* java -Dpj.nt=4 . . .
*
*
* @return Default number of threads per process for a hybrid team.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if the "pj.nt" property value
* is not an integer greater than or equal to 1.
*/
public static int getDefaultThreadCount()
{
int k = PJProperties.getPjNt();
if (k == 0) k = Runtime.getRuntime().availableProcessors();
return k;
}
/**
* Determine the rank of the process that contains the worker thread with
* the given index.
*
* @param w Worker index.
*
* @return Worker process rank.
*
* @exception IllegalArgumentException
* (unchecked exception) Thrown if w is not in the range 0 ..
* getTotalThreadCount()−1.
*/
public int workerRank
(int w)
{
// Verify preconditions.
if (0 > w || w >= count)
{
throw new IllegalArgumentException
("HybridTeam.workerRank(): w (= "+w+") illegal");
}
// Do a binary search to find w in lowestIndex.
int L = 0;
int U = size;
while (U - L > 1)
{
// Invariant: w >= lowestIndex[L] and w < lowestIndex[U].
int M = (L + U)/2;
if (w >= lowestIndex[M])
{
L = M;
}
else
{
U = M;
}
}
// Assert: L = U-1 and w >= lowestIndex[L] and w < lowestIndex[U].
return L;
}
}
Ads help maintain this website.