com.powsybl.computation.mpi.MpiComputationManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-computation-mpi Show documentation
Show all versions of powsybl-computation-mpi Show documentation
A computation implementation to run computations with MPI
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.computation.mpi;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.io.WorkingDirectory;
import com.powsybl.computation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
/**
*
* @author Geoffroy Jamgotchian
*/
public class MpiComputationManager implements ComputationManager {
private static final Logger LOGGER = LoggerFactory.getLogger(MpiComputationManager.class);
private static final int LOG_DELAY = 10; // 10 s
private static final int CHUNK_MAX_SIZE = (int) (100 * Math.pow(2, 20)); // 100 Mb
private final Path localDir;
private final MpiExecutorContext executorContext;
private final MpiJobScheduler scheduler;
private Future> busyCoresPrintTask;
public MpiComputationManager(Path localDir, MpiJobScheduler scheduler) {
this(localDir, scheduler, new MpiExecutorContext());
}
public MpiComputationManager(Path localDir, MpiNativeServices nativeServices) throws IOException, InterruptedException {
this(localDir, nativeServices, new NoMpiStatisticsFactory(), null, null, new MpiExecutorContext(), 1, false, null);
}
public MpiComputationManager(Path localDir, MpiStatisticsFactory statisticsFactory, Path statisticsDbDir, String statisticsDbName,
MpiExecutorContext executorContext, int coresPerRank, boolean verbose, Path stdOutArchive) throws IOException, InterruptedException {
this(localDir, new JniMpiNativeServices(), statisticsFactory, statisticsDbDir, statisticsDbName, executorContext,
coresPerRank, verbose, stdOutArchive);
}
public MpiComputationManager(Path localDir, MpiNativeServices nativeServices, MpiStatisticsFactory statisticsFactory,
Path statisticsDbDir, String statisticsDbName, MpiExecutorContext executorContext,
int coresPerRank, boolean verbose, Path stdOutArchive) throws IOException, InterruptedException {
this(localDir, new MpiJobSchedulerImpl(nativeServices, statisticsFactory, statisticsDbDir, statisticsDbName, coresPerRank,
verbose, executorContext.getSchedulerExecutor(), stdOutArchive), executorContext);
}
public MpiComputationManager(Path localDir, MpiJobScheduler scheduler, MpiExecutorContext executorContext) {
this.localDir = Objects.requireNonNull(localDir);
this.executorContext = Objects.requireNonNull(executorContext);
this.scheduler = scheduler;
if (executorContext.getMonitorExecutor() != null) {
busyCoresPrintTask = executorContext.getMonitorExecutor().scheduleAtFixedRate(
() -> LOGGER.info("Busy cores {}/{}, {} tasks/s", scheduler.getResources().getBusyCores(),
scheduler.getResources().getAvailableCores(),
((float) scheduler.getStartedTasksAndReset()) / LOG_DELAY),
0, LOG_DELAY, TimeUnit.SECONDS);
}
}
@Override
public String getVersion() {
return "MPI " + scheduler.getVersion();
}
@Override
public Path getLocalDir() {
return localDir;
}
@Override
public OutputStream newCommonFile(final String fileName) {
// transfer the common file in fixed size chunks
return new OutputStream() {
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
private int chunk = 0;
private void checkSize(boolean last) {
if (last || buffer.size() > CHUNK_MAX_SIZE) {
scheduler.sendCommonFile(new CommonFile(fileName, buffer.toByteArray(), chunk++, last));
buffer.reset();
}
}
@Override
public void write(int b) {
buffer.write(b);
checkSize(false);
}
@Override
public void write(byte[] b) throws IOException {
buffer.write(b);
checkSize(false);
}
@Override
public void write(byte[] b, int off, int len) {
buffer.write(b, off, len);
checkSize(false);
}
@Override
public void flush() throws IOException {
buffer.flush();
}
@Override
public void close() throws IOException {
buffer.close();
checkSize(true);
}
};
}
private static class AsyncContext {
private WorkingDirectory workingDir;
private List parametersList;
private ExecutionReport report;
}
private static final class ExecutionListenerImpl extends DefaultExecutionListener {
private final CommandExecution execution;
private final ExecutionHandler handler;
private ExecutionListenerImpl(CommandExecution execution, ExecutionHandler handler) {
this.execution = execution;
this.handler = handler;
}
@Override
public void onExecutionStart(int fromExecutionIndex, int toExecutionIndex) {
try {
for (int executionIndex = fromExecutionIndex; executionIndex <= toExecutionIndex; executionIndex++) {
handler.onExecutionStart(execution, executionIndex);
}
} catch (Exception e) {
LOGGER.error(e.toString(), e);
}
}
@Override
public void onExecutionCompletion(int executionIndex) {
try {
handler.onExecutionCompletion(execution, executionIndex);
} catch (Exception e) {
LOGGER.error(e.toString(), e);
}
}
}
@Override
public CompletableFuture execute(final ExecutionEnvironment environment,
final ExecutionHandler handler) {
Objects.requireNonNull(environment);
Objects.requireNonNull(handler);
return CompletableFuture
.completedFuture(new AsyncContext())
.thenApplyAsync(ctxt -> before(ctxt, environment, handler), executorContext.getComputationExecutor())
.thenComposeAsync(ctxt -> execute(ctxt, environment, handler), executorContext.getComputationExecutor())
.thenApplyAsync(ctxt -> after(ctxt, handler), executorContext.getComputationExecutor());
}
private AsyncContext before(AsyncContext ctxt, ExecutionEnvironment environment, ExecutionHandler handler) {
try {
ctxt.workingDir = new WorkingDirectory(localDir, environment.getWorkingDirPrefix(), environment.isDebug());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
try {
ctxt.parametersList = handler.before(ctxt.workingDir.toPath());
} catch (Throwable t) {
try {
ctxt.workingDir.close();
} catch (IOException e2) {
LOGGER.error(e2.toString(), e2);
}
throw new PowsyblException(t);
}
return ctxt;
}
private CompletableFuture execute(AsyncContext ctxt, ExecutionEnvironment environment, ExecutionHandler handler) {
CompletableFuture last = null;
for (CommandExecution execution : ctxt.parametersList) {
ExecutionListener l = new ExecutionListenerImpl<>(execution, handler);
if (last == null) {
last = scheduler.execute(execution, ctxt.workingDir.toPath(), environment.getVariables(), l);
} else {
last = last.thenCompose(report -> {
if (report.getErrors().isEmpty()) {
return scheduler.execute(execution, ctxt.workingDir.toPath(), environment.getVariables(), l);
} else {
return CompletableFuture.completedFuture(report);
}
});
}
}
if (last != null) {
return last.thenApply(report -> {
ctxt.report = report;
return ctxt;
});
} else {
ctxt.report = new DefaultExecutionReport(Collections.emptyList());
return CompletableFuture.completedFuture(ctxt);
}
}
private R after(AsyncContext ctxt, ExecutionHandler handler) {
try {
return handler.after(ctxt.workingDir.toPath(), ctxt.report);
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
try {
ctxt.workingDir.close();
} catch (IOException e2) {
LOGGER.error(e2.toString(), e2);
}
}
}
@Override
public ComputationResourcesStatus getResourcesStatus() {
return new MpiComputationResourcesStatus(scheduler.getResources());
}
@Override
public Executor getExecutor() {
return executorContext.getApplicationExecutor();
}
@Override
public void close() {
try {
scheduler.shutdown();
} catch (Exception e) {
LOGGER.error(e.toString(), e);
}
if (busyCoresPrintTask != null) {
busyCoresPrintTask.cancel(true);
}
try {
executorContext.shutdown();
} catch (Exception e) {
LOGGER.error(e.toString(), e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy