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

org.btrplace.scheduler.choco.view.CNetwork Maven / Gradle / Ivy

/*
 * Copyright  2021 The BtrPlace Authors. All rights reserved.
 * Use of this source code is governed by a LGPL-style
 * license that can be found in the LICENSE.txt file.
 */

package org.btrplace.scheduler.choco.view;

import org.btrplace.model.Attributes;
import org.btrplace.model.Model;
import org.btrplace.model.Node;
import org.btrplace.model.VM;
import org.btrplace.model.view.network.Link;
import org.btrplace.model.view.network.Network;
import org.btrplace.model.view.network.Routing.LinkDirection;
import org.btrplace.model.view.network.Switch;
import org.btrplace.scheduler.SchedulerException;
import org.btrplace.scheduler.SchedulerModelingException;
import org.btrplace.scheduler.choco.Parameters;
import org.btrplace.scheduler.choco.ReconfigurationProblem;
import org.btrplace.scheduler.choco.transition.RelocatableVM;
import org.btrplace.scheduler.choco.transition.VMTransition;
import org.chocosolver.solver.Cause;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.Task;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * The solver part of the network view.
 * Define the maximal bandwidth allocatable for each migration according to the capacity
 * of the network elements on each migration path. Then, establish the relation between the
 * migrations duration and their allocated bandwidth based on specific VMs attributes related
 * to VM memory activity.
 *
 * @author Vincent Kherbache
 */
public class CNetwork implements ChocoView {

  /**
   * The view identifier.
   */
  public static final String VIEW_ID = "NetworkView";
  private final Network net;
  private org.chocosolver.solver.Model csp;
    private Model source;

    /**
     * Make a new network view.
     *
     * @param n the network view we rely on
     */
    public CNetwork(Network n) throws SchedulerException {
        net = n;
    }

    @Override
    public boolean inject(Parameters ps, ReconfigurationProblem rp) throws SchedulerException {
        csp = rp.getModel();
        source = rp.getSourceModel();

        return true;
    }

    @Override
    public String getIdentifier() {
        return net.getIdentifier();
    }

    @Override
    public boolean beforeSolve(ReconfigurationProblem rp) throws SchedulerException {

        Model mo = rp.getSourceModel();
        Attributes attrs = mo.getAttributes();

        // Pre-compute duration and bandwidth for each VM migration
        for (VMTransition migration : rp.getVMActions()) {

            if (!(migration instanceof RelocatableVM)) {
                continue;
            }

            // Get vars from migration
            VM vm = migration.getVM();
            IntVar bandwidth = ((RelocatableVM) migration).getBandwidth();
            IntVar duration = migration.getDuration();
            Node src = rp.getSourceModel().getMapping().getVMLocation(vm);

            // Try to get the destination node
            Node dst;

            if (!migration.getDSlice().getHoster().isInstantiated()) {
                throw new SchedulerModelingException(null, "Destination node for VM '" + vm + "' should be known !");
            }

            if (!mo.getAttributes().isSet(vm, "memUsed")) {
                throw new SchedulerModelingException(null, "Unable to retrieve 'memUsed' attribute for the vm '" + vm + "'");
            }

            dst = rp.getNode(migration.getDSlice().getHoster().getValue());
            if (src.equals(dst)) {
                try {
                    ((RelocatableVM) migration).getBandwidth().instantiateTo(0, Cause.Null);
                    continue;
                } catch (ContradictionException e) {
                    rp.getLogger().debug("Contradiction exception when trying to instantiate bandwidth and " +
                            " duration variables for " + vm + " migration", e);
                    return false;
                }
            }

            // Get attribute vars
            int memUsed = attrs.get(vm, "memUsed", -1);

            // Get VM memory activity attributes if defined, otherwise set an idle workload on the VM
            double hotDirtySize = attrs.get(vm, "hotDirtySize", 5.0);// Minimal observed value on idle VM
            double hotDirtyDuration = attrs.get(vm, "hotDirtyDuration", 2.0); // Minimal observed value on idle VM
            double coldDirtyRate = attrs.get(vm, "coldDirtyRate", 0.0);

            // Get the maximal bandwidth available on the migration path
            int maxBW = net.getRouting().getMaxBW(src, dst);

            // Compute the duration related to each enumerated bandwidth
            double durationMin;
            double durationColdPages;
            double durationHotPages;
            double durationTotal;

            // Cheat a bit, real is less than theoretical (8->9)
            double bandwidthOctet = maxBW / 9.0;

            // Estimate the duration for the current bandwidth
            durationMin = memUsed / bandwidthOctet;
            if (durationMin > hotDirtyDuration) {

                durationColdPages = (hotDirtySize + (durationMin - hotDirtyDuration) * coldDirtyRate) /
                        (bandwidthOctet - coldDirtyRate);
                durationHotPages = (hotDirtySize / bandwidthOctet * ((hotDirtySize / hotDirtyDuration) /
                        (bandwidthOctet - (hotDirtySize / hotDirtyDuration))));
                durationTotal = durationMin + durationColdPages + durationHotPages;
            } else {
                durationTotal = durationMin + (((hotDirtySize / hotDirtyDuration) * durationMin) /
                        (bandwidthOctet - (hotDirtySize / hotDirtyDuration)));
            }

            // Instantiate the computed bandwidth and duration
            try {
                //prevent from a 0 duration when the memory usage is very low
                int dd = (int) Math.max(1, Math.round(durationTotal));
                duration.instantiateTo(dd, Cause.Null);
                bandwidth.instantiateTo(maxBW, Cause.Null);
            } catch (ContradictionException e) {
                rp.getLogger().debug("Contradiction exception when trying to instantiate bandwidth and " +
                        " duration variables for " + vm + " migration: ", e);
                return false;
            }
        }

        // Add links and switches constraints
        addLinkConstraints(rp);        
        addSwitchConstraints(rp);

        return true;
    }

