From 642324575897a2a75b99c5252ae040ab481ccd31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Klervie=20Tocz=C3=A9?= <klervie.tocze@liu.se>
Date: Tue, 14 Jan 2025 10:09:25 +0100
Subject: [PATCH] Final updates before ICPE submission

---
 Code/src/MixedReality_Optimization.java | 53 ++++++++++----
 Code/src/device/EnergyModel.java        |  6 ++
 Code/src/device/PiecewiseLinear.java    | 32 ++++++++
 Code/src/system/Network.java            | 97 +++++++++++++++++++------
 Code/src/utils/Config.java              |  8 +-
 5 files changed, 153 insertions(+), 43 deletions(-)
 create mode 100644 Code/src/device/EnergyModel.java
 create mode 100644 Code/src/device/PiecewiseLinear.java

diff --git a/Code/src/MixedReality_Optimization.java b/Code/src/MixedReality_Optimization.java
index 2a68030..39800ec 100644
--- a/Code/src/MixedReality_Optimization.java
+++ b/Code/src/MixedReality_Optimization.java
@@ -22,20 +22,21 @@ public class MixedReality_Optimization {
             //Parameters for the different studies
             int numberOfFunctionInstances = 2;
             Boolean usingUniformLoadDistribution = false;
-            int standardDeviation = 10;
-            Boolean linksAreLoaded = true;
-            Boolean randomStartLocation = false;
+            int standardDeviation = 30;
+            Boolean linksAreLoaded = false;
+            Boolean oneCoreAllocation= true;
+            Boolean randomStartLocation = true;
+            Boolean colocationScenario = false; // Note: the colocation scenario is only run if the random start location is not activated
 
             String appId = "MR_Service"; // identifier of the application
             Application application = createApplication(appId);
 
-            //TODO Check whether this is still actual
             System.out.println("Description of the experiment:");
             System.out.println("- Number of functions instances: " + numberOfFunctionInstances);
             if (usingUniformLoadDistribution)
-                {System.out.println("- Load distribution: NORMAL with std " + standardDeviation);}
+                {System.out.println("- Load distribution: UNIFORM");}
             else{
-                System.out.println("- Load distribution: UNIFORM");
+                System.out.println("- Load distribution: NORMAL with std " + standardDeviation);
             }
             System.out.println("   The (mean) load increases by 10% per scenario");
             if(linksAreLoaded){
@@ -43,6 +44,11 @@ public class MixedReality_Optimization {
             }else{
                 System.out.println("- Load on links: 0%");
             }
+            if(oneCoreAllocation){
+                System.out.println("- A function instance is allocated up to one CPU core");
+            }else{
+                System.out.println("- A function instance is allocated all remaining CPU capacity");
+            }
             if (randomStartLocation)
             {System.out.println("- Start location: RANDOM ");}
             else{
@@ -52,20 +58,27 @@ public class MixedReality_Optimization {
             //Determine startLocation = at which device the request is received. This is the placing device
             String startLocation;
             if (randomStartLocation){
-                Random randomLoc = new Random();
-                Integer randomStart=randomLoc.nextInt(11);
-                startLocation= "gateway_" + randomStart.toString();
-                System.out.println("Random start location is "+startLocation);
+                System.out.println("Random start location is decided per repetition");
+                startLocation=null; //Will be set later in the random case
             }
             else{
-                //For this scenario the start node is NOT random between scenarios
-                Integer randomStart=0;
-                startLocation= "gateway_" + randomStart;
-                System.out.println("Non random start location is "+startLocation);
+                if(colocationScenario){
+                    //For this scenario the start node is NOT random between scenarios
+                    Integer randomStart=0; //Start device of 0 with the current function instance placement enables the possibility of colocation on the requesting device
+                    startLocation= "gateway_" + randomStart;
+                    System.out.println("Non random start location is "+startLocation);
+                }
+                else {
+                    //For this scenario the start node is NOT random between scenarios
+                    Integer randomStart=4;
+                    startLocation= "gateway_" + randomStart;
+                    System.out.println("Non random start location is "+startLocation);
+                }
+
             }
 
             System.out.println("Creating the network to be used");
-            Network network = new Network(application,startLocation);
+            Network network = new Network(application,startLocation,oneCoreAllocation);
 
             System.out.println("Placing the function instances");
             placeFunctionInstances(numberOfFunctionInstances,network.getEdgeDevices());
@@ -80,6 +93,16 @@ public class MixedReality_Optimization {
             for (int a = 0; a< Config.REPETITION_NUMBER; a++) {
                 System.out.println("Repetition " + a);
 
+                //For the random beginning device, we want to change it here
+                if(randomStartLocation){
+                    // Get new random beginning device
+                    Random randomLoc = new Random(Config.SEED+a);
+                    Integer randomStart=randomLoc.nextInt(11);
+                    startLocation= "gateway_" + randomStart.toString();
+                    System.out.println("Random start location is "+startLocation);
+                    network.modifyPlacingDevice(startLocation);
+                }
+
                 //for each utilization scenario
                 for (int i = 0; i < Config.LOAD_SCENARIO_NUMBER; i++) {
                     System.out.println("Utilization scenario " + i);
diff --git a/Code/src/device/EnergyModel.java b/Code/src/device/EnergyModel.java
new file mode 100644
index 0000000..46efa54
--- /dev/null
+++ b/Code/src/device/EnergyModel.java
@@ -0,0 +1,6 @@
+package device;
+
+public interface EnergyModel {
+
+    Double getDynamicPowerForUtilization (Double utilization);
+}
diff --git a/Code/src/device/PiecewiseLinear.java b/Code/src/device/PiecewiseLinear.java
new file mode 100644
index 0000000..d277587
--- /dev/null
+++ b/Code/src/device/PiecewiseLinear.java
@@ -0,0 +1,32 @@
+package device;
+
+import utils.Config;
+
+import static java.lang.Math.floor;
+
+public class PiecewiseLinear implements EnergyModel{
+
+    //Power data from Ahvar et al. - Parasilo server
+    int[] powerPerCore = new int[]{98,148,161,176,178,180,184,200,208,212,215,217,218,221,230,237,241};
+    int[] powerDynPerCore =new int[17];
+
+    public PiecewiseLinear(){
+        for (int i=0; i<powerDynPerCore.length;i++){
+            powerDynPerCore[i]=powerPerCore[i]-powerPerCore[0];
+        }
+    }
+
+    @Override
+    public Double getDynamicPowerForUtilization(Double utilization) {
+        double powerRes=0.0;
+        if(utilization>=100.0){
+            powerRes=powerDynPerCore[powerDynPerCore.length-1];
+        }
+        else{
+            int j = (int) floor(utilization* Config.DEFAULT_DEVICE_NB_CORES/100);
+            powerRes = (powerDynPerCore[j+1]-powerDynPerCore[j])*Config.DEFAULT_DEVICE_NB_CORES*(utilization/100)+((j+1)*powerDynPerCore[j]-j*powerDynPerCore[j+1]);
+        }
+
+        return powerRes;
+    }
+}
diff --git a/Code/src/system/Network.java b/Code/src/system/Network.java
index 596a892..b4c524d 100644
--- a/Code/src/system/Network.java
+++ b/Code/src/system/Network.java
@@ -2,6 +2,8 @@ package system;
 
 import application.Application;
 import device.Device;
+import device.EnergyModel;
+import device.PiecewiseLinear;
 import org.apache.commons.math3.util.Pair;
 import placement.RequestPlacementOutput;
 import utils.Config;
@@ -40,7 +42,11 @@ public class Network {
 
     String placingDevice;
 
-    public Network(Application applicationConsidered, String placingDevice){
+    EnergyModel energyModel;
+
+    Boolean oneCoreAllocation;
+
+    public Network(Application applicationConsidered, String placingDevice, boolean oneCoreAllocation_){
 
         application= applicationConsidered;
         this.placingDevice=placingDevice;
@@ -80,6 +86,9 @@ public class Network {
 
         createNetworkGraph();
         dijkstraAlg = new DijkstraShortestPath<>(graph);
+
+        energyModel = new PiecewiseLinear();
+        oneCoreAllocation=oneCoreAllocation_;
     }
 
     private void createNetworkGraph(){
@@ -173,13 +182,14 @@ public class Network {
                 Double currentUtilization = utilization.get(device);
                 //Get size to be calculated
                 Double size = application.getTargetFunctionCPUSize(functionInstance);
-                //Get available capacity
-                Double availableCapacity = Config.DEFAULT_DEVICE_CAPACITY * (1-(currentUtilization / 100));//Note: this is allocating all the available capacity
+                //Get capacity allocated to the function instance
+                Double allocatedCapacity=getAllocatedCapacity(currentUtilization);
+
                 //Calculate according to formula
-                if (availableCapacity==0){
+                if (allocatedCapacity==0){
                     deviceTiming=Double.valueOf(Config.INFINITE);
                 }else {
-                    deviceTiming = (size / availableCapacity);
+                    deviceTiming = (size / allocatedCapacity);
                 }
                 //Add to the Map variable
                 time_devices.put(device+"-"+functionInstance, deviceTiming);
@@ -187,6 +197,23 @@ public class Network {
             return deviceTiming;
     }
 
+    private Double getAllocatedCapacity(Double currentUtilization){
+        //Get available capacity
+        Double availableCapacity = Config.DEFAULT_DEVICE_CAPACITY_PER_CORE*Config.DEFAULT_DEVICE_NB_CORES * (1-(currentUtilization / 100));
+
+        //A function instance gets up to one core of capacity or the full remaining capacity
+        Double allocatedCapacity=0.0;
+        if(availableCapacity-Config.DEFAULT_DEVICE_CAPACITY_PER_CORE >=0 && oneCoreAllocation){
+            //At least one core is available, we allocate one core
+            allocatedCapacity= (double) Config.DEFAULT_DEVICE_CAPACITY_PER_CORE;
+        }
+        else{
+            //We allocate what is available
+            allocatedCapacity=availableCapacity;
+        }
+        return allocatedCapacity;
+    }
+
     private double calculateWeight(Device source, Device destination){
         //For this scenario the weight is the latency calculated as the distance between the nodes divided by 100
         double distance = calculateDistance(source.getLocationInformation(),destination.getLocationInformation())/100;
@@ -226,12 +253,12 @@ public class Network {
         return totalLatency;
     }
 
-    private double getDynamicPowerForUtilization(double utilizationWithServicePlaced, double dynPower){
+    /*private double getDynamicPowerForUtilization(double utilizationWithServicePlaced, double dynPower){
         //We consider a linear model were the dynamic power part is 0 at 0% utilization (OBS it still has idle power but this is another constant)
         // and Dyn power att 100% utilization
         //utilization in percentage
         return dynPower*(utilizationWithServicePlaced/100);
-    }
+    }*/ //TODO Move to a new Linear energy model class
 
     public double getLinkEnergyConsumption(String startFunctionInstanceName, String destinationFunctionInstanceName,
                                            String startLocation, String destinationLocation){
@@ -354,10 +381,16 @@ public class Network {
 
             //Get Pidle
             int p_device_idle = Config.DEFAULT_DEVICE_P_IDLE;
-            //GetPdyn
-            int p_device_dyn = Config.DEFAULT_DEVICE_P_DYN;
+
+            //Calculate utilization after allocation
+            double utilizationAfterAllocation = calculateUtilizationAfterAllocation(deviceName);
+
             //Calculate energy
-            energy_consumption = p_device_idle * deviceTiming + p_device_dyn * deviceTiming; //Assumes 100% utilization when selected
+            energy_consumption = p_device_idle * deviceTiming + energyModel.getDynamicPowerForUtilization(utilizationAfterAllocation) * deviceTiming;
+
+            if(energy_consumption <0){
+                System.out.println("PRoblem");
+            }
 
             //Add to Map variables
             energy_devices.put(functionInstanceName, energy_consumption);
@@ -365,15 +398,25 @@ public class Network {
         return energy_consumption;
     }
 
+    private double calculateUtilizationAfterAllocation(String device){
+        Double currentUtilization = utilization.get(device);
+        Double allocatedCapacity = getAllocatedCapacity(currentUtilization);
+
+        //Calculate share of utilization of this allocated capacity
+        Double allocatedUtilization= allocatedCapacity/(Config.DEFAULT_DEVICE_CAPACITY_PER_CORE*Config.DEFAULT_DEVICE_NB_CORES)*100; //In percentage
+
+        return currentUtilization+allocatedUtilization;
+    }
+
     public double getInstanceMarginalEnergyConsumption(String functionInstanceName){
         // 1- Getting the hardware name
         Pair<String, String> nameSplit = Utils.splitLongFunctionInstanceName(functionInstanceName);
         String deviceName = nameSplit.getKey();
 
         //Check whether we already have info about this
-        double energy_residual_consumption;
+        double energy_marginal_consumption;
         if(energy_residual_devices.get(functionInstanceName)!=null){
-            energy_residual_consumption=energy_residual_devices.get(functionInstanceName);
+            energy_marginal_consumption =energy_residual_devices.get(functionInstanceName);
         }else{
             //We need to calculate it
 
@@ -382,24 +425,25 @@ public class Network {
 
             //Get Pidle
             int p_device_idle = Config.DEFAULT_DEVICE_P_IDLE;
-            //GetPdyn
-            int p_device_dyn = Config.DEFAULT_DEVICE_P_DYN;
+
+            //Calculate utilization after allocation
+            double utilizationAfterAllocation = calculateUtilizationAfterAllocation(deviceName);
+
             //Get utilization value for this device
             Double beforeUtilization = utilization.get(deviceName);
             if (beforeUtilization == 0) {
-                energy_residual_consumption = p_device_idle * deviceTiming + p_device_dyn * deviceTiming; //Assumes the utilization gets up to 100%
+                energy_marginal_consumption = p_device_idle * deviceTiming + energyModel.getDynamicPowerForUtilization(utilizationAfterAllocation) * deviceTiming;
             } else {
-                double utilizationWithServicePlaced = 100.0; //Assumption, see above
-                double utilizationIncrease = utilizationWithServicePlaced - beforeUtilization;
-                //OBS Assumes a linear power consumption model
-                double p_device_dyn_util = getDynamicPowerForUtilization(utilizationIncrease, p_device_dyn);//How much power does the utilization increase due to the placement requires?
-                energy_residual_consumption = p_device_dyn_util * deviceTiming; //Only the dynamic part
+                //How much power does the utilization increase due to the placement requires?
+                double powerIncrease = energyModel.getDynamicPowerForUtilization(utilizationAfterAllocation) - energyModel.getDynamicPowerForUtilization(beforeUtilization);
+
+                energy_marginal_consumption = powerIncrease * deviceTiming; //Only the dynamic part
             }
 
             //Add to Map variables
-            energy_residual_devices.put(functionInstanceName, energy_residual_consumption);
+            energy_residual_devices.put(functionInstanceName, energy_marginal_consumption);
         }
-        return energy_residual_consumption;
+        return energy_marginal_consumption;
     }
 
         public void evaluatePlacementOutput(RequestPlacementOutput output, String startLocationMathematical, String endLocationMathematical){
@@ -509,7 +553,7 @@ public class Network {
             energyResLinkDevice = energyResLink + energyResDevice;
 
             //Print the results in a usable way
-            System.out.println("Evaluated placement: Time " + timeLinkDevice + " Energy " + energyLinkDevice + " Residual energy " + energyResLinkDevice + "In details - time link "+ timeLink + " time device " + timeDevice + " energy link " + energyLink + " energy device " + energyDevice + " energy res link "+energyResLink + " energy res device "+energyResDevice);
+            System.out.println("Evaluated placement: Completion time " + timeLinkDevice + " Overall energy " + energyLinkDevice + " Marginal energy " + energyResLinkDevice + " In details - completion time link "+ timeLink + " completion time device " + timeDevice + " overall energy link " + energyLink + " overall energy device " + energyDevice + " marginal energy link "+energyResLink + " marginal energy device "+energyResDevice);
         }
     }
 
@@ -540,7 +584,7 @@ public class Network {
         //Devices
         List<String> deviceNames = new ArrayList<>();
         for (Device device : edgeDevices) {
-            if (device.getName().contains("gateway")) {//TODO: with current setup should be all of them so function not needed
+            if (device.getName().contains("gateway")) {//Note: with current setup should be all of them so this is only to double check
                 deviceNames.add(device.getName());
             }
         }
@@ -597,4 +641,9 @@ public class Network {
     public List<Device> getEdgeDevices(){
         return edgeDevices;
     }
+
+    // Used for the random beginning device case
+    public void modifyPlacingDevice(String newPlacingDevice){
+        this.placingDevice=newPlacingDevice;
+    }
 }
diff --git a/Code/src/utils/Config.java b/Code/src/utils/Config.java
index 2a30df4..a5f2d37 100644
--- a/Code/src/utils/Config.java
+++ b/Code/src/utils/Config.java
@@ -2,13 +2,13 @@ package utils;
 
 public class Config {
 	public static final int LOAD_SCENARIO_NUMBER = 11;
-	public static final int REPETITION_NUMBER = 25;
+	public static final int REPETITION_NUMBER = 40;
 	public static final int DEFAULT_LINK_CAPACITY =500;//MBytes/sec
 	public static final int DEFAULT_LINK_P_IDLE =1;
 	public static final int DEFAULT_LINK_P_DYN =9;
-	public static final int DEFAULT_DEVICE_CAPACITY =500;//MI
-	public static final int DEFAULT_DEVICE_P_IDLE =98;//W - Data fron Ahvar - Parasilo zero core was 750
-	public static final int DEFAULT_DEVICE_P_DYN =148;//W - Data fron Ahvar - Parasilo one core was 250
+	public static final int DEFAULT_DEVICE_CAPACITY_PER_CORE =500;//MI
+	public static final int DEFAULT_DEVICE_P_IDLE =98;//W - Data from Ahvar - Parasilo zero core
+	public static final int DEFAULT_DEVICE_NB_CORES =16;// Data from Ahvar - Parasilo
 	public static final int INFINITE = 10000;//Very big number so that link/devices with 100% utilization are discarded as impossible
 	public static final int SEED = 165746;
 }
-- 
GitLab