/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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 org.optaplanner.examples.cloudbalancing.optional.score; import java.util.HashMap; import java.util.Map; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore; import org.optaplanner.core.impl.score.director.incremental.AbstractIncrementalScoreCalculator; import org.optaplanner.examples.cloudbalancing.domain.CloudBalance; import org.optaplanner.examples.cloudbalancing.domain.CloudComputer; import org.optaplanner.examples.cloudbalancing.domain.CloudProcess; public class CloudBalancingIncrementalScoreCalculator extends AbstractIncrementalScoreCalculator<CloudBalance> { private Map<CloudComputer, Integer> cpuPowerUsageMap; private Map<CloudComputer, Integer> memoryUsageMap; private Map<CloudComputer, Integer> networkBandwidthUsageMap; private Map<CloudComputer, Integer> processCountMap; private int hardScore; private int softScore; @Override public void resetWorkingSolution(CloudBalance cloudBalance) { int computerListSize = cloudBalance.getComputerList().size(); cpuPowerUsageMap = new HashMap<>(computerListSize); memoryUsageMap = new HashMap<>(computerListSize); networkBandwidthUsageMap = new HashMap<>(computerListSize); processCountMap = new HashMap<>(computerListSize); for (CloudComputer computer : cloudBalance.getComputerList()) { cpuPowerUsageMap.put(computer, 0); memoryUsageMap.put(computer, 0); networkBandwidthUsageMap.put(computer, 0); processCountMap.put(computer, 0); } hardScore = 0; softScore = 0; for (CloudProcess process : cloudBalance.getProcessList()) { insert(process); } } @Override public void beforeEntityAdded(Object entity) { // Do nothing } @Override public void afterEntityAdded(Object entity) { // TODO the maps should probably be adjusted insert((CloudProcess) entity); } @Override public void beforeVariableChanged(Object entity, String variableName) { retract((CloudProcess) entity); } @Override public void afterVariableChanged(Object entity, String variableName) { insert((CloudProcess) entity); } @Override public void beforeEntityRemoved(Object entity) { retract((CloudProcess) entity); } @Override public void afterEntityRemoved(Object entity) { // Do nothing // TODO the maps should probably be adjusted } private void insert(CloudProcess process) { CloudComputer computer = process.getComputer(); if (computer != null) { int cpuPower = computer.getCpuPower(); int oldCpuPowerUsage = cpuPowerUsageMap.get(computer); int oldCpuPowerAvailable = cpuPower - oldCpuPowerUsage; int newCpuPowerUsage = oldCpuPowerUsage + process.getRequiredCpuPower(); int newCpuPowerAvailable = cpuPower - newCpuPowerUsage; hardScore += Math.min(newCpuPowerAvailable, 0) - Math.min(oldCpuPowerAvailable, 0); cpuPowerUsageMap.put(computer, newCpuPowerUsage); int memory = computer.getMemory(); int oldMemoryUsage = memoryUsageMap.get(computer); int oldMemoryAvailable = memory - oldMemoryUsage; int newMemoryUsage = oldMemoryUsage + process.getRequiredMemory(); int newMemoryAvailable = memory - newMemoryUsage; hardScore += Math.min(newMemoryAvailable, 0) - Math.min(oldMemoryAvailable, 0); memoryUsageMap.put(computer, newMemoryUsage); int networkBandwidth = computer.getNetworkBandwidth(); int oldNetworkBandwidthUsage = networkBandwidthUsageMap.get(computer); int oldNetworkBandwidthAvailable = networkBandwidth - oldNetworkBandwidthUsage; int newNetworkBandwidthUsage = oldNetworkBandwidthUsage + process.getRequiredNetworkBandwidth(); int newNetworkBandwidthAvailable = networkBandwidth - newNetworkBandwidthUsage; hardScore += Math.min(newNetworkBandwidthAvailable, 0) - Math.min(oldNetworkBandwidthAvailable, 0); networkBandwidthUsageMap.put(computer, newNetworkBandwidthUsage); int oldProcessCount = processCountMap.get(computer); if (oldProcessCount == 0) { softScore -= computer.getCost(); } int newProcessCount = oldProcessCount + 1; processCountMap.put(computer, newProcessCount); } } private void retract(CloudProcess process) { CloudComputer computer = process.getComputer(); if (computer != null) { int cpuPower = computer.getCpuPower(); int oldCpuPowerUsage = cpuPowerUsageMap.get(computer); int oldCpuPowerAvailable = cpuPower - oldCpuPowerUsage; int newCpuPowerUsage = oldCpuPowerUsage - process.getRequiredCpuPower(); int newCpuPowerAvailable = cpuPower - newCpuPowerUsage; hardScore += Math.min(newCpuPowerAvailable, 0) - Math.min(oldCpuPowerAvailable, 0); cpuPowerUsageMap.put(computer, newCpuPowerUsage); int memory = computer.getMemory(); int oldMemoryUsage = memoryUsageMap.get(computer); int oldMemoryAvailable = memory - oldMemoryUsage; int newMemoryUsage = oldMemoryUsage - process.getRequiredMemory(); int newMemoryAvailable = memory - newMemoryUsage; hardScore += Math.min(newMemoryAvailable, 0) - Math.min(oldMemoryAvailable, 0); memoryUsageMap.put(computer, newMemoryUsage); int networkBandwidth = computer.getNetworkBandwidth(); int oldNetworkBandwidthUsage = networkBandwidthUsageMap.get(computer); int oldNetworkBandwidthAvailable = networkBandwidth - oldNetworkBandwidthUsage; int newNetworkBandwidthUsage = oldNetworkBandwidthUsage - process.getRequiredNetworkBandwidth(); int newNetworkBandwidthAvailable = networkBandwidth - newNetworkBandwidthUsage; hardScore += Math.min(newNetworkBandwidthAvailable, 0) - Math.min(oldNetworkBandwidthAvailable, 0); networkBandwidthUsageMap.put(computer, newNetworkBandwidthUsage); int oldProcessCount = processCountMap.get(computer); int newProcessCount = oldProcessCount - 1; if (newProcessCount == 0) { softScore += computer.getCost(); } processCountMap.put(computer, newProcessCount); } } @Override public HardSoftScore calculateScore() { return HardSoftScore.valueOf(hardScore, softScore); } }