    /**
     * Add the cumulative constraints for each link.
     *
     * Full-duplex links are considered, two cumulative constraints are defined per link by looking at
     * the migration direction for each link on the migration path.
     *
     * @param rp the reconfiguration problem
     */
    private void addLinkConstraints(ReconfigurationProblem rp) {

        // Links limitation
        List tasksListUp = new ArrayList<>();
        List tasksListDown = new ArrayList<>();
        List heightsListUp = new ArrayList<>();
        List heightsListDown = new ArrayList<>();

        for (Link l : net.getLinks()) {

            for (VM vm : rp.getVMs()) {
                VMTransition a = rp.getVMAction(vm);

                if (a instanceof RelocatableVM
                        && !a.getDSlice().getHoster().isInstantiatedTo(a.getCSlice().getHoster().getValue())) {

                    Node src = source.getMapping().getVMLocation(vm);
                    Node dst = rp.getNode(a.getDSlice().getHoster().getValue());
                    List path = net.getRouting().getPath(src, dst);

                    // Check first if the link is on migration path
                    if (path.contains(l)) {
                        // Get link direction
                        LinkDirection linkDirection = net.getRouting().getLinkDirection(src, dst, l);
                        // UpLink
                        if (linkDirection == LinkDirection.UPLINK) {
                            tasksListUp.add(((RelocatableVM) a).getMigrationTask());
                            heightsListUp.add(((RelocatableVM) a).getBandwidth());
                        }
                        // DownLink
                        else {
                            tasksListDown.add(((RelocatableVM) a).getMigrationTask());
                            heightsListDown.add(((RelocatableVM) a).getBandwidth());
                        }
                    }
                }
            }
            if (!tasksListUp.isEmpty()) {

                // Post the cumulative constraint for the current UpLink
                csp.post(csp.cumulative(
                        tasksListUp.toArray(new Task[tasksListUp.size()]),
                        heightsListUp.toArray(new IntVar[heightsListUp.size()]),
                        csp.intVar(l.getCapacity()),
                        true
                ));

                tasksListUp.clear();
                heightsListUp.clear();
            }
            if (!tasksListDown.isEmpty()) {

                // Post the cumulative constraint for the current DownLink
                csp.post(csp.cumulative(
                        tasksListDown.toArray(new Task[tasksListDown.size()]),
                        heightsListDown.toArray(new IntVar[heightsListDown.size()]),
                        csp.intVar(l.getCapacity()),
                        true
                ));

                tasksListDown.clear();
                heightsListDown.clear();
            }
        }
    }
    /**
     * Add the cumulative constraints for each blocking switch (having limited capacity)
     *
     * @param rp the reconfiguration problem
     */
    private void addSwitchConstraints(ReconfigurationProblem rp) {
        
        // Switches capacity limitation
        List tasksList = new ArrayList<>();
        List heightsList = new ArrayList<>();
        
        for(Switch sw : net.getSwitches()) {


            // Only if the capacity is limited
            if (sw.getCapacity() != Integer.MAX_VALUE) {

                for (VM vm : rp.getVMs()) {
                    VMTransition a = rp.getVMAction(vm);

                    if (a != null && a instanceof RelocatableVM) {

                        if (a.getDSlice().getHoster().isInstantiated()) {

                            if (a.getCSlice().getHoster().getValue() != a.getDSlice().getHoster().getValue()) {

                                Node src = source.getMapping().getVMLocation(vm);
                                Node dst = rp.getNode(a.getDSlice().getHoster().getValue());

                                if (!Collections.disjoint(net.getConnectedLinks(sw), net.getRouting().getPath(src, dst))) {
                                    tasksList.add(new Task(a.getStart(), a.getDuration(), a.getEnd()));
                                    heightsList.add(((RelocatableVM) a).getBandwidth());
                                }
                            }
                        }
                    }
                }

                if (!tasksList.isEmpty()) {
                    // Post the cumulative constraint for the current switch
                    csp.post(csp.cumulative(
                            tasksList.toArray(new Task[tasksList.size()]),
                            heightsList.toArray(new IntVar[heightsList.size()]),
                            csp.intVar(sw.getCapacity()),
                            true
                    ));

                    tasksList.clear();
                    heightsList.clear();
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy