diff options
| author | Dante Niewenhuis <d.niewenhuis@hotmail.com> | 2024-10-25 13:32:41 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-25 13:32:41 +0200 |
| commit | 5a365dbc068f2a8cdfa9813c39cc84bb30e15637 (patch) | |
| tree | 72716d562787b85e03cdc7fe1d30c827054d25a0 /opendc-compute/opendc-compute-simulator/src/main/java/org/opendc | |
| parent | 27f5b7dcb05aefdab9b762175d538931face0aba (diff) | |
Rewrote the FlowEngine (#256)
* Removed unused components. Updated tests.
Improved checkpointing model
Improved model, started with SimPowerSource
implemented FailureModels and Checkpointing
First working version
midway commit
first update
All simulation are now run with a single CPU and single MemoryUnit. multi CPUs are combined into one. This is for performance and explainability.
* fixed merge conflicts
* Updated M3SA paths.
* Fixed small typo
Diffstat (limited to 'opendc-compute/opendc-compute-simulator/src/main/java/org/opendc')
13 files changed, 1497 insertions, 0 deletions
diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostListener.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostListener.java new file mode 100644 index 00000000..01acfa97 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostListener.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.host; + +import org.opendc.compute.api.TaskState; +import org.opendc.compute.simulator.service.ServiceTask; + +/** + * Listener interface for events originating from a {@link SimHost}. + */ +public interface HostListener { + /** + * This method is invoked when the state of <code>task</code> on <code>host</code> changes. + */ + default void onStateChanged(SimHost host, ServiceTask task, TaskState newState) {} + + /** + * This method is invoked when the state of a {@link SimHost} has changed. + */ + default void onStateChanged(SimHost host, HostState newState) {} +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostModel.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostModel.java new file mode 100644 index 00000000..96236c5c --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostModel.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.host; + +/** + * Record describing the static machine properties of the host. + * + * @param cpuCapacity The total CPU capacity of the host in MHz. + * @param coreCount The number of logical processing cores available for this host. + * @param memoryCapacity The amount of memory available for this host in MB. + */ +public record HostModel(float cpuCapacity, int coreCount, long memoryCapacity) {} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostState.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostState.java new file mode 100644 index 00000000..29fc8cb4 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/host/HostState.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.host; + +/** + * The state of a host. + */ +public enum HostState { + /** + * The host is up and able to host guests. + */ + UP, + + /** + * The host is in a (forced) down state and unable to host any guests. + */ + DOWN, + + /** + * The host is in an error state and unable to host any guests. + */ + ERROR +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ComputeService.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ComputeService.java new file mode 100644 index 00000000..84e23516 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ComputeService.java @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.service; + +import java.time.Duration; +import java.time.Instant; +import java.time.InstantSource; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.SplittableRandom; +import java.util.UUID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.opendc.common.Dispatcher; +import org.opendc.common.util.Pacer; +import org.opendc.compute.api.Flavor; +import org.opendc.compute.api.Image; +import org.opendc.compute.api.TaskState; +import org.opendc.compute.simulator.host.HostListener; +import org.opendc.compute.simulator.host.HostModel; +import org.opendc.compute.simulator.host.HostState; +import org.opendc.compute.simulator.host.SimHost; +import org.opendc.compute.simulator.scheduler.ComputeScheduler; +import org.opendc.compute.simulator.telemetry.SchedulerStats; +import org.opendc.simulator.compute.workload.Workload; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link ComputeService} hosts the API implementation of the OpenDC Compute Engine. + */ +public final class ComputeService implements AutoCloseable { + private static final Logger LOGGER = LoggerFactory.getLogger(ComputeService.class); + + /** + * The {@link InstantSource} representing the clock tracking the (simulation) time. + */ + private final InstantSource clock; + + /** + * The {@link ComputeScheduler} responsible for placing the tasks onto hosts. + */ + private final ComputeScheduler scheduler; + + /** + * The {@link Pacer} used to pace the scheduling requests. + */ + private final Pacer pacer; + + /** + * The {@link SplittableRandom} used to generate the unique identifiers for the service resources. + */ + private final SplittableRandom random = new SplittableRandom(0); + + private final int maxNumFailures; + + /** + * A flag to indicate that the service is closed. + */ + private boolean isClosed; + + /** + * A mapping from host to host view. + */ + private final Map<SimHost, HostView> hostToView = new HashMap<>(); + + /** + * The available hypervisors. + */ + private final Set<HostView> availableHosts = new HashSet<>(); + + /** + * The tasks that should be launched by the service. + */ + private final Deque<SchedulingRequest> taskQueue = new ArrayDeque<>(); + + /** + * The active tasks in the system. + */ + private final Map<ServiceTask, SimHost> activeTasks = new HashMap<>(); + + /** + * The active tasks in the system. + */ + private final Map<ServiceTask, SimHost> completedTasks = new HashMap<>(); + + /** + * The registered flavors for this compute service. + */ + private final Map<UUID, ServiceFlavor> flavorById = new HashMap<>(); + + private final List<ServiceFlavor> flavors = new ArrayList<>(); + + /** + * The registered images for this compute service. + */ + private final Map<UUID, ServiceImage> imageById = new HashMap<>(); + + private final List<ServiceImage> images = new ArrayList<>(); + + /** + * The registered tasks for this compute service. + */ + private final Map<UUID, ServiceTask> taskById = new HashMap<>(); + + private final List<ServiceTask> tasks = new ArrayList<>(); + + private final List<ServiceTask> tasksToRemove = new ArrayList<>(); + + /** + * A [HostListener] used to track the active tasks. + */ + private final HostListener hostListener = new HostListener() { + @Override + public void onStateChanged(@NotNull SimHost host, @NotNull HostState newState) { + LOGGER.debug("Host {} state changed: {}", host, newState); + + final HostView hv = hostToView.get(host); + + if (hv != null) { + if (newState == HostState.UP) { + availableHosts.add(hv); + } else { + availableHosts.remove(hv); + } + } + + // Re-schedule on the new machine + requestSchedulingCycle(); + } + + @Override + public void onStateChanged(@NotNull SimHost host, @NotNull ServiceTask task, @NotNull TaskState newState) { + if (task.getHost() != host) { + // This can happen when a task is rescheduled and started on another machine, while being deleted from + // the old machine. + return; + } + + task.setState(newState); + + if (newState == TaskState.COMPLETED || newState == TaskState.TERMINATED || newState == TaskState.FAILED) { + LOGGER.info("task {} {} {} finished", task.getUid(), task.getName(), task.getFlavor()); + + if (activeTasks.remove(task) != null) { + tasksActive--; + } + + HostView hv = hostToView.get(host); + final ServiceFlavor flavor = task.getFlavor(); + if (hv != null) { + hv.provisionedCores -= flavor.getCoreCount(); + hv.instanceCount--; + hv.availableMemory += flavor.getMemorySize(); + } else { + LOGGER.error("Unknown host {}", host); + } + + task.setHost(null); + host.removeTask(task); + + if (newState == TaskState.COMPLETED) { + tasksCompleted++; + } + if (newState == TaskState.TERMINATED) { + tasksTerminated++; + } + + if (task.getState() == TaskState.COMPLETED || task.getState() == TaskState.TERMINATED) { + tasksToRemove.add(task); + } + + // Try to reschedule if needed + requestSchedulingCycle(); + } + } + }; + + private int maxCores = 0; + private long maxMemory = 0L; + private long attemptsSuccess = 0L; + private long attemptsFailure = 0L; + private int tasksTotal = 0; + private int tasksPending = 0; + private int tasksActive = 0; + private int tasksTerminated = 0; + private int tasksCompleted = 0; + + /** + * Construct a {@link ComputeService} instance. + */ + public ComputeService(Dispatcher dispatcher, ComputeScheduler scheduler, Duration quantum, int maxNumFailures) { + this.clock = dispatcher.getTimeSource(); + this.scheduler = scheduler; + this.pacer = new Pacer(dispatcher, quantum.toMillis(), (time) -> doSchedule()); + this.maxNumFailures = maxNumFailures; + } + + /** + * Create a new {@link Builder} instance. + */ + public static Builder builder(Dispatcher dispatcher, ComputeScheduler scheduler) { + return new Builder(dispatcher, scheduler); + } + + /** + * Create a new {@link ComputeClient} to control the compute service. + */ + public ComputeClient newClient() { + if (isClosed) { + throw new IllegalStateException("Service is closed"); + } + return new ComputeClient(this); + } + + /** + * Return the {@link ServiceTask}s hosted by this service. + */ + public List<ServiceTask> getTasks() { + return Collections.unmodifiableList(tasks); + } + + /** + * Return the {@link ServiceTask}s hosted by this service. + */ + public List<ServiceTask> getTasksToRemove() { + return Collections.unmodifiableList(tasksToRemove); + } + + public void clearTasksToRemove() { + this.tasksToRemove.clear(); + } + + /** + * Add a {@link SimHost} to the scheduling pool of the compute service. + */ + public void addHost(SimHost host) { + // Check if host is already known + if (hostToView.containsKey(host)) { + return; + } + + HostView hv = new HostView(host); + HostModel model = host.getModel(); + + maxCores = Math.max(maxCores, model.coreCount()); + maxMemory = Math.max(maxMemory, model.memoryCapacity()); + hostToView.put(host, hv); + + if (host.getState() == HostState.UP) { + availableHosts.add(hv); + } + + scheduler.addHost(hv); + host.addListener(hostListener); + } + + /** + * Remove a {@link SimHost} from the scheduling pool of the compute service. + */ + public void removeHost(SimHost host) { + HostView view = hostToView.remove(host); + if (view != null) { + availableHosts.remove(view); + scheduler.removeHost(view); + host.removeListener(hostListener); + } + } + + /** + * Lookup the {@link SimHost} that currently hosts the specified {@link ServiceTask}. + */ + public SimHost lookupHost(ServiceTask task) { + return task.getHost(); + } + + /** + * Return the {@link SimHost}s that are registered with this service. + */ + public Set<SimHost> getHosts() { + return Collections.unmodifiableSet(hostToView.keySet()); + } + + public InstantSource getClock() { + return this.clock; + } + + /** + * Collect the statistics about the scheduler component of this service. + */ + public SchedulerStats getSchedulerStats() { + return new SchedulerStats( + availableHosts.size(), + hostToView.size() - availableHosts.size(), + attemptsSuccess, + attemptsFailure, + tasksTotal, + tasksPending, + tasksActive, + tasksCompleted, + tasksTerminated); + } + + @Override + public void close() { + if (isClosed) { + return; + } + + isClosed = true; + pacer.cancel(); + } + + /** + * Enqueue the specified [task] to be scheduled onto a host. + */ + SchedulingRequest schedule(ServiceTask task) { + LOGGER.debug("Enqueueing task {} to be assigned to host", task.getUid()); + + long now = clock.millis(); + SchedulingRequest request = new SchedulingRequest(task, now); + + task.launchedAt = Instant.ofEpochMilli(now); + taskQueue.add(request); + tasksPending++; + requestSchedulingCycle(); + return request; + } + + void delete(ServiceFlavor flavor) { + flavorById.remove(flavor.getUid()); + flavors.remove(flavor); + } + + void delete(ServiceImage image) { + imageById.remove(image.getUid()); + images.remove(image); + } + + void delete(ServiceTask task) { + completedTasks.remove(task); + taskById.remove(task.getUid()); + tasks.remove(task); + } + + /** + * Indicate that a new scheduling cycle is needed due to a change to the service's state. + */ + private void requestSchedulingCycle() { + // Bail out in case the queue is empty. + if (taskQueue.isEmpty()) { + return; + } + + pacer.enqueue(); + } + + /** + * Run a single scheduling iteration. + */ + private void doSchedule() { + // reorder tasks + + while (!taskQueue.isEmpty()) { + SchedulingRequest request = taskQueue.peek(); + + if (request.isCancelled) { + taskQueue.poll(); + tasksPending--; + continue; + } + + final ServiceTask task = request.task; + + if (task.getNumFailures() >= maxNumFailures) { + LOGGER.warn("task {} has been terminated because it failed {} times", task, task.getNumFailures()); + + taskQueue.poll(); + tasksPending--; + tasksTerminated++; + task.setState(TaskState.TERMINATED); + tasksToRemove.add(task); + continue; + } + + final ServiceFlavor flavor = task.getFlavor(); + final HostView hv = scheduler.select(request.task); + + if (hv == null || !hv.getHost().canFit(task)) { + LOGGER.trace("Task {} selected for scheduling but no capacity available for it at the moment", task); + + if (flavor.getMemorySize() > maxMemory || flavor.getCoreCount() > maxCores) { + // Remove the incoming image + taskQueue.poll(); + tasksPending--; + + LOGGER.warn("Failed to spawn {}: does not fit", task); + + task.setState(TaskState.FAILED); + continue; + } else { + break; + } + } + + SimHost host = hv.getHost(); + + // Remove request from queue + taskQueue.poll(); + tasksPending--; + + LOGGER.info("Assigned task {} to host {}", task, host); + + try { + task.host = host; + + host.spawn(task); + // host.start(task); + + tasksActive++; + attemptsSuccess++; + + hv.instanceCount++; + hv.provisionedCores += flavor.getCoreCount(); + hv.availableMemory -= flavor.getMemorySize(); + + activeTasks.put(task, host); + } catch (Exception cause) { + LOGGER.error("Failed to deploy VM", cause); + attemptsFailure++; + } + } + } + + /** + * Builder class for a {@link ComputeService}. + */ + public static class Builder { + private final Dispatcher dispatcher; + private final ComputeScheduler computeScheduler; + private Duration quantum = Duration.ofSeconds(1); + private int maxNumFailures = 10; + + Builder(Dispatcher dispatcher, ComputeScheduler computeScheduler) { + this.dispatcher = dispatcher; + this.computeScheduler = computeScheduler; + } + + /** + * Set the scheduling quantum of the service. + */ + public Builder withQuantum(Duration quantum) { + this.quantum = quantum; + return this; + } + + public Builder withMaxNumFailures(int maxNumFailures) { + this.maxNumFailures = maxNumFailures; + return this; + } + + /** + * Build a {@link ComputeService}. + */ + public ComputeService build() { + return new ComputeService(dispatcher, computeScheduler, quantum, maxNumFailures); + } + } + + /** + * Implementation of {@link ComputeClient} using a {@link ComputeService}. + */ + public static class ComputeClient { + private final ComputeService service; + private boolean isClosed; + + ComputeClient(ComputeService service) { + this.service = service; + } + + /** + * Method to check if the client is still open and throw an exception if it is not. + */ + private void checkOpen() { + if (isClosed) { + throw new IllegalStateException("Client is already closed"); + } + } + + @NotNull + public List<Flavor> queryFlavors() { + checkOpen(); + return new ArrayList<>(service.flavors); + } + + public Flavor findFlavor(@NotNull UUID id) { + checkOpen(); + + return service.flavorById.get(id); + } + + @NotNull + public Flavor newFlavor(@NotNull String name, int cpuCount, long memorySize, @NotNull Map<String, ?> meta) { + checkOpen(); + + final ComputeService service = this.service; + UUID uid = new UUID(service.clock.millis(), service.random.nextLong()); + ServiceFlavor flavor = new ServiceFlavor(service, uid, name, cpuCount, memorySize, meta); + + service.flavorById.put(uid, flavor); + service.flavors.add(flavor); + + return flavor; + } + + @NotNull + public List<Image> queryImages() { + checkOpen(); + + return new ArrayList<>(service.images); + } + + public Image findImage(@NotNull UUID id) { + checkOpen(); + + return service.imageById.get(id); + } + + public Image newImage(@NotNull String name) { + return newImage(name, Collections.emptyMap(), Collections.emptyMap()); + } + + @NotNull + public Image newImage(@NotNull String name, @NotNull Map<String, String> labels, @NotNull Map<String, ?> meta) { + checkOpen(); + + final ComputeService service = this.service; + UUID uid = new UUID(service.clock.millis(), service.random.nextLong()); + + ServiceImage image = new ServiceImage(service, uid, name, labels, meta); + + service.imageById.put(uid, image); + service.images.add(image); + + return image; + } + + @NotNull + public ServiceTask newTask( + @NotNull String name, + @NotNull Flavor flavor, + @NotNull Workload workload, + @NotNull Map<String, ?> meta) { + checkOpen(); + + final ComputeService service = this.service; + UUID uid = new UUID(service.clock.millis(), service.random.nextLong()); + + final ServiceFlavor internalFlavor = + Objects.requireNonNull(service.flavorById.get(flavor.getUid()), "Unknown flavor"); + + ServiceTask task = new ServiceTask(service, uid, name, internalFlavor, workload, meta); + + service.taskById.put(uid, task); + service.tasks.add(task); + + service.tasksTotal++; + + task.start(); + + return task; + } + + @Nullable + public ServiceTask findTask(@NotNull UUID id) { + checkOpen(); + return service.taskById.get(id); + } + + @NotNull + public List<ServiceTask> queryTasks() { + checkOpen(); + + return new ArrayList<>(service.tasks); + } + + public void close() { + isClosed = true; + } + + @Override + public String toString() { + return "ComputeService.Client"; + } + + @Nullable + public void rescheduleTask(@NotNull ServiceTask task, @NotNull Workload workload) { + ServiceTask internalTask = findTask(task.getUid()); + // SimHost from = service.lookupHost(internalTask); + + // from.delete(internalTask); + + internalTask.host = null; + + internalTask.setWorkload(workload); + internalTask.start(); + } + } + + /** + * A request to schedule a {@link ServiceTask} onto one of the {@link SimHost}s. + */ + static class SchedulingRequest { + final ServiceTask task; + final long submitTime; + + boolean isCancelled; + + SchedulingRequest(ServiceTask task, long submitTime) { + this.task = task; + this.submitTime = submitTime; + } + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/HostView.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/HostView.java new file mode 100644 index 00000000..f4aa9c70 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/HostView.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.service; + +import org.opendc.compute.simulator.host.SimHost; + +/** + * A view of a {@link SimHost} as seen from the {@link ComputeService}. + */ +public class HostView { + private final SimHost host; + int instanceCount; + long availableMemory; + int provisionedCores; + + /** + * Construct a {@link HostView} instance. + * + * @param host The host to create a view of. + */ + public HostView(SimHost host) { + this.host = host; + this.availableMemory = host.getModel().memoryCapacity(); + } + + /** + * The {@link SimHost} this is a view of. + */ + public SimHost getHost() { + return host; + } + + /** + * Return the number of instances on this host. + */ + public int getInstanceCount() { + return instanceCount; + } + + /** + * Return the available memory of the host. + */ + public long getAvailableMemory() { + return availableMemory; + } + + /** + * Return the provisioned cores on the host. + */ + public int getProvisionedCores() { + return provisionedCores; + } + + @Override + public String toString() { + return "HostView[host=" + host + "]"; + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceFlavor.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceFlavor.java new file mode 100644 index 00000000..eddde87e --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceFlavor.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.service; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import org.jetbrains.annotations.NotNull; +import org.opendc.compute.api.Flavor; + +/** + * Implementation of {@link Flavor} provided by {@link ComputeService}. + */ +public final class ServiceFlavor implements Flavor { + private final ComputeService service; + private final UUID uid; + private final String name; + private final int coreCount; + private final long memorySize; + private final Map<String, ?> meta; + + ServiceFlavor(ComputeService service, UUID uid, String name, int coreCount, long memorySize, Map<String, ?> meta) { + this.service = service; + this.uid = uid; + this.name = name; + this.coreCount = coreCount; + this.memorySize = memorySize; + this.meta = meta; + } + + @Override + public int getCoreCount() { + return coreCount; + } + + @Override + public long getMemorySize() { + return memorySize; + } + + @NotNull + @Override + public UUID getUid() { + return uid; + } + + @NotNull + @Override + public String getName() { + return name; + } + + @NotNull + @Override + public Map<String, Object> getMeta() { + return Collections.unmodifiableMap(meta); + } + + @Override + public void reload() { + // No-op: this object is the source-of-truth + } + + @Override + public void delete() { + service.delete(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ServiceFlavor flavor = (ServiceFlavor) o; + return service.equals(flavor.service) && uid.equals(flavor.uid); + } + + @Override + public int hashCode() { + return Objects.hash(service, uid); + } + + @Override + public String toString() { + return "Flavor[uid=" + uid + ",name=" + name + "]"; + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceImage.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceImage.java new file mode 100644 index 00000000..dffa4356 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceImage.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.service; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import org.jetbrains.annotations.NotNull; +import org.opendc.compute.api.Image; + +/** + * Implementation of {@link Image} provided by {@link ComputeService}. + */ +public final class ServiceImage implements Image { + private final ComputeService service; + private final UUID uid; + private final String name; + private final Map<String, String> labels; + private final Map<String, ?> meta; + + ServiceImage(ComputeService service, UUID uid, String name, Map<String, String> labels, Map<String, ?> meta) { + this.service = service; + this.uid = uid; + this.name = name; + this.labels = labels; + this.meta = meta; + } + + @NotNull + @Override + public UUID getUid() { + return uid; + } + + @NotNull + @Override + public String getName() { + return name; + } + + @NotNull + @Override + public Map<String, Object> getMeta() { + return Collections.unmodifiableMap(meta); + } + + @Override + public void reload() { + // No-op: this object is the source-of-truth + } + + @Override + public void delete() { + service.delete(this); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ServiceImage image = (ServiceImage) o; + return service.equals(image.service) && uid.equals(image.uid); + } + + @Override + public int hashCode() { + return Objects.hash(service, uid); + } + + @Override + public String toString() { + return "Image[uid=" + uid + ",name=" + name + "]"; + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceTask.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceTask.java new file mode 100644 index 00000000..f39142eb --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/service/ServiceTask.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.service; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.opendc.compute.api.TaskState; +import org.opendc.compute.simulator.TaskWatcher; +import org.opendc.compute.simulator.host.SimHost; +import org.opendc.simulator.compute.workload.Workload; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of {@link ServiceTask} provided by {@link ComputeService}. + */ +public class ServiceTask { + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceTask.class); + + private final ComputeService service; + private final UUID uid; + + private final String name; + private final ServiceFlavor flavor; + public Workload workload; + + private Map<String, ?> meta; // TODO: remove this + + private final List<TaskWatcher> watchers = new ArrayList<>(); + private TaskState state = TaskState.CREATED; + Instant launchedAt = null; + Instant createdAt; + Instant finishedAt; + SimHost host = null; + private ComputeService.SchedulingRequest request = null; + + private int numFailures = 0; + + ServiceTask( + ComputeService service, + UUID uid, + String name, + ServiceFlavor flavor, + Workload workload, + Map<String, ?> meta) { + this.service = service; + this.uid = uid; + this.name = name; + this.flavor = flavor; + this.workload = workload; + this.meta = meta; + + this.createdAt = this.service.getClock().instant(); + } + + @NotNull + public UUID getUid() { + return uid; + } + + @NotNull + public String getName() { + return name; + } + + @NotNull + public ServiceFlavor getFlavor() { + return flavor; + } + + @NotNull + public Map<String, Object> getMeta() { + return Collections.unmodifiableMap(meta); + } + + public void setWorkload(Workload newWorkload) { + this.workload = newWorkload; + } + + @NotNull + public TaskState getState() { + return state; + } + + @Nullable + public Instant getLaunchedAt() { + return launchedAt; + } + + @Nullable + public Instant getCreatedAt() { + return createdAt; + } + + @Nullable + public Instant getFinishedAt() { + return finishedAt; + } + + /** + * Return the {@link SimHost} on which the task is running or <code>null</code> if it is not running on a host. + */ + public SimHost getHost() { + return host; + } + + public void setHost(SimHost host) { + this.host = host; + } + + public int getNumFailures() { + return this.numFailures; + } + + public void start() { + switch (state) { + case PROVISIONING: + LOGGER.debug("User tried to start task but request is already pending: doing nothing"); + case RUNNING: + LOGGER.debug("User tried to start task but task is already running"); + break; + case COMPLETED: + case TERMINATED: + LOGGER.warn("User tried to start deleted task"); + throw new IllegalStateException("Task is deleted"); + case CREATED: + LOGGER.info("User requested to start task {}", uid); + setState(TaskState.PROVISIONING); + assert request == null : "Scheduling request already active"; + request = service.schedule(this); + break; + case FAILED: + LOGGER.info("User requested to start task after failure {}", uid); + setState(TaskState.PROVISIONING); + request = service.schedule(this); + break; + } + } + + public void watch(@NotNull TaskWatcher watcher) { + watchers.add(watcher); + } + + public void unwatch(@NotNull TaskWatcher watcher) { + watchers.remove(watcher); + } + + public void delete() { + cancelProvisioningRequest(); + final SimHost host = this.host; + if (host != null) { + host.delete(this); + } + service.delete(this); + + this.setState(TaskState.DELETED); + } + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ServiceTask task = (ServiceTask) o; + return service.equals(task.service) && uid.equals(task.uid); + } + + public int hashCode() { + return Objects.hash(service, uid); + } + + public String toString() { + return "Task[uid=" + uid + ",name=" + name + ",state=" + state + "]"; + } + + void setState(TaskState newState) { + if (this.state == newState) { + return; + } + + for (TaskWatcher watcher : watchers) { + watcher.onStateChanged(this, newState); + } + if (newState == TaskState.FAILED) { + this.numFailures++; + } + + if ((newState == TaskState.COMPLETED) || newState == TaskState.FAILED) { + this.finishedAt = this.service.getClock().instant(); + } + + this.state = newState; + } + + /** + * Cancel the provisioning request if active. + */ + private void cancelProvisioningRequest() { + final ComputeService.SchedulingRequest request = this.request; + if (request != null) { + this.request = null; + request.isCancelled = true; + } + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestCpuStats.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestCpuStats.java new file mode 100644 index 00000000..ea37f5f2 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestCpuStats.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.telemetry; + +/** + * Statistics about the CPUs of a guest. + * + * @param activeTime The cumulative time (in seconds) that the CPUs of the guest were actively running. + * @param idleTime The cumulative time (in seconds) the CPUs of the guest were idle. + * @param stealTime The cumulative CPU time (in seconds) that the guest was ready to run, but not granted time by the host. + * @param lostTime The cumulative CPU time (in seconds) that was lost due to interference with other machines. + * @param capacity The available CPU capacity of the guest (in MHz). + * @param usage Amount of CPU resources (in MHz) actually used by the guest. + * @param utilization The utilization of the CPU resources (in %) relative to the total CPU capacity. + */ +public record GuestCpuStats( + long activeTime, + long idleTime, + long stealTime, + long lostTime, + float capacity, + float usage, + float utilization) {} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestSystemStats.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestSystemStats.java new file mode 100644 index 00000000..0d51e223 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/GuestSystemStats.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.telemetry; + +import java.time.Duration; +import java.time.Instant; + +/** + * System-level statistics of a guest. + * + * @param uptime The cumulative uptime of the guest since last boot (in ms). + * @param downtime The cumulative downtime of the guest since last boot (in ms). + * @param bootTime The time at which the guest booted. + */ +public record GuestSystemStats(Duration uptime, Duration downtime, Instant bootTime) {} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostCpuStats.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostCpuStats.java new file mode 100644 index 00000000..3f2aab78 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostCpuStats.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.telemetry; + +/** + * Statistics about the CPUs of a host. + * + * @param activeTime The cumulative time (in seconds) that the CPUs of the host were actively running. + * @param idleTime The cumulative time (in seconds) the CPUs of the host were idle. + * @param stealTime The cumulative CPU time (in seconds) that virtual machines were ready to run, but were not able to. + * @param lostTime The cumulative CPU time (in seconds) that was lost due to interference between virtual machines. + * @param capacity The available CPU capacity of the host (in MHz). + * @param demand Amount of CPU resources (in MHz) the guests would use if there were no CPU contention or CPU + * limits. + * @param usage Amount of CPU resources (in MHz) actually used by the host. + * @param utilization The utilization of the CPU resources (in %) relative to the total CPU capacity. + */ +public record HostCpuStats( + long activeTime, + long idleTime, + long stealTime, + long lostTime, + float capacity, + float demand, + float usage, + float utilization) {} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostSystemStats.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostSystemStats.java new file mode 100644 index 00000000..353e62fa --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/HostSystemStats.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.telemetry; + +import java.time.Duration; +import java.time.Instant; + +/** + * System-level statistics of a host. + * + * @param uptime The cumulative uptime of the host since last boot (in ms). + * @param downtime The cumulative downtime of the host since last boot (in ms). + * @param bootTime The time at which the task started. + * @param powerDraw Instantaneous power draw of the system (in W). + * @param energyUsage The cumulative energy usage of the system (in J). + * @param guestsTerminated The number of guests that are in a terminated state. + * @param guestsRunning The number of guests that are in a running state. + * @param guestsError The number of guests that are in an error state. + * @param guestsInvalid The number of guests that are in an unknown state. + */ +public record HostSystemStats( + Duration uptime, + Duration downtime, + Instant bootTime, + float powerDraw, + float energyUsage, + int guestsTerminated, + int guestsRunning, + int guestsError, + int guestsInvalid) {} diff --git a/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/SchedulerStats.java b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/SchedulerStats.java new file mode 100644 index 00000000..9d44a4b8 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/java/org/opendc/compute/simulator/telemetry/SchedulerStats.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.compute.simulator.telemetry; + +/** + * Statistics about the scheduling component of the [ComputeService]. + * + * @param hostsAvailable The number of hosts currently available for scheduling. + * @param hostsUnavailable The number of hosts unavailable for scheduling. + * @param attemptsSuccess Scheduling attempts that resulted into an allocation onto a host. + * @param attemptsFailure The number of failed scheduling attempt due to any reason + * @param tasksTotal The number of tasks registered with the service. + * @param tasksPending The number of tasks that are pending to be scheduled. + * @param tasksActive The number of tasks that are currently managed by the service and running. + */ +public record SchedulerStats( + int hostsAvailable, + int hostsUnavailable, + long attemptsSuccess, + long attemptsFailure, + int tasksTotal, + int tasksPending, + int tasksActive, + int tasksCompleted, + int tasksTerminated) {} |
