001/* 002 * $Id: MPJEngine.java 4748 2014-02-12 23:25:15Z kredel $ 003 */ 004 005package edu.jas.kern; 006 007 008import java.io.IOException; 009import java.util.ArrayList; 010import java.util.Arrays; 011 012import mpi.Comm; 013import mpi.Intracomm; 014import mpi.MPI; 015import mpi.MPIException; 016import mpi.Status; 017 018import org.apache.log4j.Logger; 019 020 021/** 022 * MPI engine, provides global MPI service. <b>Note:</b> could eventually be 023 * done directly with MPI, but provides logging. <b>Usage:</b> To obtain a 024 * reference to the MPI service communicator use 025 * <code>MPJEngine.getComminicator()</code>. Once an engine has been created it 026 * must be shutdown to exit JAS with <code>MPJEngine.terminate()</code>. 027 * @author Heinz Kredel 028 */ 029 030public final class MPJEngine { 031 032 033 private static final Logger logger = Logger.getLogger(MPJEngine.class); 034 035 036 private static final boolean debug = logger.isDebugEnabled(); 037 038 039 /** 040 * Command line arguments. Required for MPI runtime system. 041 */ 042 protected static String[] cmdline; 043 044 045 /** 046 * Hostnames of MPI partners. 047 */ 048 public static ArrayList<String> hostNames = new ArrayList<String>(); 049 050 051 /** 052 * Flag for MPI usage. <b>Note:</b> Only introduced because Google app 053 * engine does not support MPI. 054 */ 055 public static boolean NO_MPI = false; 056 057 058 /** 059 * Number of processors. 060 */ 061 public static final int N_CPUS = Runtime.getRuntime().availableProcessors(); 062 063 064 /* 065 * Core number of threads. 066 * N_CPUS x 1.5, x 2, x 2.5, min 3, ?. 067 */ 068 public static final int N_THREADS = (N_CPUS < 3 ? 3 : N_CPUS + N_CPUS / 2); 069 070 071 /** 072 * MPI communicator engine. 073 */ 074 static Intracomm mpiComm; 075 076 077 /** 078 * MPI engine base tag number. 079 */ 080 public static final int TAG = 11; 081 082 083 /** 084 * Hostname suffix. 085 */ 086 public static final String hostSuf = "-ib"; 087 088 089 // /* 090 // * Send locks per tag. 091 // */ 092 // private static SortedMap<Integer,Object> sendLocks = new TreeMap<Integer,Object>(); 093 094 095 // /* 096 // * receive locks per tag. 097 // */ 098 // private static SortedMap<Integer,Object> recvLocks = new TreeMap<Integer,Object>(); 099 100 101 /** 102 * No public constructor. 103 */ 104 private MPJEngine() { 105 } 106 107 108 /** 109 * Set the commandline. 110 * @param args the command line to use for the MPI runtime system. 111 */ 112 public static synchronized void setCommandLine(String[] args) { 113 cmdline = args; 114 } 115 116 117 /** 118 * Test if a pool is running. 119 * @return true if a thread pool has been started or is running, else false. 120 */ 121 public static synchronized boolean isRunning() { 122 if (mpiComm == null) { 123 return false; 124 } 125 //if (MPI.Finalized()) { // FMPJ only 126 // return false; 127 //} 128 return true; 129 } 130 131 132 /** 133 * Get the MPI communicator. 134 * @return a Communicator constructed for cmdline. 135 */ 136 public static synchronized Comm getCommunicator() throws IOException { 137 if (cmdline == null) { 138 throw new IllegalArgumentException("command line not set"); 139 } 140 return getCommunicator(cmdline); 141 } 142 143 144 /** 145 * Get the MPI communicator. 146 * @param args the command line to use for the MPI runtime system. 147 * @return a Communicator. 148 */ 149 public static synchronized Comm getCommunicator(String[] args) throws IOException { 150 if (NO_MPI) { 151 return null; 152 } 153 if (mpiComm == null) { 154 //String[] args = new String[] { }; //"-np " + N_THREADS }; 155 if (!MPI.Initialized()) { 156 if (args == null) { 157 throw new IllegalArgumentException("command line is null"); 158 } 159 cmdline = args; 160 args = MPI.Init(args); 161 //int tl = MPI.Init_thread(args,MPI.THREAD_MULTIPLE); 162 logger.info("MPI initialized on " + MPI.Get_processor_name()); 163 //logger.info("thread level MPI.THREAD_MULTIPLE: " + MPI.THREAD_MULTIPLE 164 // + ", provided: " + tl); 165 if (debug) { 166 logger.debug("remaining args: " + Arrays.toString(args)); 167 } 168 } 169 mpiComm = MPI.COMM_WORLD; 170 int size = mpiComm.Size(); 171 int rank = mpiComm.Rank(); 172 logger.info("MPI size = " + size + ", rank = " + rank); 173 // maintain list of hostnames of partners 174 hostNames.ensureCapacity(size); 175 for (int i = 0; i < size; i++) { 176 hostNames.add(""); 177 } 178 String myhost = MPI.Get_processor_name(); 179 if (myhost.matches("\\An\\d*")) { // bwGRiD node names n010207 180 myhost += hostSuf; 181 } 182 if (myhost.matches("kredel.*")) { 183 myhost = "localhost"; 184 } 185 hostNames.set(rank, myhost); 186 if (rank == 0) { 187 String[] va = new String[1]; 188 va[0] = hostNames.get(0); 189 mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); 190 for (int i = 1; i < size; i++) { 191 Status stat = mpiComm.Recv(va, 0, va.length, MPI.OBJECT, i, TAG); 192 if (stat == null) { 193 throw new IOException("no Status received"); 194 //throw new MPIException("no Status received"); 195 } 196 int cnt = stat.Get_count(MPI.OBJECT); 197 if (cnt == 0) { 198 throw new IOException("no Object received"); 199 //throw new MPIException("no object received"); 200 } 201 String v = va[0]; 202 hostNames.set(i, v); 203 } 204 logger.info("MPI partner host names = " + hostNames); 205 } else { 206 String[] va = new String[1]; 207 mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); 208 hostNames.set(0, va[0]); 209 va[0] = hostNames.get(rank); 210 mpiComm.Send(va, 0, va.length, MPI.OBJECT, 0, TAG); 211 } 212 } 213 return mpiComm; 214 } 215 216 217 /** 218 * Stop execution. 219 */ 220 public static synchronized void terminate() { 221 if (mpiComm == null) { 222 return; 223 } 224 //if (MPI.Finalized()) { // FMPJ only 225 // return; 226 //} 227 try { 228 logger.info("terminating MPI on rank = " + mpiComm.Rank()); 229 mpiComm = null; 230 MPI.Finalize(); 231 } catch (MPIException e) { 232 e.printStackTrace(); 233 } 234 } 235 236 237 /** 238 * Set no MPI usage. 239 */ 240 public static synchronized void setNoMPI() { 241 NO_MPI = true; 242 terminate(); 243 } 244 245 246 /** 247 * Set MPI usage. 248 */ 249 public static synchronized void setMPI() { 250 NO_MPI = false; 251 } 252 253 254 // /* 255 // * Get send lock per tag. 256 // * @param tag message tag. 257 // * @return a lock for sends. 258 // */ 259 // public static synchronized Object getSendLock(int tag) { 260 // tag = 11; // one global lock 261 // Object lock = sendLocks.get(tag); 262 // if ( lock == null ) { 263 // lock = new Object(); 264 // sendLocks.put(tag,lock); 265 // } 266 // return lock; 267 // } 268 269 270 // /* 271 // * Get receive lock per tag. 272 // * @param tag message tag. 273 // * @return a lock for receives. 274 // */ 275 // public static synchronized Object getRecvLock(int tag) { 276 // Object lock = recvLocks.get(tag); 277 // if ( lock == null ) { 278 // lock = new Object(); 279 // recvLocks.put(tag,lock); 280 // } 281 // return lock; 282 // } 283 284 285 // /* 286 // * Wait for termination of a mpj Request. 287 // * @param req a Request. 288 // * @return a Status after termination of req.Wait(). 289 // */ 290 // public static Status waitRequest(final Request req) { 291 // if ( req == null ) { 292 // throw new IllegalArgumentException("null request"); 293 // } 294 // int delay = 10; 295 // int delcnt = 0; 296 // Status stat = null; 297 // while (true) { 298 // synchronized (MPJEngine.class) { // global static lock 299 // stat = req.Get_status(); // should be non destructive, but is not 300 // if ( stat != null ) { 301 // return req.Wait(); // should terminate immediately 302 // } 303 // } 304 // try { 305 // Thread.currentThread().sleep(delay); // varied a bit 306 // } catch (InterruptedException e) { 307 // logger.info("sleep interrupted"); 308 // e.printStackTrace(); 309 // } 310 // delcnt++; 311 // if ( delcnt % 7 == 0 ) { 312 // delay++; 313 // System.out.println("delay(" + delay + "): " + Thread.currentThread().toString()); 314 // } 315 // } 316 // } 317 318}