edu.mit.streamjit.impl.compiler2.DescendingShareAllocationStrategy.java Source code

Java tutorial

Introduction

Here is the source code for edu.mit.streamjit.impl.compiler2.DescendingShareAllocationStrategy.java

Source

/*
 * Copyright (c) 2013-2014 Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package edu.mit.streamjit.impl.compiler2;

import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
import com.google.common.math.DoubleMath;
import com.google.common.math.IntMath;
import edu.mit.streamjit.api.Worker;
import edu.mit.streamjit.impl.common.Configuration;
import edu.mit.streamjit.impl.common.Workers;
import edu.mit.streamjit.util.CollectionUtils;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * An allocation strategy that gives each core a floating-point "share"
 * parameter in [0,1], then allocates the specified fraction of the total
 * iterations to those cores with priority by descending order of share.
 *
 * This strategy favors space multiplexing.  Equal data-parallelization can only
 * occur if all N shares are approximately 1/N, as we do not normalize.
 * @author Jeffrey Bosboom <jbosboom@csail.mit.edu>
 * @since 12/31/2013
 */
public class DescendingShareAllocationStrategy implements AllocationStrategy {
    private final int maxNumCores;

    public DescendingShareAllocationStrategy(int maxNumCores) {
        this.maxNumCores = maxNumCores;
    }

    @Override
    public int maxNumCores() {
        return maxNumCores;
    }

    @Override
    public void makeParameters(Set<Worker<?, ?>> workers, Configuration.Builder builder) {
        for (Worker<?, ?> w : workers)
            for (int i = 0; i < maxNumCores(); ++i) {
                String name = String.format("node%dcore%dshare", Workers.getIdentifier(w), i);
                builder.addParameter(new Configuration.FloatParameter(name, 0, 1, 1f / maxNumCores()));
            }
    }

    @Override
    public void allocateGroup(ActorGroup group, Range<Integer> iterations, List<Core> cores, Configuration config) {
        List<Float> shares = new ArrayList<>(cores.size());
        for (int core = 0; core < cores.size(); ++core) {
            String name = String.format("node%dcore%diter", group.id(), core);
            Configuration.FloatParameter parameter = config.getParameter(name, Configuration.FloatParameter.class);
            if (parameter == null)
                shares.add(0f);
            else
                shares.add(parameter.getValue());
        }

        assert iterations.lowerBoundType() == BoundType.CLOSED && iterations.upperBoundType() == BoundType.OPEN;
        int totalAvailable = iterations.upperEndpoint() - iterations.lowerEndpoint();
        while (!iterations.isEmpty()) {
            int max = CollectionUtils.maxIndex(shares);
            float share = shares.get(max);
            if (share == 0)
                break;
            int amount = DoubleMath.roundToInt(share * totalAvailable, RoundingMode.HALF_EVEN);
            int done = iterations.lowerEndpoint();
            Range<Integer> allocation = group.isStateful() ? iterations
                    : iterations.intersection(Range.closedOpen(done, done + amount));
            cores.get(max).allocate(group, allocation);
            iterations = Range.closedOpen(allocation.upperEndpoint(), iterations.upperEndpoint());
            shares.set(max, 0f); //don't allocate to this core again
        }

        //If we have iterations left over not assigned to a core, spread them
        //evenly over all cores.
        if (!iterations.isEmpty()) {
            int perCore = IntMath.divide(iterations.upperEndpoint() - iterations.lowerEndpoint(), cores.size(),
                    RoundingMode.CEILING);
            for (int i = 0; i < cores.size() && !iterations.isEmpty(); ++i) {
                int min = iterations.lowerEndpoint();
                Range<Integer> allocation = group.isStateful() ? iterations
                        : iterations.intersection(Range.closedOpen(min, min + perCore));
                cores.get(i).allocate(group, allocation);
                iterations = Range.closedOpen(allocation.upperEndpoint(), iterations.upperEndpoint());
            }
        }
        assert iterations.isEmpty();
    }
}