/*
Copyright (C) 2009 Diego Darriba
This program 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 2 of the License, or
(at your option) any later version.
This program 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package es.uvigo.darwin.prottest.facade.strategy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import mpi.MPI;
import mpi.Request;
import mpi.Status;
import es.uvigo.darwin.prottest.exe.RunEstimator;
import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
import es.uvigo.darwin.prottest.model.Model;
import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
import es.uvigo.darwin.prottest.util.collection.ModelCollection;
import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
/**
* This strategy distributes the workload in a dynamic way.
*/
public class DynamicDistributionStrategy extends DistributionStrategy {
/** MPJ Tag for requesting a new model. */
private static final int TAG_SEND_REQUEST = 1;
/** MPJ Tag for sending a new model. */
private static final int TAG_SEND_MODEL = 2;
/**
* Instantiates a new dynamic distribution strategy.
*
* @param mpjMe the rank of the current process in MPJ
* @param mpjSize the size of the MPJ communicator
* @param options the application options
* @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
*/
public DynamicDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options, CheckPointManager cpManager) {
super(mpjMe, mpjSize, options, cpManager);
if (mpjSize == 1) {
throw new ProtTestInternalException("Dynamic Distribution Strategy" +
" requires at least 2 processors");
}
itemsPerProc = new int[mpjSize];
displs = new int[mpjSize];
modelSet = new SingleModelCollection(options.getAlignment());
}
/* (non-Javadoc)
* @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#distribute(es.uvigo.darwin.prottest.util.collection.ModelCollection)
*/
public Model[] distribute(ModelCollection arrayListModel, ModelWeightComparator comparator) {
numberOfModels = arrayListModel.size();
Collections.sort(arrayListModel, comparator);
for (Model model : arrayListModel) {
Model[] computedModel = new Model[1];
// getModel request
Request modelRequest = MPI.COMM_WORLD.Irecv(computedModel, 0, 1, MPI.OBJECT, MPI.ANY_SOURCE, TAG_SEND_REQUEST);
// prepare model
Model[] modelToSend = new Model[1];
modelToSend[0] = model;
// wait for request
Status requestStatus = modelRequest.Wait();
if (computedModel[0] != null) {
// set checkpoint
int index = arrayListModel.indexOf(computedModel[0]);
arrayListModel.set(index, computedModel[0]);
setCheckpoint(arrayListModel);
}
// send model
Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1, MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
// update structures
itemsPerProc[requestStatus.source]++;
// wait for send
modelSend.Wait();
}
itemsPerProc[0] = modelSet.size();
displs[0] = 0;
for (int i = 1; i < mpjSize; i++)
displs[i] = displs[i-1] + itemsPerProc[i-1];
// finalize
for (int i = 1; i < mpjSize; i++) {
Model[] computedModel = new Model[1];
Request modelRequest = MPI.COMM_WORLD.Irecv(computedModel, 0, 1, MPI.OBJECT, MPI.ANY_SOURCE, TAG_SEND_REQUEST);
Model[] modelToSend = { null };
// wait for request
Status requestStatus = modelRequest.Wait();
if (computedModel[0] != null) {
// set checkpoint
int index = arrayListModel.indexOf(computedModel[0]);
arrayListModel.set(index, computedModel[0]);
setCheckpoint(arrayListModel);
}
// send null model
Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1, MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
modelSend.Wait();
}
computationDone();
return arrayListModel.toArray(new Model[0]);
}
/* (non-Javadoc)
* @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#request()
*/
public void request() {
startTime = System.currentTimeMillis();
List<RunEstimator> runenvList = new ArrayList<RunEstimator>();
Model[] lastComputedModel = new Model[1];
while (true) {
// send request to root
Request modelRequest = MPI.COMM_WORLD.Isend(lastComputedModel, 0, 1, MPI.OBJECT, 0, TAG_SEND_REQUEST);
// prepare reception
Model[] modelToReceive = new Model[1];
// wait for request
modelRequest.Wait();
// receive model
Request modelReceive = MPI.COMM_WORLD.Irecv(modelToReceive, 0, 1, MPI.OBJECT, 0, TAG_SEND_MODEL);
modelReceive.Wait();
Model model = modelToReceive[0];
if (model == null)
break;
else {
// compute
modelSet.add(model);
RunEstimator runenv =
factory.createRunEstimator(options, model);
runenv.addObserver(this);
if(!runenv.optimizeModel())
throw new ProtTestInternalException("Optimization error");
runenvList.add(runenv);
lastComputedModel[0] = runenv.getModel();
}
}
endTime = System.currentTimeMillis();
}
}