blob: 94f58566647114475fd1d3c7b4566b412cfcb6a6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.wayang.core.optimizer.costs;
import org.apache.wayang.core.function.FunctionDescriptor;
import org.apache.wayang.core.plan.wayangplan.Operator;
import org.apache.wayang.core.util.JsonSerializable;
import org.apache.wayang.core.util.JsonSerializables;
import java.util.Collection;
import java.util.LinkedList;
import org.apache.wayang.core.util.json.JSONObject;
/**
* Reflects the (estimated) required resources of an {@link Operator} or {@link FunctionDescriptor}.
*/
public class LoadProfile implements JsonSerializable {
/**
* Instance with all values set to {@code 0}.
*/
public static final LoadProfile emptyLoadProfile = new LoadProfile(
new LoadEstimate(0),
new LoadEstimate(0),
new LoadEstimate(0),
new LoadEstimate(0)
);
private final LoadEstimate cpuUsage, ramUsage, networkUsage, diskUsage;
private final Collection<LoadProfile> subprofiles = new LinkedList<>();
/**
* The resource utilization of this load profile.
*/
private double resourceUtilization = 1d;
/**
* Overhead time that occurs when working on this load profile.
*/
private long overheadMillis;
/**
* Creates a new instance without network and disk usage, full resource utilization, and no overhead.
*
* @param cpuUsage the CPU load
* @param ramUsage the RAM load
*/
public LoadProfile(LoadEstimate cpuUsage, LoadEstimate ramUsage) {
this(cpuUsage, ramUsage, null, null);
}
/**
* Creates a new instance with full resource utilization, and no overhead.
*
* @param cpuUsage the CPU load
* @param ramUsage the RAM load
* @param networkUsage the network load
* @param diskUsage the disk load
*/
public LoadProfile(LoadEstimate cpuUsage,
LoadEstimate ramUsage,
LoadEstimate networkUsage,
LoadEstimate diskUsage) {
this(cpuUsage, ramUsage, networkUsage, diskUsage, 1d, 0);
}
/**
* Creates a new instance.
*
* @param cpuUsage the CPU load
* @param ramUsage the RAM load
* @param networkUsage the network load
* @param diskUsage the disk load
* @param resourceUtilization resource utilization in the interval {@code [0, 1]}
* @param overheadMillis static overhead in milliseconds
*/
public LoadProfile(LoadEstimate cpuUsage,
LoadEstimate ramUsage,
LoadEstimate networkUsage,
LoadEstimate diskUsage,
double resourceUtilization,
long overheadMillis) {
this.cpuUsage = cpuUsage;
this.ramUsage = ramUsage;
this.networkUsage = networkUsage;
this.diskUsage = diskUsage;
this.overheadMillis = overheadMillis;
this.resourceUtilization = resourceUtilization;
}
public LoadEstimate getCpuUsage() {
return this.cpuUsage;
}
public LoadEstimate getRamUsage() {
return this.ramUsage;
}
public LoadEstimate getNetworkUsage() {
return this.networkUsage;
}
public LoadEstimate getDiskUsage() {
return this.diskUsage;
}
public Collection<LoadProfile> getSubprofiles() {
return this.subprofiles;
}
public void nest(LoadProfile subprofile) {
this.subprofiles.add(subprofile);
}
public long getOverheadMillis() {
return this.overheadMillis;
}
public void setOverheadMillis(long overheadMillis) {
this.overheadMillis = overheadMillis;
}
public double getResourceUtilization() {
return resourceUtilization;
}
public void setResourceUtilization(double resourceUtilization) {
this.resourceUtilization = resourceUtilization;
}
/**
* Multiplies the values of this instance and nested instances except for the RAM usage, which will not be altered.
* This is to represent this instance occurring sequentially (not simultaneously) {@code n} times.
*
* @param n the factor to multiply with
* @return the product
*/
public LoadProfile timesSequential(int n) {
if (n == 1) return this;
LoadProfile product = new LoadProfile(
this.cpuUsage.times(n),
this.ramUsage,
this.networkUsage != null ? this.networkUsage.times(n) : null,
this.diskUsage != null ? this.diskUsage.times(n) : null,
this.resourceUtilization,
this.overheadMillis
);
for (LoadProfile subprofile : this.getSubprofiles()) {
product.nest(subprofile.timesSequential(n));
}
return product;
}
/**
* Adds a this and the given instance.
*
* @param that the other summand
* @return a new instance representing the sum
*/
public LoadProfile plus(LoadProfile that) {
return new LoadProfile(
LoadEstimate.add(this.cpuUsage, that.cpuUsage),
LoadEstimate.add(this.ramUsage, that.ramUsage),
LoadEstimate.add(this.networkUsage, that.networkUsage),
LoadEstimate.add(this.diskUsage, that.diskUsage),
(this.resourceUtilization + that.resourceUtilization) / 2,
this.overheadMillis + that.overheadMillis
);
}
@Override
public JSONObject toJson() {
JSONObject json = new JSONObject();
json.put("cpu", JsonSerializables.serialize(this.cpuUsage, false));
json.put("ram", JsonSerializables.serialize(this.ramUsage, false));
json.putOpt("network", JsonSerializables.serialize(this.networkUsage, false));
json.putOpt("disk", JsonSerializables.serialize(this.diskUsage, false));
json.put("utilization", this.resourceUtilization);
json.put("overhead", this.overheadMillis);
return json;
}
@SuppressWarnings("unused")
public static LoadProfile fromJson(JSONObject jsonObject) {
return new LoadProfile(
JsonSerializables.deserialize(jsonObject.getJSONObject("cpu"), LoadEstimate.class),
JsonSerializables.deserialize(jsonObject.getJSONObject("ram"), LoadEstimate.class),
JsonSerializables.deserialize(jsonObject.optJSONObject("network"), LoadEstimate.class),
JsonSerializables.deserialize(jsonObject.optJSONObject("disk"), LoadEstimate.class),
jsonObject.getDouble("utilization"),
jsonObject.getLong("overhead")
);
}
}