From bafe762ac01d16904c18404283027e426e19bc73 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 3 Feb 2021 16:35:48 +0100 Subject: Code reorganization. Moving main code to src, keeping modules in modules/ --- .../acme/planning/machine/CloudBalance.java | 48 ++++++++++++++++++++ .../machine/CloudBalancingEasyScoreCalculator.java | 45 +++++++++++++++++++ .../acme/planning/machine/CloudComputer.java | 16 +++++++ .../acme/planning/machine/CloudPlaningMain.java | 52 ++++++++++++++++++++++ .../acme/planning/machine/CloudPlanner.java | 22 +++++++++ .../acme/planning/machine/CloudProcess.java | 48 ++++++++++++++++++++ .../machine/CloudProcessDifficultyComparator.java | 15 +++++++ .../acme/planning/machine/ScalewayInstance.java | 25 +++++++++++ 8 files changed, 271 insertions(+) create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java create mode 100644 src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java (limited to 'src/ri-planner/src/main/java/io/trygvis') diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java new file mode 100644 index 0000000..7311918 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalance.java @@ -0,0 +1,48 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty; +import org.optaplanner.core.api.domain.solution.PlanningScore; +import org.optaplanner.core.api.domain.solution.PlanningSolution; +import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty; +import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider; +import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; + +import java.util.List; + +@PlanningSolution +public class CloudBalance { + + private List computerList; + + private List processList; + + private HardSoftScore score; + + public CloudBalance(List computerList, List processList) { + this.computerList = computerList; + this.processList = processList; + } + + public CloudBalance() { + } + + @ValueRangeProvider(id = "computerRange") + @ProblemFactCollectionProperty + public List getComputerList() { + return computerList; + } + + @PlanningEntityCollectionProperty + public List getProcessList() { + return processList; + } + + @PlanningScore + public HardSoftScore getScore() { + return score; + } + + public void setScore(HardSoftScore score) { + this.score = score; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java new file mode 100644 index 0000000..6a14372 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudBalancingEasyScoreCalculator.java @@ -0,0 +1,45 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; +import org.optaplanner.core.api.score.calculator.EasyScoreCalculator; + +public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator { + + @Override + public HardSoftScore calculateScore(CloudBalance cloudBalance) { + int hardScore = 0; + int softScore = 0; + for (CloudComputer computer : cloudBalance.getComputerList()) { + int cpu = 0; + int memory = 0; + boolean used = false; + + // Calculate usage + for (CloudProcess process : cloudBalance.getProcessList()) { + if (computer.equals(process.computer)) { + cpu += process.requiredCpu; + memory += process.requiredMemory; + used = true; + } + } + + var instance = computer.instance; + + // Hard constraints + int cpuPowerAvailable = instance.cpu - cpu; + if (cpuPowerAvailable < 0) { + hardScore += cpuPowerAvailable; + } + int memoryAvailable = instance.memory - memory; + if (memoryAvailable < 0) { + hardScore += memoryAvailable; + } + + // Soft constraints + if (used) { + softScore -= instance.cost; + } + } + return HardSoftScore.of(hardScore, softScore); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java new file mode 100644 index 0000000..aa2087d --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudComputer.java @@ -0,0 +1,16 @@ +package io.trygvis.acme.planning.machine; + +public class CloudComputer { + public final String host; + public final ScalewayInstance instance; + + public CloudComputer(String host, ScalewayInstance instance) { + this.host = host; + this.instance = instance; + } + + @Override + public String toString() { + return host; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java new file mode 100644 index 0000000..60b3fd3 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlaningMain.java @@ -0,0 +1,52 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.solver.SolverFactory; + +import java.util.ArrayList; + +public class CloudPlaningMain { + public static final ScalewayInstance Stardust1_s = new ScalewayInstance("Stardust1-s", 0.0025, 1000, 1000); + public static final ScalewayInstance DEV1_S = new ScalewayInstance("DEV1-S", 0.01, 2000, 2000); + public static final ScalewayInstance DEV1_M = new ScalewayInstance("DEV1-M", 0.02, 3000, 4000); + public static final ScalewayInstance DEV1_L = new ScalewayInstance("DEV1-L", 0.04, 4000, 8000); + public static final ScalewayInstance DEV1_XL = new ScalewayInstance("DEV1-XL", 0.06, 4000, 12000); + + public static void main(String[] args) { + var solverFactory = SolverFactory.createFromXmlResource("io/trygvis/acme/planning/machine/solver-config.xml"); + var solver = solverFactory.buildSolver(); + + var computers = new ArrayList(); + + computers.add(new CloudComputer("acme-1", DEV1_S)); + computers.add(new CloudComputer("acme-2", DEV1_M)); + computers.add(new CloudComputer("acme-3", DEV1_S)); + + var processes = new ArrayList(); + + processes.add(new CloudProcess("statera", 200, 1000)); + processes.add(new CloudProcess("statera-console", 100, 50)); + processes.add(new CloudProcess("4tune-web", 100, 50)); + processes.add(new CloudProcess("4tune-api", 200, 200)); + processes.add(new CloudProcess("pdb", 500, 500)); + processes.add(new CloudProcess("mdb", 500, 200)); + + var unsolvedCloudBalance = new CloudBalance(computers, processes); + + var solvedCloudBalance = solver.solve(unsolvedCloudBalance); + + System.out.println("solvedCloudBalance.getScore() = " + solvedCloudBalance.getScore()); + for (CloudProcess process : solvedCloudBalance.getProcessList()) { + System.out.println("process.id = " + process.id); + if (process.computer == null) { + System.out.println("COMPUTER IS NULL"); + } else { + System.out.println("process.computer.host = " + process.computer.host); + } + } + + System.out.println("------------------------------------------------------------------------"); + +// System.out.println("\nSolved cloudBalance with 400 computers and 1200 processes:\n" +// + toDisplayString(solvedCloudBalance)); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java new file mode 100644 index 0000000..c629656 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudPlanner.java @@ -0,0 +1,22 @@ +package io.trygvis.acme.planning.machine; + +import org.optaplanner.core.api.domain.entity.PlanningEntity; +import org.optaplanner.core.api.domain.variable.PlanningVariable; + +@PlanningEntity() +public class CloudPlanner { + private int requiredCpuPower; + private int requiredMemory; + private int requiredNetworkBandwidth; + + private CloudComputer computer; + + @PlanningVariable(valueRangeProviderRefs = {"computerRange"}) + public CloudComputer getComputer() { + return computer; + } + + public void setComputer(CloudComputer computer) { + this.computer = computer; + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java new file mode 100644 index 0000000..2002903 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcess.java @@ -0,0 +1,48 @@ +package io.trygvis.acme.planning.machine; + +import org.apache.commons.lang3.builder.CompareToBuilder; +import org.optaplanner.core.api.domain.entity.PlanningEntity; +import org.optaplanner.core.api.domain.variable.PlanningVariable; + +import java.util.Comparator; + +@PlanningEntity(difficultyComparatorClass = CloudProcessDifficultyComparator.class) +public class CloudProcess { + public String id; + public int requiredCpu; + public int requiredMemory; + public int requiredMultiplicand; + + @PlanningVariable( + valueRangeProviderRefs = "computerRange", + strengthComparatorClass = CloudComputerStrengthComparator.class) + public CloudComputer computer; + + public CloudProcess(String id, int requiredCpu, int requiredMemory) { + this.id = id; + this.requiredCpu = requiredCpu; + this.requiredMemory = requiredMemory; + + this.requiredMultiplicand = requiredCpu * requiredMemory; + } + + @SuppressWarnings("unused") + public CloudProcess() { + } + + public String toString() { + return id; + } + + public static class CloudComputerStrengthComparator implements Comparator { + public int compare(CloudComputer a, CloudComputer b) { + var x = a.instance; + var y = b.instance; + return new CompareToBuilder() + .append(x.multiplicand, y.multiplicand) + .append(y.cost, x.cost) // Descending (but this is debatable) + .append(x.kind, y.kind) + .toComparison(); + } + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java new file mode 100644 index 0000000..658e826 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/CloudProcessDifficultyComparator.java @@ -0,0 +1,15 @@ +package io.trygvis.acme.planning.machine; + +import org.apache.commons.lang3.builder.CompareToBuilder; + +import java.util.Comparator; + +public class CloudProcessDifficultyComparator implements Comparator { + + public int compare(CloudProcess a, CloudProcess b) { + return new CompareToBuilder() + .append(a.requiredMultiplicand, b.requiredMultiplicand) + .append(a.id, b.id) + .toComparison(); + } +} diff --git a/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java new file mode 100644 index 0000000..dfdc0e0 --- /dev/null +++ b/src/ri-planner/src/main/java/io/trygvis/acme/planning/machine/ScalewayInstance.java @@ -0,0 +1,25 @@ +package io.trygvis.acme.planning.machine; + +public class ScalewayInstance { + public final String kind; + // Euros / hour + public final double cost; + public final int cpu; + public final int memory; + + public int multiplicand; + + public ScalewayInstance(String kind, double cost, int cpu, int memory) { + this.kind = kind; + this.cost = cost; + this.cpu = cpu; + this.memory = memory; + + this.multiplicand = cpu * memory; + } + + @Override + public String toString() { + return kind; + } +} -- cgit v1.2.3