All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rinde.rinsim.experiment.LocalComputer Maven / Gradle / Ivy

There is a newer version: 4.4.6
Show newest version
/*
 * Copyright (C) 2011-2016 Rinde van Lon, iMinds-DistriNet, KU Leuven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.rinde.rinsim.experiment;

import static com.google.common.base.Verify.verifyNotNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.rinde.rinsim.experiment.Experiment.Builder;
import com.github.rinde.rinsim.experiment.Experiment.SimArgs;
import com.github.rinde.rinsim.experiment.Experiment.SimulationResult;
import com.github.rinde.rinsim.experiment.PostProcessor.FailureStrategy;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

final class LocalComputer implements Computer {
  static final Logger LOGGER = LoggerFactory.getLogger(LocalComputer.class);
  static final long THREAD_SLEEP_TIME_MS = 10L;
  static final long MAX_WAIT_FOR_SHUTDOWN_S = 10L;

  LocalComputer() {}

  @Override
  public ExperimentResults compute(Builder builder, Set inputs) {
    final ImmutableList.Builder runnerBuilder =
      ImmutableList.builder();
    for (final SimArgs args : inputs) {
      runnerBuilder.add(new ExperimentRunner(args));
    }

    final List runners = runnerBuilder.build();

    final int threads = Math.min(builder.numThreads, runners.size());
    final ListeningExecutorService executor;
    if (builder.showGui) {
      executor = MoreExecutors.newDirectExecutorService();
    } else {
      executor = MoreExecutors.listeningDecorator(
        Executors.newFixedThreadPool(threads, new LocalThreadFactory()));
    }

    final List results =
      Collections.synchronizedList(new ArrayList());
    final ResultCollector resultCollector =
      new ResultCollector(executor, results, builder.resultListeners);

    try {
      for (final ExperimentRunner r : runners) {
        checkForError(executor, resultCollector);
        final ListenableFuture f = executor.submit(r);
        Futures.addCallback(f, resultCollector);
      }
      while (results.size() < inputs.size() && !resultCollector.hasError()) {
        Thread.sleep(THREAD_SLEEP_TIME_MS);
      }
      checkForError(executor, resultCollector);
    } catch (final InterruptedException e) {
      LOGGER.trace("Interrupt, shutting down the executor.");
      executor.shutdownNow();
      LOGGER.trace("Waiting for executor to shutdown.");
      try {
        final boolean executorStopped =
          executor.awaitTermination(MAX_WAIT_FOR_SHUTDOWN_S, TimeUnit.SECONDS);
        if (executorStopped) {
          LOGGER.trace("Executor is shutdown.");
        } else {
          LOGGER.warn("Executor did not stop, timed out after {} seconds.",
            MAX_WAIT_FOR_SHUTDOWN_S);
        }
      } catch (final InterruptedException e1) {
        LOGGER.warn("Waiting for executor to shutdown is interrupted.");
      }
      return ExperimentResults.create(builder,
        ImmutableSet.of());
    }

    checkForError(executor, resultCollector);
    executor.shutdown();

    final ExperimentResults er =
      ExperimentResults.create(builder, ImmutableSet.copyOf(results));
    for (final ResultListener rl : builder.resultListeners) {
      rl.doneComputing(er);
    }
    return er;
  }

  static void checkForError(ListeningExecutorService executor,
      ResultCollector collector) {
    if (collector.hasError()) {
      executor.shutdown();
      if (collector.throwable instanceof RuntimeException) {
        throw (RuntimeException) collector.throwable;
      }
      throw new IllegalStateException(collector.throwable);
    }
  }

  static class LocalThreadFactory implements ThreadFactory {
    static final AtomicInteger THREAD_ID = new AtomicInteger(0);

    LocalThreadFactory() {}

    @Override
    public Thread newThread(@Nullable Runnable r) {
      return new Thread(r, "RinSim-exp-" + THREAD_ID.getAndIncrement());
    }
  }

  static class ResultCollector implements FutureCallback {
    final ListeningExecutorService executor;
    final List results;
    final List resultListeners;

    @Nullable
    volatile Throwable throwable;

    ResultCollector(ListeningExecutorService ex, List res,
        List listeners) {
      executor = ex;
      results = res;
      resultListeners = listeners;
    }

    public boolean hasError() {
      return throwable != null;
    }

    @Override
    public void onFailure(Throwable t) {
      throwable = t;
      executor.shutdownNow();
    }

    @Override
    public void onSuccess(@Nullable SimulationResult result) {
      final SimulationResult res = verifyNotNull(result);
      for (final ResultListener rl : resultListeners) {
        try {
          rl.receive(res);
        } catch (final RuntimeException e) {
          System.err
            .println("ResultListener " + rl + " failed to receive result.");
          e.printStackTrace(System.err);
        }
      }
      if (res.getResultObject() == FailureStrategy.RETRY) {
        final ExperimentRunner newRunner =
          new ExperimentRunner(res.getSimArgs());
        Futures.addCallback(executor.submit(newRunner), this);
      } else {
        // FIXME this should be changed into a more decent progress indicator
        System.out.print(".");
        results.add(result);
      }
    }
  }

  static class ExperimentRunner implements Callable {
    private final SimArgs arguments;

    ExperimentRunner(SimArgs args) {
      arguments = args;
    }

    @Override
    public SimulationResult call() {
      final Object resultObject = Experiment.perform(arguments);
      final SimulationResult result =
        SimulationResult.create(arguments, resultObject);
      return result;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy