1 //****************************************************************************** 2 // 3 // File: CommPattern.java 4 // Package: edu.rit.pj.cluster 5 // Unit: Class edu.rit.pj.cluster.CommPattern 6 // 7 // This Java source file is copyright (C) 2008 by Alan Kaminsky. All rights 8 // reserved. For further information, contact the author, Alan Kaminsky, at 9 // ark@cs.rit.edu. 10 // 11 // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free 12 // software; you can redistribute it and/or modify it under the terms of the GNU 13 // General Public License as published by the Free Software Foundation; either 14 // version 3 of the License, or (at your option) any later version. 15 // 16 // PJ is distributed in the hope that it will be useful, but WITHOUT ANY 17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 18 // A PARTICULAR PURPOSE. See the GNU General Public License for more details. 19 // 20 // Linking this library statically or dynamically with other modules is making a 21 // combined work based on this library. Thus, the terms and conditions of the GNU 22 // General Public License cover the whole combination. 23 // 24 // As a special exception, the copyright holders of this library give you 25 // permission to link this library with independent modules to produce an 26 // executable, regardless of the license terms of these independent modules, and 27 // to copy and distribute the resulting executable under terms of your choice, 28 // provided that you also meet, for each linked independent module, the terms 29 // and conditions of the license of that module. An independent module is a module 30 // which is not derived from or based on this library. If you modify this library, 31 // you may extend this exception to your version of the library, but you are not 32 // obligated to do so. If you do not wish to do so, delete this exception 33 // statement from your version. 34 // 35 // A copy of the GNU General Public License is provided in the file gpl.txt. You 36 // may also obtain a copy of the GNU General Public License on the World Wide 37 // Web at http://www.gnu.org/licenses/gpl.html. 38 // 39 //****************************************************************************** 40 package edu.rit.pj.cluster; 41 42 import java.util.ArrayList; 43 44 /** 45 * Class CommPattern provides static methods for calculating communication 46 * patterns for collective communication operations. 47 * 48 * @author Alan Kaminsky 49 * @version 15-Mar-2008 50 */ 51 public class CommPattern { 52 53 // Prevent construction. 54 private CommPattern() { 55 } 56 57 // Exported operations. 58 /** 59 * Calculate the communication pattern for a parallel broadcast tree. This 60 * is also used in reverse for a parallel reduction tree. 61 * 62 * @param size Size of the communicator. Must be >= 1. 63 * @param rank Rank of this process in the communicator. Must be in the 64 * range 0 .. <code>size</code>-1. 65 * @param root Rank of the root process for the broadcast. Must be in the 66 * range 0 .. <code>size</code>-1. 67 * @return Array of process ranks for the parallel broadcast pattern. The 68 * element at index 0 is the parent process rank, or -1 if there is no 69 * parent process. The elements at indexes 1 and above, if any, are the 70 * child process ranks. 71 * @exception IllegalArgumentException (unchecked exception) Thrown if any 72 * argument is illegal. 73 */ 74 public static int[] broadcastPattern(int size, 75 int rank, 76 int root) { 77 // Verify preconditions. 78 if (size < 1) { 79 throw new IllegalArgumentException("broadcastPattern(): size must be >= 1"); 80 } 81 if (0 > rank || rank >= size) { 82 throw new IllegalArgumentException("broadcastPattern(): rank must be in the range 0 .. " 83 + (size - 1)); 84 } 85 if (0 > root || root >= size) { 86 throw new IllegalArgumentException("broadcastPattern(): root must be in the range 0 .. " 87 + (size - 1)); 88 } 89 90 // Imagine for the moment that the processes are numbered 1 through K, 91 // where K = size. The broadcast communication pattern takes place in a 92 // number of rounds. The rounds are numbered 1, 2, 4, 8, and so on. In 93 // round 1, process 1 sends to process 2. In round 2, processes 1 and 2 94 // send to processes 3 and 4 in parallel. In round 4, processes 1, 2, 3, 95 // and 4 send to processes 5, 6, 7, and 8 in parallel: 96 // 97 // Process 98 // 1 2 3 4 5 6 7 8 99 // | | | | | | | | 100 // | | | | | | | | 101 // |--->| | | | | | | Round 1 102 // | | | | | | | | 103 // | | | | | | | | 104 // |-------->| | | | | | Round 2 105 // | |-------->| | | | | 106 // | | | | | | | | 107 // | | | | | | | | 108 // |------------------>| | | | Round 4 109 // | |------------------>| | | 110 // | | |------------------>| | 111 // | | | |------------------>| 112 // | | | | | | | | 113 // | | | | | | | | 114 // 115 // In general, in round i, processes 1 through i send to processes 1+i 116 // through i+i in parallel. This continues until there are no more 117 // processes to send to. 118 // 119 // After calculating the above pattern, the process numbers are shifted 120 // such that process 1 becomes process root, process 2 becomes process 121 // root+1, and so on. In general, process i becomes process (i+root-1) 122 // (mod size). 123 // This process's rank relative to the root, in the range 1 .. size. 124 int thisrank 125 = rank >= root 126 ? rank - root + 1 127 : rank + size - root + 1; 128 129 // Parent process. 130 int parent = -1; 131 132 // List of child processes. 133 ArrayList<Integer> childlist = new ArrayList<Integer>(); 134 135 // Do all rounds. 136 int round = 1; 137 while (round < size) { 138 // Do all messages within this round. 139 for (int src = 1; src <= round; ++src) { 140 int dst = src + round; 141 142 // If this process is the destination, record source as parent. 143 if (thisrank == dst) { 144 parent = src; 145 } // If this process is the source, record destination as child. 146 else if (thisrank == src && dst <= size) { 147 childlist.add(dst); 148 } 149 } 150 151 // Next round. 152 round <<= 1; 153 } 154 155 // Make an array to hold parent and child processes. 156 int n = childlist.size(); 157 int[] result = new int[n + 1]; 158 159 // Record parent, offsetting rank. 160 result[0] = parent == -1 ? -1 : (parent + root - 1) % size; 161 162 // Record children, offsetting ranks. 163 for (int i = 0; i < n; ++i) { 164 result[i + 1] = (childlist.get(i) + root - 1) % size; 165 } 166 167 // All done! 168 return result; 169 } 170 171 // Unit test main program. 172 // /** 173 // * Unit test main program. 174 // * <P> 175 // * Usage: java edu.rit.pj.cluster.CommPattern <I>size</I> <I>rank</I> 176 // * <I>root</I> 177 // */ 178 // public static void main 179 // (String[] args) 180 // { 181 // if (args.length != 3) usage(); 182 // int size = Integer.parseInt (args[0]); 183 // int rank = Integer.parseInt (args[1]); 184 // int root = Integer.parseInt (args[2]); 185 // int[] pattern = CommPattern.broadcastPattern (size, rank, root); 186 // System.out.print ("broadcastPattern (size="); 187 // System.out.print (size); 188 // System.out.print (", rank="); 189 // System.out.print (rank); 190 // System.out.print (", root="); 191 // System.out.print (root); 192 // System.out.print (") returns {"); 193 // System.out.print (pattern[0]); 194 // for (int i = 1; i < pattern.length; ++ i) 195 // { 196 // System.out.print (", "); 197 // System.out.print (pattern[i]); 198 // } 199 // System.out.println ("}"); 200 // } 201 // 202 // /** 203 // * Print a usage message and exit. 204 // */ 205 // private static void usage() 206 // { 207 // System.err.println ("Usage: java edu.rit.pj.cluster.CommPattern <size> <rank> <root>"); 208 // System.exit (1); 209 // } 210 }