From 0ec2b285d1ecb2b806e3ee89bc4478db8a7ae106 Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Wed, 30 Oct 2024 16:29:17 +0100 Subject: [PATCH 1/3] Added power sources to OpenDC. In the current form each Cluster has a single power source that is connected to all hosts in that cluster --- .../simulator/service/ComputeService.java | 19 + .../opendc/compute/simulator/host/SimHost.kt | 3 + .../simulator/provisioner/ComputeSteps.kt | 3 +- .../provisioner/HostsProvisioningStep.kt | 61 +- .../telemetry/ComputeMetricReader.kt | 532 +----------------- .../simulator/telemetry/ComputeMonitor.kt | 6 + .../telemetry/parquet/ComputeExportConfig.kt | 36 +- .../parquet/DfltPowerSourceExportColumns.kt | 91 +++ .../parquet/ParquetComputeMonitor.kt | 17 +- .../telemetry/table/HostTableReader.kt | 4 + .../telemetry/table/HostTableReaderImpl.kt | 218 +++++++ .../telemetry/table/PowerSourceTableReader.kt | 73 +++ .../table/PowerSourceTableReaderImpl.kt | 96 ++++ .../telemetry/table/ServiceTableReader.kt | 2 + .../telemetry/table/ServiceTableReaderImpl.kt | 101 ++++ .../telemetry/table/TaskTableReader.kt | 4 + .../telemetry/table/TaskTableReaderImpl.kt | 196 +++++++ .../compute/topology/TopologyFactories.kt | 34 +- .../compute/topology/specs/ClusterSpec.kt | 7 + .../compute/topology/specs/PowerSourceSpec.kt | 11 + .../compute/topology/specs/TopologySpecs.kt | 36 +- .../base/ScenarioIntegrationTest.kt | 4 +- .../simulator/compute/machine/SimMachine.java | 5 +- .../compute/power/SimPowerSource.java | 17 +- .../simulator/compute/power/SimPsu.java | 26 +- .../compute/workload/SimTraceWorkload.java | 16 - .../org/opendc/web/runner/OpenDCRunner.kt | 8 +- 27 files changed, 1024 insertions(+), 602 deletions(-) create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltPowerSourceExportColumns.kt create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt create mode 100644 opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt create mode 100644 opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt create mode 100644 opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt 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 index 84e23516b..f64475730 100644 --- 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 @@ -50,6 +50,7 @@ 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.power.SimPowerSource; import org.opendc.simulator.compute.workload.Workload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,6 +98,11 @@ public final class ComputeService implements AutoCloseable { */ private final Set availableHosts = new HashSet<>(); + /** + * The available powerSources + */ + private final Set powerSources = new HashSet<>(); + /** * The tasks that should be launched by the service. */ @@ -283,6 +289,15 @@ public void addHost(SimHost host) { host.addListener(hostListener); } + public void addPowerSource(SimPowerSource simPowerSource) { + // Check if host is already known + if (powerSources.contains(simPowerSource)) { + return; + } + + powerSources.add(simPowerSource); + } + /** * Remove a {@link SimHost} from the scheduling pool of the compute service. */ @@ -313,6 +328,10 @@ public InstantSource getClock() { return this.clock; } + public Set getPowerSources() { + return Collections.unmodifiableSet(this.powerSources); + } + /** * Collect the statistics about the scheduler component of this service. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt index 31ff384cf..c7b94f93c 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt @@ -31,6 +31,7 @@ import org.opendc.compute.simulator.telemetry.GuestCpuStats import org.opendc.compute.simulator.telemetry.GuestSystemStats import org.opendc.compute.simulator.telemetry.HostCpuStats import org.opendc.compute.simulator.telemetry.HostSystemStats +import org.opendc.simulator.Multiplexer import org.opendc.simulator.compute.cpu.CpuPowerModel import org.opendc.simulator.compute.machine.SimMachine import org.opendc.simulator.compute.models.MachineModel @@ -61,6 +62,7 @@ public class SimHost( private val graph: FlowGraph, private val machineModel: MachineModel, private val powerModel: CpuPowerModel, + private val powerMux: Multiplexer ) : AutoCloseable { /** * The event listeners registered with this host. @@ -130,6 +132,7 @@ public class SimHost( this.graph, this.machineModel, this.powerModel, + this.powerMux ) { cause -> hostState = if (cause != null) HostState.ERROR else HostState.DOWN } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt index 07db3d26f..d8bb703e2 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/ComputeSteps.kt @@ -27,6 +27,7 @@ package org.opendc.compute.simulator.provisioner import org.opendc.compute.carbon.CarbonTrace import org.opendc.compute.simulator.scheduler.ComputeScheduler import org.opendc.compute.simulator.telemetry.ComputeMonitor +import org.opendc.compute.topology.specs.ClusterSpec import org.opendc.compute.topology.specs.HostSpec import java.time.Duration @@ -74,7 +75,7 @@ public fun registerComputeMonitor( */ public fun setupHosts( serviceDomain: String, - specs: List, + specs: List, ): ProvisioningStep { return HostsProvisioningStep(serviceDomain, specs) } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt index 19674d5e0..1d6e8a5fb 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt @@ -24,7 +24,10 @@ package org.opendc.compute.simulator.provisioner import org.opendc.compute.simulator.host.SimHost import org.opendc.compute.simulator.service.ComputeService +import org.opendc.compute.topology.specs.ClusterSpec import org.opendc.compute.topology.specs.HostSpec +import org.opendc.simulator.Multiplexer +import org.opendc.simulator.compute.power.SimPowerSource import org.opendc.simulator.engine.FlowEngine /** @@ -36,37 +39,57 @@ import org.opendc.simulator.engine.FlowEngine */ public class HostsProvisioningStep internal constructor( private val serviceDomain: String, - private val specs: List, + private val clusterSpecs: List, ) : ProvisioningStep { override fun apply(ctx: ProvisioningContext): AutoCloseable { val service = requireNotNull( ctx.registry.resolve(serviceDomain, ComputeService::class.java), ) { "Compute service $serviceDomain does not exist" } - val hosts = mutableSetOf() + val simHosts = mutableSetOf() + val simPowerSources = mutableListOf() - val flowEngine = FlowEngine.create(ctx.dispatcher) - val flowGraph = flowEngine.newGraph() + val engine = FlowEngine.create(ctx.dispatcher) + val graph = engine.newGraph() - for (spec in specs) { - val host = - SimHost( - spec.uid, - spec.name, - spec.meta, - ctx.dispatcher.timeSource, - flowGraph, - spec.model, - spec.cpuPowerModel, - ) + for (cluster in clusterSpecs){ - require(hosts.add(host)) { "Host with uid ${spec.uid} already exists" } - service.addHost(host) + // Create the Power Source to which hosts are connected + // TODO: Add connection to totalPower + val simPowerSource = SimPowerSource(graph) + service.addPowerSource(simPowerSource) + simPowerSources.add(simPowerSource) + + val powerMux = Multiplexer(graph) + graph.addEdge(powerMux, simPowerSource) + + // Create hosts, they are connected to the powerMux when SimMachine is created + for (hostSpec in cluster.hostSpecs) { + val simHost = + SimHost( + hostSpec.uid, + hostSpec.name, + hostSpec.meta, + ctx.dispatcher.timeSource, + graph, + hostSpec.model, + hostSpec.cpuPowerModel, + powerMux + ) + + require(simHosts.add(simHost)) { "Host with uid ${hostSpec.uid} already exists" } + service.addHost(simHost) + } } return AutoCloseable { - for (host in hosts) { - host.close() + for (simHost in simHosts) { + simHost.close() + } + + for (simPowerSource in simPowerSources){ + // TODO: add close function +// simPowerSource.close() } } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt index c84b2a3f3..60385279f 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt @@ -29,18 +29,16 @@ import kotlinx.coroutines.launch import mu.KotlinLogging import org.opendc.common.Dispatcher import org.opendc.common.asCoroutineDispatcher -import org.opendc.compute.api.TaskState import org.opendc.compute.carbon.CarbonTrace import org.opendc.compute.simulator.host.SimHost import org.opendc.compute.simulator.service.ComputeService import org.opendc.compute.simulator.service.ServiceTask -import org.opendc.compute.simulator.telemetry.table.HostInfo -import org.opendc.compute.simulator.telemetry.table.HostTableReader -import org.opendc.compute.simulator.telemetry.table.ServiceTableReader -import org.opendc.compute.simulator.telemetry.table.TaskInfo -import org.opendc.compute.simulator.telemetry.table.TaskTableReader +import org.opendc.compute.simulator.telemetry.table.HostTableReaderImpl +import org.opendc.compute.simulator.telemetry.table.PowerSourceTableReaderImpl +import org.opendc.compute.simulator.telemetry.table.ServiceTableReaderImpl +import org.opendc.compute.simulator.telemetry.table.TaskTableReaderImpl +import org.opendc.simulator.compute.power.SimPowerSource import java.time.Duration -import java.time.Instant /** * A helper class to collect metrics from a [ComputeService] instance and automatically export the metrics every @@ -75,15 +73,21 @@ public class ComputeMetricReader( private var loggCounter = 0 /** - * Mapping from [Host] instances to [HostTableReaderImpl] + * Mapping from [SimHost] instances to [HostTableReaderImpl] */ private val hostTableReaders = mutableMapOf() /** - * Mapping from [Task] instances to [TaskTableReaderImpl] + * Mapping from [ServiceTask] instances to [TaskTableReaderImpl] */ private val taskTableReaders = mutableMapOf() + /** + * Mapping from [SimPowerSource] instances to [PowerSourceTableReaderImpl] + */ + private val powerSourceTableReaders = mutableMapOf() + + /** * The background job that is responsible for collecting the metrics every cycle. */ @@ -143,6 +147,20 @@ public class ComputeMetricReader( } this.service.clearTasksToRemove() + for (simPowerSource in this.service.powerSources) { + val reader = this.powerSourceTableReaders.computeIfAbsent(simPowerSource) { + PowerSourceTableReaderImpl( + it, + startTime, + carbonTrace + ) + } + + reader.record(now) + this.monitor.record(reader.copy()) + reader.reset() + } + this.serviceTableReader.record(now) monitor.record(this.serviceTableReader.copy()) @@ -165,500 +183,4 @@ public class ComputeMetricReader( override fun close() { job.cancel() } - - /** - * An aggregator for service metrics before they are reported. - */ - private class ServiceTableReaderImpl( - private val service: ComputeService, - private val startTime: Duration = Duration.ofMillis(0), - ) : ServiceTableReader { - override fun copy(): ServiceTableReader { - val newServiceTable = - ServiceTableReaderImpl( - service, - ) - newServiceTable.setValues(this) - - return newServiceTable - } - - override fun setValues(table: ServiceTableReader) { - _timestamp = table.timestamp - _timestampAbsolute = table.timestampAbsolute - - _hostsUp = table.hostsUp - _hostsDown = table.hostsDown - _tasksTotal = table.tasksTotal - _tasksPending = table.tasksPending - _tasksActive = table.tasksActive - _tasksCompleted = table.tasksCompleted - _tasksTerminated = table.tasksTerminated - _attemptsSuccess = table.attemptsSuccess - _attemptsFailure = table.attemptsFailure - } - - private var _timestamp: Instant = Instant.MIN - override val timestamp: Instant - get() = _timestamp - - private var _timestampAbsolute: Instant = Instant.MIN - override val timestampAbsolute: Instant - get() = _timestampAbsolute - - override val hostsUp: Int - get() = _hostsUp - private var _hostsUp = 0 - - override val hostsDown: Int - get() = _hostsDown - private var _hostsDown = 0 - - override val tasksTotal: Int - get() = _tasksTotal - private var _tasksTotal = 0 - - override val tasksPending: Int - get() = _tasksPending - private var _tasksPending = 0 - - override val tasksCompleted: Int - get() = _tasksCompleted - private var _tasksCompleted = 0 - - override val tasksActive: Int - get() = _tasksActive - private var _tasksActive = 0 - - override val tasksTerminated: Int - get() = _tasksTerminated - private var _tasksTerminated = 0 - - override val attemptsSuccess: Int - get() = _attemptsSuccess - private var _attemptsSuccess = 0 - - override val attemptsFailure: Int - get() = _attemptsFailure - private var _attemptsFailure = 0 - - /** - * Record the next cycle. - */ - fun record(now: Instant) { - _timestamp = now - _timestampAbsolute = now + startTime - - val stats = service.getSchedulerStats() - _hostsUp = stats.hostsAvailable - _hostsDown = stats.hostsUnavailable - _tasksTotal = stats.tasksTotal - _tasksPending = stats.tasksPending - _tasksCompleted = stats.tasksCompleted - _tasksActive = stats.tasksActive - _tasksTerminated = stats.tasksTerminated - _attemptsSuccess = stats.attemptsSuccess.toInt() - _attemptsFailure = stats.attemptsFailure.toInt() - } - } - - /** - * An aggregator for host metrics before they are reported. - */ - private class HostTableReaderImpl( - host: SimHost, - private val startTime: Duration = Duration.ofMillis(0), - private val carbonTrace: CarbonTrace = CarbonTrace(null), - ) : HostTableReader { - override fun copy(): HostTableReader { - val newHostTable = - HostTableReaderImpl(_host) - newHostTable.setValues(this) - - return newHostTable - } - - override fun setValues(table: HostTableReader) { - _timestamp = table.timestamp - _timestampAbsolute = table.timestampAbsolute - - _guestsTerminated = table.guestsTerminated - _guestsRunning = table.guestsRunning - _guestsError = table.guestsError - _guestsInvalid = table.guestsInvalid - _cpuLimit = table.cpuLimit - _cpuDemand = table.cpuDemand - _cpuUsage = table.cpuUsage - _cpuUtilization = table.cpuUtilization - _cpuActiveTime = table.cpuActiveTime - _cpuIdleTime = table.cpuIdleTime - _cpuStealTime = table.cpuStealTime - _cpuLostTime = table.cpuLostTime - _powerDraw = table.powerDraw - _energyUsage = table.energyUsage - _carbonIntensity = table.carbonIntensity - _carbonEmission = table.carbonEmission - _uptime = table.uptime - _downtime = table.downtime - _bootTime = table.bootTime - _bootTimeAbsolute = table.bootTimeAbsolute - } - - private val _host = host - - override val host: HostInfo = - HostInfo( - host.getUid().toString(), - host.getName(), - "x86", - host.getModel().coreCount, - host.getModel().cpuCapacity, - host.getModel().memoryCapacity, - ) - - override val timestamp: Instant - get() = _timestamp - private var _timestamp = Instant.MIN - - override val timestampAbsolute: Instant - get() = _timestampAbsolute - private var _timestampAbsolute = Instant.MIN - - override val guestsTerminated: Int - get() = _guestsTerminated - private var _guestsTerminated = 0 - - override val guestsRunning: Int - get() = _guestsRunning - private var _guestsRunning = 0 - - override val guestsError: Int - get() = _guestsError - private var _guestsError = 0 - - override val guestsInvalid: Int - get() = _guestsInvalid - private var _guestsInvalid = 0 - - override val cpuLimit: Double - get() = _cpuLimit - private var _cpuLimit = 0.0 - - override val cpuUsage: Double - get() = _cpuUsage - private var _cpuUsage = 0.0 - - override val cpuDemand: Double - get() = _cpuDemand - private var _cpuDemand = 0.0 - - override val cpuUtilization: Double - get() = _cpuUtilization - private var _cpuUtilization = 0.0 - - override val cpuActiveTime: Long - get() = _cpuActiveTime - previousCpuActiveTime - private var _cpuActiveTime = 0L - private var previousCpuActiveTime = 0L - - override val cpuIdleTime: Long - get() = _cpuIdleTime - previousCpuIdleTime - private var _cpuIdleTime = 0L - private var previousCpuIdleTime = 0L - - override val cpuStealTime: Long - get() = _cpuStealTime - previousCpuStealTime - private var _cpuStealTime = 0L - private var previousCpuStealTime = 0L - - override val cpuLostTime: Long - get() = _cpuLostTime - previousCpuLostTime - private var _cpuLostTime = 0L - private var previousCpuLostTime = 0L - - override val powerDraw: Double - get() = _powerDraw - private var _powerDraw = 0.0 - - override val energyUsage: Double - get() = _energyUsage - previousEnergyUsage - private var _energyUsage = 0.0 - private var previousEnergyUsage = 0.0 - - override val carbonIntensity: Double - get() = _carbonIntensity - private var _carbonIntensity = 0.0 - - override val carbonEmission: Double - get() = _carbonEmission - private var _carbonEmission = 0.0 - - override val uptime: Long - get() = _uptime - previousUptime - private var _uptime = 0L - private var previousUptime = 0L - - override val downtime: Long - get() = _downtime - previousDowntime - private var _downtime = 0L - private var previousDowntime = 0L - - override val bootTime: Instant? - get() = _bootTime - private var _bootTime: Instant? = null - - override val bootTimeAbsolute: Instant? - get() = _bootTimeAbsolute - private var _bootTimeAbsolute: Instant? = null - - /** - * Record the next cycle. - */ - fun record(now: Instant) { - val hostCpuStats = _host.getCpuStats() - val hostSysStats = _host.getSystemStats() - - _timestamp = now - _timestampAbsolute = now + startTime - - _guestsTerminated = hostSysStats.guestsTerminated - _guestsRunning = hostSysStats.guestsRunning - _guestsError = hostSysStats.guestsError - _guestsInvalid = hostSysStats.guestsInvalid - _cpuLimit = hostCpuStats.capacity - _cpuDemand = hostCpuStats.demand - _cpuUsage = hostCpuStats.usage - _cpuUtilization = hostCpuStats.utilization - _cpuActiveTime = hostCpuStats.activeTime - _cpuIdleTime = hostCpuStats.idleTime - _cpuStealTime = hostCpuStats.stealTime - _cpuLostTime = hostCpuStats.lostTime - _powerDraw = hostSysStats.powerDraw - _energyUsage = hostSysStats.energyUsage - _carbonIntensity = carbonTrace.getCarbonIntensity(timestampAbsolute) - - _carbonEmission = carbonIntensity * (energyUsage / 3600000.0) // convert energy usage from J to kWh - _uptime = hostSysStats.uptime.toMillis() - _downtime = hostSysStats.downtime.toMillis() - _bootTime = hostSysStats.bootTime - _bootTime = hostSysStats.bootTime + startTime - } - - /** - * Finish the aggregation for this cycle. - */ - fun reset() { - // Reset intermediate state for next aggregation - previousCpuActiveTime = _cpuActiveTime - previousCpuIdleTime = _cpuIdleTime - previousCpuStealTime = _cpuStealTime - previousCpuLostTime = _cpuLostTime - previousEnergyUsage = _energyUsage - previousUptime = _uptime - previousDowntime = _downtime - - _guestsTerminated = 0 - _guestsRunning = 0 - _guestsError = 0 - _guestsInvalid = 0 - - _cpuLimit = 0.0 - _cpuUsage = 0.0 - _cpuDemand = 0.0 - _cpuUtilization = 0.0 - - _powerDraw = 0.0 - _energyUsage = 0.0 - _carbonIntensity = 0.0 - _carbonEmission = 0.0 - } - } - - /** - * An aggregator for task metrics before they are reported. - */ - private class TaskTableReaderImpl( - private val service: ComputeService, - private val task: ServiceTask, - private val startTime: Duration = Duration.ofMillis(0), - ) : TaskTableReader { - override fun copy(): TaskTableReader { - val newTaskTable = - TaskTableReaderImpl( - service, - task, - ) - newTaskTable.setValues(this) - - return newTaskTable - } - - override fun setValues(table: TaskTableReader) { - host = table.host - - _timestamp = table.timestamp - _timestampAbsolute = table.timestampAbsolute - - _cpuLimit = table.cpuLimit - _cpuActiveTime = table.cpuActiveTime - _cpuIdleTime = table.cpuIdleTime - _cpuStealTime = table.cpuStealTime - _cpuLostTime = table.cpuLostTime - _uptime = table.uptime - _downtime = table.downtime - _provisionTime = table.provisionTime - _bootTime = table.bootTime - _bootTimeAbsolute = table.bootTimeAbsolute - - _creationTime = table.creationTime - _finishTime = table.finishTime - - _taskState = table.taskState - } - - /** - * The static information about this task. - */ - override val taskInfo = - TaskInfo( - task.uid.toString(), - task.name, - "vm", - "x86", - task.flavor.coreCount, - task.flavor.memorySize, - ) - - /** - * The [HostInfo] of the host on which the task is hosted. - */ - override var host: HostInfo? = null - private var _host: SimHost? = null - - private var _timestamp = Instant.MIN - override val timestamp: Instant - get() = _timestamp - - private var _timestampAbsolute = Instant.MIN - override val timestampAbsolute: Instant - get() = _timestampAbsolute - - override val uptime: Long - get() = _uptime - previousUptime - private var _uptime: Long = 0 - private var previousUptime = 0L - - override val downtime: Long - get() = _downtime - previousDowntime - private var _downtime: Long = 0 - private var previousDowntime = 0L - - override val provisionTime: Instant? - get() = _provisionTime - private var _provisionTime: Instant? = null - - override val bootTime: Instant? - get() = _bootTime - private var _bootTime: Instant? = null - - override val creationTime: Instant? - get() = _creationTime - private var _creationTime: Instant? = null - - override val finishTime: Instant? - get() = _finishTime - private var _finishTime: Instant? = null - - override val cpuLimit: Double - get() = _cpuLimit - private var _cpuLimit = 0.0 - - override val cpuActiveTime: Long - get() = _cpuActiveTime - previousCpuActiveTime - private var _cpuActiveTime = 0L - private var previousCpuActiveTime = 0L - - override val cpuIdleTime: Long - get() = _cpuIdleTime - previousCpuIdleTime - private var _cpuIdleTime = 0L - private var previousCpuIdleTime = 0L - - override val cpuStealTime: Long - get() = _cpuStealTime - previousCpuStealTime - private var _cpuStealTime = 0L - private var previousCpuStealTime = 0L - - override val cpuLostTime: Long - get() = _cpuLostTime - previousCpuLostTime - private var _cpuLostTime = 0L - private var previousCpuLostTime = 0L - - override val bootTimeAbsolute: Instant? - get() = _bootTimeAbsolute - private var _bootTimeAbsolute: Instant? = null - - override val taskState: TaskState? - get() = _taskState - private var _taskState: TaskState? = null - - /** - * Record the next cycle. - */ - fun record(now: Instant) { - val newHost = service.lookupHost(task) - if (newHost != null && newHost.getUid() != _host?.getUid()) { - _host = newHost - host = - HostInfo( - newHost.getUid().toString(), - newHost.getName(), - "x86", - newHost.getModel().coreCount, - newHost.getModel().cpuCapacity, - newHost.getModel().memoryCapacity, - ) - } - - val cpuStats = _host?.getCpuStats(task) - val sysStats = _host?.getSystemStats(task) - - _timestamp = now - _timestampAbsolute = now + startTime - - _cpuLimit = cpuStats?.capacity ?: 0.0 - _cpuActiveTime = cpuStats?.activeTime ?: 0 - _cpuIdleTime = cpuStats?.idleTime ?: 0 - _cpuStealTime = cpuStats?.stealTime ?: 0 - _cpuLostTime = cpuStats?.lostTime ?: 0 - _uptime = sysStats?.uptime?.toMillis() ?: 0 - _downtime = sysStats?.downtime?.toMillis() ?: 0 - _provisionTime = task.launchedAt - _bootTime = sysStats?.bootTime - _creationTime = task.createdAt - _finishTime = task.finishedAt - - _taskState = task.state - - if (sysStats != null) { - _bootTimeAbsolute = sysStats.bootTime + startTime - } else { - _bootTimeAbsolute = null - } - } - - /** - * Finish the aggregation for this cycle. - */ - fun reset() { - previousUptime = _uptime - previousDowntime = _downtime - previousCpuActiveTime = _cpuActiveTime - previousCpuIdleTime = _cpuIdleTime - previousCpuStealTime = _cpuStealTime - previousCpuLostTime = _cpuLostTime - - _host = null - _cpuLimit = 0.0 - } - } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMonitor.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMonitor.kt index 534bcc09d..5e1fe2c95 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMonitor.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMonitor.kt @@ -23,6 +23,7 @@ package org.opendc.compute.simulator.telemetry import org.opendc.compute.simulator.telemetry.table.HostTableReader +import org.opendc.compute.simulator.telemetry.table.PowerSourceTableReader import org.opendc.compute.simulator.telemetry.table.ServiceTableReader import org.opendc.compute.simulator.telemetry.table.TaskTableReader @@ -40,6 +41,11 @@ public interface ComputeMonitor { */ public fun record(reader: HostTableReader) {} + /** + * Record an entry with the specified [reader]. + */ + public fun record(reader: PowerSourceTableReader) {} + /** * Record an entry with the specified [reader]. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ComputeExportConfig.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ComputeExportConfig.kt index 3f220ad13..691d01c13 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ComputeExportConfig.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ComputeExportConfig.kt @@ -36,6 +36,7 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonObject import org.opendc.common.logger.logger import org.opendc.compute.simulator.telemetry.table.HostTableReader +import org.opendc.compute.simulator.telemetry.table.PowerSourceTableReader import org.opendc.compute.simulator.telemetry.table.ServiceTableReader import org.opendc.compute.simulator.telemetry.table.TaskTableReader import org.opendc.trace.util.parquet.exporter.ColListSerializer @@ -49,21 +50,25 @@ import org.opendc.trace.util.parquet.exporter.columnSerializer * * @param[hostExportColumns] the columns that will be included in the `host.parquet` raw output file. * @param[taskExportColumns] the columns that will be included in the `task.parquet` raw output file. + * @param[powerSourceExportColumns] the columns that will be included in the `power.parquet` raw output file. * @param[serviceExportColumns] the columns that will be included in the `service.parquet` raw output file. */ @Serializable(with = ComputeExportConfig.Companion.ComputeExportConfigSerializer::class) public data class ComputeExportConfig( public val hostExportColumns: Set>, public val taskExportColumns: Set>, + public val powerSourceExportColumns: Set>, public val serviceExportColumns: Set>, ) { public constructor( hostExportColumns: Collection>, taskExportColumns: Collection>, + powerSourceExportColumns: Collection>, serviceExportColumns: Collection>, ) : this( hostExportColumns.toSet() + DfltHostExportColumns.BASE_EXPORT_COLUMNS, taskExportColumns.toSet() + DfltTaskExportColumns.BASE_EXPORT_COLUMNS, + powerSourceExportColumns.toSet() + DfltPowerSourceExportColumns.BASE_EXPORT_COLUMNS, serviceExportColumns.toSet() + DfltServiceExportColumns.BASE_EXPORT_COLUMNS, ) @@ -75,6 +80,7 @@ public data class ComputeExportConfig( | === Compute Export Config === | Host columns : ${hostExportColumns.map { it.name }.toString().trim('[', ']')} | Task columns : ${taskExportColumns.map { it.name }.toString().trim('[', ']')} + | Power Source columns : ${powerSourceExportColumns.map { it.name }.toString().trim('[', ']')} | Service columns : ${serviceExportColumns.map { it.name }.toString().trim('[', ']')} """.trimIndent() @@ -88,19 +94,21 @@ public data class ComputeExportConfig( public fun loadDfltColumns() { DfltHostExportColumns DfltTaskExportColumns + DfltPowerSourceExportColumns DfltServiceExportColumns } /** - * Config that includes all columns defined in [DfltHostExportColumns], - * [DfltTaskExportColumns], [DfltServiceExportColumns] among all other loaded + * Config that includes all columns defined in [DfltHostExportColumns], [DfltTaskExportColumns], + * [DfltPowerSourceExportColumns], [DfltServiceExportColumns] among all other loaded * columns for [HostTableReader], [TaskTableReader] and [ServiceTableReader]. */ public val ALL_COLUMNS: ComputeExportConfig by lazy { - ComputeExportConfig.Companion.loadDfltColumns() + loadDfltColumns() ComputeExportConfig( hostExportColumns = ExportColumn.getAllLoadedColumns(), taskExportColumns = ExportColumn.getAllLoadedColumns(), + powerSourceExportColumns = ExportColumn.getAllLoadedColumns(), serviceExportColumns = ExportColumn.getAllLoadedColumns(), ) } @@ -121,6 +129,10 @@ public data class ComputeExportConfig( "taskExportColumns", ListSerializer(columnSerializer()).descriptor, ) + element( + "powerSourceExportColumns", + ListSerializer(columnSerializer()).descriptor, + ) element( "serviceExportColumns", ListSerializer(columnSerializer()).descriptor, @@ -135,16 +147,18 @@ public data class ComputeExportConfig( } // Loads the default columns so that they are available for deserialization. - ComputeExportConfig.Companion.loadDfltColumns() + loadDfltColumns() val elem = jsonDec.decodeJsonElement().jsonObject val hostFields: List> = elem["hostExportColumns"].toFieldList() val taskFields: List> = elem["taskExportColumns"].toFieldList() + val powerSourceFields: List> = elem["powerSourceExportColumns"].toFieldList() val serviceFields: List> = elem["serviceExportColumns"].toFieldList() return ComputeExportConfig( hostExportColumns = hostFields, taskExportColumns = taskFields, + powerSourceExportColumns = powerSourceFields, serviceExportColumns = serviceFields, ) } @@ -153,22 +167,28 @@ public data class ComputeExportConfig( encoder: Encoder, value: ComputeExportConfig, ) { - encoder.encodeStructure(ComputeExportConfig.Companion.ComputeExportConfigSerializer.descriptor) { + encoder.encodeStructure(descriptor) { encodeSerializableElement( - ComputeExportConfig.Companion.ComputeExportConfigSerializer.descriptor, + descriptor, 0, ColListSerializer(columnSerializer()), value.hostExportColumns.toList(), ) encodeSerializableElement( - ComputeExportConfig.Companion.ComputeExportConfigSerializer.descriptor, + descriptor, 1, ColListSerializer(columnSerializer()), value.taskExportColumns.toList(), ) encodeSerializableElement( - ComputeExportConfig.Companion.ComputeExportConfigSerializer.descriptor, + descriptor, 2, + ColListSerializer(columnSerializer()), + value.powerSourceExportColumns.toList(), + ) + encodeSerializableElement( + descriptor, + 3, ColListSerializer(columnSerializer()), value.serviceExportColumns.toList(), ) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltPowerSourceExportColumns.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltPowerSourceExportColumns.kt new file mode 100644 index 000000000..95db55fe8 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/DfltPowerSourceExportColumns.kt @@ -0,0 +1,91 @@ +/* + * 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.telemetry.parquet + +import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.FLOAT +import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT32 +import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName.INT64 +import org.apache.parquet.schema.Types +import org.opendc.compute.simulator.telemetry.table.PowerSourceTableReader +import org.opendc.trace.util.parquet.exporter.ExportColumn + +/** + * This object wraps the [ExportColumn]s to solves ambiguity for field + * names that are included in more than 1 exportable. + * + * Additionally, it allows to load all the fields at once by just its symbol, + * so that these columns can be deserialized. Additional fields can be added + * from anywhere, and they are deserializable as long as they are loaded by the jvm. + * + * ```kotlin + * ... + * // Loads the column + * DfltHostExportColumns + * ... + * ``` + */ +public object DfltPowerSourceExportColumns { + public val TIMESTAMP: ExportColumn = + ExportColumn( + field = Types.required(INT64).named("timestamp"), + ) { it.timestamp.toEpochMilli() } + + public val TIMESTAMP_ABS: ExportColumn = + ExportColumn( + field = Types.required(INT64).named("timestamp_absolute"), + ) { it.timestampAbsolute.toEpochMilli() } + + public val CPU_COUNT: ExportColumn = + ExportColumn( + field = Types.required(INT32).named("hosts_connected"), + ) { it.hostsConnected } + + public val POWER_DRAW: ExportColumn = + ExportColumn( + field = Types.required(FLOAT).named("power_draw"), + ) { it.powerDraw } + + public val ENERGY_USAGE: ExportColumn = + ExportColumn( + field = Types.required(FLOAT).named("energy_usage"), + ) { it.energyUsage } + + public val CARBON_INTENSITY: ExportColumn = + ExportColumn( + field = Types.required(FLOAT).named("carbon_intensity"), + ) { it.carbonIntensity } + + public val CARBON_EMISSION: ExportColumn = + ExportColumn( + field = Types.required(FLOAT).named("carbon_emission"), + ) { it.carbonEmission } + + /** + * The columns that are always included in the output file. + */ + internal val BASE_EXPORT_COLUMNS = + setOf( + TIMESTAMP_ABS, + TIMESTAMP, + ) +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt index 4cd920c43..f8f5551c4 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt @@ -24,6 +24,7 @@ package org.opendc.compute.simulator.telemetry.parquet import org.opendc.compute.simulator.telemetry.ComputeMonitor import org.opendc.compute.simulator.telemetry.table.HostTableReader +import org.opendc.compute.simulator.telemetry.table.PowerSourceTableReader import org.opendc.compute.simulator.telemetry.table.ServiceTableReader import org.opendc.compute.simulator.telemetry.table.TaskTableReader import org.opendc.trace.util.parquet.exporter.ExportColumn @@ -37,6 +38,7 @@ import java.io.File public class ParquetComputeMonitor( private val hostExporter: Exporter, private val taskExporter: Exporter, + private val powerSourceExporter: Exporter, private val serviceExporter: Exporter, ) : ComputeMonitor, AutoCloseable { override fun record(reader: HostTableReader) { @@ -47,6 +49,10 @@ public class ParquetComputeMonitor( taskExporter.write(reader) } + override fun record(reader: PowerSourceTableReader) { + powerSourceExporter.write(reader) + } + override fun record(reader: ServiceTableReader) { serviceExporter.write(reader) } @@ -54,6 +60,7 @@ public class ParquetComputeMonitor( override fun close() { hostExporter.close() taskExporter.close() + powerSourceExporter.close() serviceExporter.close() } @@ -77,12 +84,13 @@ public class ParquetComputeMonitor( bufferSize = bufferSize, hostExportColumns = computeExportConfig.hostExportColumns, taskExportColumns = computeExportConfig.taskExportColumns, + powerSourceExportColumns = computeExportConfig.powerSourceExportColumns, serviceExportColumns = computeExportConfig.serviceExportColumns, ) /** * Constructor that loads default [ExportColumn]s defined in - * [DfltHostExportColumns], [DfltTaskExportColumns], [DfltServiceExportColumns] + * [DfltHostExportColumns], [DfltTaskExportColumns], [DfltPowerSourceExportColumns], [DfltServiceExportColumns] * in case optional parameters are omitted and all fields need to be retrieved. * * @param[base] parent pathname for output file. @@ -95,6 +103,7 @@ public class ParquetComputeMonitor( bufferSize: Int, hostExportColumns: Collection>? = null, taskExportColumns: Collection>? = null, + powerSourceExportColumns: Collection>? = null, serviceExportColumns: Collection>? = null, ): ParquetComputeMonitor { // Loads the fields in case they need to be retrieved if optional params are omitted. @@ -113,6 +122,12 @@ public class ParquetComputeMonitor( columns = taskExportColumns ?: Exportable.getAllLoadedColumns(), bufferSize = bufferSize, ), + powerSourceExporter = + Exporter( + outputFile = File(base, "$partition/powerSource.parquet").also { it.parentFile.mkdirs() }, + columns = powerSourceExportColumns ?: Exportable.getAllLoadedColumns(), + bufferSize = bufferSize, + ), serviceExporter = Exporter( outputFile = File(base, "$partition/service.parquet").also { it.parentFile.mkdirs() }, diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReader.kt index a5a862cea..cf8d3c8c9 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReader.kt @@ -33,6 +33,10 @@ public interface HostTableReader : Exportable { public fun setValues(table: HostTableReader) + public fun record(now: Instant) + + public fun reset() + /** * The [HostInfo] of the host to which the row belongs to. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt new file mode 100644 index 000000000..8408f2b99 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt @@ -0,0 +1,218 @@ +package org.opendc.compute.simulator.telemetry.table + +import org.opendc.compute.carbon.CarbonTrace +import org.opendc.compute.simulator.host.SimHost +import java.time.Duration +import java.time.Instant + +/** + * An aggregator for host metrics before they are reported. + */ +public class HostTableReaderImpl( + host: SimHost, + private val startTime: Duration = Duration.ofMillis(0), + private val carbonTrace: CarbonTrace = CarbonTrace(null), +) : HostTableReader { + override fun copy(): HostTableReader { + val newHostTable = + HostTableReaderImpl(_host) + newHostTable.setValues(this) + + return newHostTable + } + + override fun setValues(table: HostTableReader) { + _timestamp = table.timestamp + _timestampAbsolute = table.timestampAbsolute + + _guestsTerminated = table.guestsTerminated + _guestsRunning = table.guestsRunning + _guestsError = table.guestsError + _guestsInvalid = table.guestsInvalid + _cpuLimit = table.cpuLimit + _cpuDemand = table.cpuDemand + _cpuUsage = table.cpuUsage + _cpuUtilization = table.cpuUtilization + _cpuActiveTime = table.cpuActiveTime + _cpuIdleTime = table.cpuIdleTime + _cpuStealTime = table.cpuStealTime + _cpuLostTime = table.cpuLostTime + _powerDraw = table.powerDraw + _energyUsage = table.energyUsage + _carbonIntensity = table.carbonIntensity + _carbonEmission = table.carbonEmission + _uptime = table.uptime + _downtime = table.downtime + _bootTime = table.bootTime + _bootTimeAbsolute = table.bootTimeAbsolute + } + + private val _host = host + + override val host: HostInfo = + HostInfo( + host.getUid().toString(), + host.getName(), + "x86", + host.getModel().coreCount, + host.getModel().cpuCapacity, + host.getModel().memoryCapacity, + ) + + override val timestamp: Instant + get() = _timestamp + private var _timestamp = Instant.MIN + + override val timestampAbsolute: Instant + get() = _timestampAbsolute + private var _timestampAbsolute = Instant.MIN + + override val guestsTerminated: Int + get() = _guestsTerminated + private var _guestsTerminated = 0 + + override val guestsRunning: Int + get() = _guestsRunning + private var _guestsRunning = 0 + + override val guestsError: Int + get() = _guestsError + private var _guestsError = 0 + + override val guestsInvalid: Int + get() = _guestsInvalid + private var _guestsInvalid = 0 + + override val cpuLimit: Double + get() = _cpuLimit + private var _cpuLimit = 0.0 + + override val cpuUsage: Double + get() = _cpuUsage + private var _cpuUsage = 0.0 + + override val cpuDemand: Double + get() = _cpuDemand + private var _cpuDemand = 0.0 + + override val cpuUtilization: Double + get() = _cpuUtilization + private var _cpuUtilization = 0.0 + + override val cpuActiveTime: Long + get() = _cpuActiveTime - previousCpuActiveTime + private var _cpuActiveTime = 0L + private var previousCpuActiveTime = 0L + + override val cpuIdleTime: Long + get() = _cpuIdleTime - previousCpuIdleTime + private var _cpuIdleTime = 0L + private var previousCpuIdleTime = 0L + + override val cpuStealTime: Long + get() = _cpuStealTime - previousCpuStealTime + private var _cpuStealTime = 0L + private var previousCpuStealTime = 0L + + override val cpuLostTime: Long + get() = _cpuLostTime - previousCpuLostTime + private var _cpuLostTime = 0L + private var previousCpuLostTime = 0L + + override val powerDraw: Double + get() = _powerDraw + private var _powerDraw = 0.0 + + override val energyUsage: Double + get() = _energyUsage - previousEnergyUsage + private var _energyUsage = 0.0 + private var previousEnergyUsage = 0.0 + + override val carbonIntensity: Double + get() = _carbonIntensity + private var _carbonIntensity = 0.0 + + override val carbonEmission: Double + get() = _carbonEmission + private var _carbonEmission = 0.0 + + override val uptime: Long + get() = _uptime - previousUptime + private var _uptime = 0L + private var previousUptime = 0L + + override val downtime: Long + get() = _downtime - previousDowntime + private var _downtime = 0L + private var previousDowntime = 0L + + override val bootTime: Instant? + get() = _bootTime + private var _bootTime: Instant? = null + + override val bootTimeAbsolute: Instant? + get() = _bootTimeAbsolute + private var _bootTimeAbsolute: Instant? = null + + /** + * Record the next cycle. + */ + override fun record(now: Instant) { + val hostCpuStats = _host.getCpuStats() + val hostSysStats = _host.getSystemStats() + + _timestamp = now + _timestampAbsolute = now + startTime + + _guestsTerminated = hostSysStats.guestsTerminated + _guestsRunning = hostSysStats.guestsRunning + _guestsError = hostSysStats.guestsError + _guestsInvalid = hostSysStats.guestsInvalid + _cpuLimit = hostCpuStats.capacity + _cpuDemand = hostCpuStats.demand + _cpuUsage = hostCpuStats.usage + _cpuUtilization = hostCpuStats.utilization + _cpuActiveTime = hostCpuStats.activeTime + _cpuIdleTime = hostCpuStats.idleTime + _cpuStealTime = hostCpuStats.stealTime + _cpuLostTime = hostCpuStats.lostTime + _powerDraw = hostSysStats.powerDraw + _energyUsage = hostSysStats.energyUsage + _carbonIntensity = carbonTrace.getCarbonIntensity(timestampAbsolute) + + _carbonEmission = carbonIntensity * (energyUsage / 3600000.0) // convert energy usage from J to kWh + _uptime = hostSysStats.uptime.toMillis() + _downtime = hostSysStats.downtime.toMillis() + _bootTime = hostSysStats.bootTime + _bootTime = hostSysStats.bootTime + startTime + } + + /** + * Finish the aggregation for this cycle. + */ + override fun reset() { + // Reset intermediate state for next aggregation + previousCpuActiveTime = _cpuActiveTime + previousCpuIdleTime = _cpuIdleTime + previousCpuStealTime = _cpuStealTime + previousCpuLostTime = _cpuLostTime + previousEnergyUsage = _energyUsage + previousUptime = _uptime + previousDowntime = _downtime + + _guestsTerminated = 0 + _guestsRunning = 0 + _guestsError = 0 + _guestsInvalid = 0 + + _cpuLimit = 0.0 + _cpuUsage = 0.0 + _cpuDemand = 0.0 + _cpuUtilization = 0.0 + + _powerDraw = 0.0 + _energyUsage = 0.0 + _carbonIntensity = 0.0 + _carbonEmission = 0.0 + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt new file mode 100644 index 000000000..eb76d2de4 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 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.table + +import org.opendc.trace.util.parquet.exporter.Exportable +import java.time.Instant + +/** + * An interface that is used to read a row of a host trace entry. + */ +public interface PowerSourceTableReader : Exportable { + public fun copy(): PowerSourceTableReader + + public fun setValues(table: PowerSourceTableReader) + + public fun record(now: Instant) + + public fun reset() + /** + * The timestamp of the current entry of the reader relative to the start of the workload. + */ + public val timestamp: Instant + + /** + * The timestamp of the current entry of the reader. + */ + public val timestampAbsolute: Instant + + /** + * The number of connected hosts + */ + public val hostsConnected: Int + + /** + * The current power draw of the host in W. + */ + public val powerDraw: Double + + /** + * The total energy consumption of the host since last sample in J. + */ + public val energyUsage: Double + + /** + * The current carbon intensity of the host in gCO2 / kW. + */ + public val carbonIntensity: Double + + /** + * The current carbon emission since the last deadline in g. + */ + public val carbonEmission: Double +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt new file mode 100644 index 000000000..98374fe23 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt @@ -0,0 +1,96 @@ +package org.opendc.compute.simulator.telemetry.table + +import org.opendc.compute.carbon.CarbonTrace +import org.opendc.simulator.compute.power.SimPowerSource +import java.time.Duration +import java.time.Instant + +/** + * An aggregator for task metrics before they are reported. + */ +public class PowerSourceTableReaderImpl( + powerSource: SimPowerSource, + private val startTime: Duration = Duration.ofMillis(0), + private val carbonTrace: CarbonTrace = CarbonTrace(null), +) : PowerSourceTableReader { + override fun copy(): PowerSourceTableReader { + val newPowerSourceTable = + PowerSourceTableReaderImpl( + powerSource + ) + newPowerSourceTable.setValues(this) + + return newPowerSourceTable + } + + override fun setValues(table: PowerSourceTableReader) { + _timestamp = table.timestamp + _timestampAbsolute = table.timestampAbsolute + + _hostsConnected = table.hostsConnected + _powerDraw = table.powerDraw + _energyUsage = table.energyUsage + _carbonIntensity = table.carbonIntensity + _carbonEmission = table.carbonEmission + } + + private val powerSource = powerSource + + private var _timestamp = Instant.MIN + override val timestamp: Instant + get() = _timestamp + + private var _timestampAbsolute = Instant.MIN + override val timestampAbsolute: Instant + get() = _timestampAbsolute + + override val hostsConnected: Int + get() = _hostsConnected + private var _hostsConnected: Int = 0 + + override val powerDraw: Double + get() = _powerDraw + private var _powerDraw = 0.0 + + override val energyUsage: Double + get() = _energyUsage - previousEnergyUsage + private var _energyUsage = 0.0 + private var previousEnergyUsage = 0.0 + + override val carbonIntensity: Double + get() = _carbonIntensity + private var _carbonIntensity = 0.0 + + override val carbonEmission: Double + get() = _carbonEmission + private var _carbonEmission = 0.0 + + /** + * Record the next cycle. + */ + override fun record(now: Instant) { + + _timestamp = now + _timestampAbsolute = now + startTime + + _hostsConnected = 0 + _powerDraw = powerSource.powerDraw + _energyUsage = powerSource.energyUsage + _carbonIntensity = carbonTrace.getCarbonIntensity(timestampAbsolute) + _carbonEmission = carbonIntensity * (energyUsage / 3600000.0) + } + + /** + * Finish the aggregation for this cycle. + */ + override fun reset() { + + previousEnergyUsage = _energyUsage + + _hostsConnected = 0 + _powerDraw = 0.0 + _energyUsage = 0.0 + _carbonIntensity = 0.0 + _carbonEmission = 0.0 + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReader.kt index 690dfe0ab..c8cc765ad 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReader.kt @@ -33,6 +33,8 @@ public interface ServiceTableReader : Exportable { public fun setValues(table: ServiceTableReader) + public fun record(now: Instant) + /** * The timestamp of the current entry of the reader. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt new file mode 100644 index 000000000..909f76777 --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt @@ -0,0 +1,101 @@ +package org.opendc.compute.simulator.telemetry.table + +import org.opendc.compute.simulator.service.ComputeService +import java.time.Duration +import java.time.Instant + +/** + * An aggregator for service metrics before they are reported. + */ +public class ServiceTableReaderImpl( + private val service: ComputeService, + private val startTime: Duration = Duration.ofMillis(0), +) : ServiceTableReader { + override fun copy(): ServiceTableReader { + val newServiceTable = + ServiceTableReaderImpl( + service, + ) + newServiceTable.setValues(this) + + return newServiceTable + } + + override fun setValues(table: ServiceTableReader) { + _timestamp = table.timestamp + _timestampAbsolute = table.timestampAbsolute + + _hostsUp = table.hostsUp + _hostsDown = table.hostsDown + _tasksTotal = table.tasksTotal + _tasksPending = table.tasksPending + _tasksActive = table.tasksActive + _tasksCompleted = table.tasksCompleted + _tasksTerminated = table.tasksTerminated + _attemptsSuccess = table.attemptsSuccess + _attemptsFailure = table.attemptsFailure + } + + private var _timestamp: Instant = Instant.MIN + override val timestamp: Instant + get() = _timestamp + + private var _timestampAbsolute: Instant = Instant.MIN + override val timestampAbsolute: Instant + get() = _timestampAbsolute + + override val hostsUp: Int + get() = _hostsUp + private var _hostsUp = 0 + + override val hostsDown: Int + get() = _hostsDown + private var _hostsDown = 0 + + override val tasksTotal: Int + get() = _tasksTotal + private var _tasksTotal = 0 + + override val tasksPending: Int + get() = _tasksPending + private var _tasksPending = 0 + + override val tasksCompleted: Int + get() = _tasksCompleted + private var _tasksCompleted = 0 + + override val tasksActive: Int + get() = _tasksActive + private var _tasksActive = 0 + + override val tasksTerminated: Int + get() = _tasksTerminated + private var _tasksTerminated = 0 + + override val attemptsSuccess: Int + get() = _attemptsSuccess + private var _attemptsSuccess = 0 + + override val attemptsFailure: Int + get() = _attemptsFailure + private var _attemptsFailure = 0 + + /** + * Record the next cycle. + */ + override fun record(now: Instant) { + _timestamp = now + _timestampAbsolute = now + startTime + + val stats = service.getSchedulerStats() + _hostsUp = stats.hostsAvailable + _hostsDown = stats.hostsUnavailable + _tasksTotal = stats.tasksTotal + _tasksPending = stats.tasksPending + _tasksCompleted = stats.tasksCompleted + _tasksActive = stats.tasksActive + _tasksTerminated = stats.tasksTerminated + _attemptsSuccess = stats.attemptsSuccess.toInt() + _attemptsFailure = stats.attemptsFailure.toInt() + } +} diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReader.kt index 825019e85..50ffa5fc7 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReader.kt @@ -35,6 +35,10 @@ public interface TaskTableReader : Exportable { public fun setValues(table: TaskTableReader) + public fun record(now: Instant) + + public fun reset() + /** * The timestamp of the current entry of the reader relative to the start of the workload. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt new file mode 100644 index 000000000..fdbec463f --- /dev/null +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt @@ -0,0 +1,196 @@ +package org.opendc.compute.simulator.telemetry.table + +import org.opendc.compute.api.TaskState +import org.opendc.compute.simulator.host.SimHost +import org.opendc.compute.simulator.service.ComputeService +import org.opendc.compute.simulator.service.ServiceTask +import java.time.Duration +import java.time.Instant + +/** + * An aggregator for task metrics before they are reported. + */ +public class TaskTableReaderImpl( + private val service: ComputeService, + private val task: ServiceTask, + private val startTime: Duration = Duration.ofMillis(0), +) : TaskTableReader { + override fun copy(): TaskTableReader { + val newTaskTable = + TaskTableReaderImpl( + service, + task, + ) + newTaskTable.setValues(this) + + return newTaskTable + } + + override fun setValues(table: TaskTableReader) { + host = table.host + + _timestamp = table.timestamp + _timestampAbsolute = table.timestampAbsolute + + _cpuLimit = table.cpuLimit + _cpuActiveTime = table.cpuActiveTime + _cpuIdleTime = table.cpuIdleTime + _cpuStealTime = table.cpuStealTime + _cpuLostTime = table.cpuLostTime + _uptime = table.uptime + _downtime = table.downtime + _provisionTime = table.provisionTime + _bootTime = table.bootTime + _bootTimeAbsolute = table.bootTimeAbsolute + + _creationTime = table.creationTime + _finishTime = table.finishTime + + _taskState = table.taskState + } + + /** + * The static information about this task. + */ + override val taskInfo: TaskInfo = + TaskInfo( + task.uid.toString(), + task.name, + "vm", + "x86", + task.flavor.coreCount, + task.flavor.memorySize, + ) + + /** + * The [HostInfo] of the host on which the task is hosted. + */ + override var host: HostInfo? = null + private var _host: SimHost? = null + + private var _timestamp = Instant.MIN + override val timestamp: Instant + get() = _timestamp + + private var _timestampAbsolute = Instant.MIN + override val timestampAbsolute: Instant + get() = _timestampAbsolute + + override val uptime: Long + get() = _uptime - previousUptime + private var _uptime: Long = 0 + private var previousUptime = 0L + + override val downtime: Long + get() = _downtime - previousDowntime + private var _downtime: Long = 0 + private var previousDowntime = 0L + + override val provisionTime: Instant? + get() = _provisionTime + private var _provisionTime: Instant? = null + + override val bootTime: Instant? + get() = _bootTime + private var _bootTime: Instant? = null + + override val creationTime: Instant? + get() = _creationTime + private var _creationTime: Instant? = null + + override val finishTime: Instant? + get() = _finishTime + private var _finishTime: Instant? = null + + override val cpuLimit: Double + get() = _cpuLimit + private var _cpuLimit = 0.0 + + override val cpuActiveTime: Long + get() = _cpuActiveTime - previousCpuActiveTime + private var _cpuActiveTime = 0L + private var previousCpuActiveTime = 0L + + override val cpuIdleTime: Long + get() = _cpuIdleTime - previousCpuIdleTime + private var _cpuIdleTime = 0L + private var previousCpuIdleTime = 0L + + override val cpuStealTime: Long + get() = _cpuStealTime - previousCpuStealTime + private var _cpuStealTime = 0L + private var previousCpuStealTime = 0L + + override val cpuLostTime: Long + get() = _cpuLostTime - previousCpuLostTime + private var _cpuLostTime = 0L + private var previousCpuLostTime = 0L + + override val bootTimeAbsolute: Instant? + get() = _bootTimeAbsolute + private var _bootTimeAbsolute: Instant? = null + + override val taskState: TaskState? + get() = _taskState + private var _taskState: TaskState? = null + + /** + * Record the next cycle. + */ + override fun record(now: Instant) { + val newHost = service.lookupHost(task) + if (newHost != null && newHost.getUid() != _host?.getUid()) { + _host = newHost + host = + HostInfo( + newHost.getUid().toString(), + newHost.getName(), + "x86", + newHost.getModel().coreCount, + newHost.getModel().cpuCapacity, + newHost.getModel().memoryCapacity, + ) + } + + val cpuStats = _host?.getCpuStats(task) + val sysStats = _host?.getSystemStats(task) + + _timestamp = now + _timestampAbsolute = now + startTime + + _cpuLimit = cpuStats?.capacity ?: 0.0 + _cpuActiveTime = cpuStats?.activeTime ?: 0 + _cpuIdleTime = cpuStats?.idleTime ?: 0 + _cpuStealTime = cpuStats?.stealTime ?: 0 + _cpuLostTime = cpuStats?.lostTime ?: 0 + _uptime = sysStats?.uptime?.toMillis() ?: 0 + _downtime = sysStats?.downtime?.toMillis() ?: 0 + _provisionTime = task.launchedAt + _bootTime = sysStats?.bootTime + _creationTime = task.createdAt + _finishTime = task.finishedAt + + _taskState = task.state + + if (sysStats != null) { + _bootTimeAbsolute = sysStats.bootTime + startTime + } else { + _bootTimeAbsolute = null + } + } + + /** + * Finish the aggregation for this cycle. + */ + override fun reset() { + previousUptime = _uptime + previousDowntime = _downtime + previousCpuActiveTime = _cpuActiveTime + previousCpuIdleTime = _cpuIdleTime + previousCpuStealTime = _cpuStealTime + previousCpuLostTime = _cpuLostTime + + _host = null + _cpuLimit = 0.0 + } +} diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt index 3329f19c5..205399662 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt @@ -24,9 +24,11 @@ package org.opendc.compute.topology +import org.opendc.compute.topology.specs.ClusterJSONSpec import org.opendc.compute.topology.specs.ClusterSpec import org.opendc.compute.topology.specs.HostJSONSpec import org.opendc.compute.topology.specs.HostSpec +import org.opendc.compute.topology.specs.PowerSourceSpec import org.opendc.compute.topology.specs.TopologySpec import org.opendc.simulator.compute.cpu.getPowerModel import org.opendc.simulator.compute.models.CpuModel @@ -49,7 +51,7 @@ private val reader = TopologyReader() public fun clusterTopology( pathToFile: String, random: RandomGenerator = SplittableRandom(0), -): List { +): List { return clusterTopology(File(pathToFile), random) } @@ -59,9 +61,9 @@ public fun clusterTopology( public fun clusterTopology( file: File, random: RandomGenerator = SplittableRandom(0), -): List { +): List { val topology = reader.read(file) - return topology.toHostSpecs(random) + return topology.toClusterSpec(random) } /** @@ -70,41 +72,41 @@ public fun clusterTopology( public fun clusterTopology( input: InputStream, random: RandomGenerator = SplittableRandom(0), -): List { +): List { val topology = reader.read(input) - return topology.toHostSpecs(random) + return topology.toClusterSpec(random) } /** * Helper method to convert a [TopologySpec] into a list of [HostSpec]s. */ -private fun TopologySpec.toHostSpecs(random: RandomGenerator): List { - return clusters.flatMap { cluster -> - List(cluster.count) { - cluster.toHostSpecs(random) - }.flatten() +private fun TopologySpec.toClusterSpec(random: RandomGenerator): List { + return clusters.map { cluster -> + cluster.toClusterSpec(random) } } /** - * Helper method to convert a [ClusterSpec] into a list of [HostSpec]s. + * Helper method to convert a [ClusterJSONSpec] into a list of [HostSpec]s. */ private var clusterId = 0 -private fun ClusterSpec.toHostSpecs(random: RandomGenerator): List { +private fun ClusterJSONSpec.toClusterSpec(random: RandomGenerator): ClusterSpec { val hostSpecs = hosts.flatMap { host -> ( List(host.count) { - host.toHostSpecs( + host.toHostSpec( clusterId, random, ) } - ) + ) } + val powerSourceSpec = PowerSourceSpec(UUID(random.nextLong(), (clusterId).toLong()), + totalPower = this.powerSource.totalPower) clusterId++ - return hostSpecs + return ClusterSpec(this.name, hostSpecs, powerSourceSpec); } /** @@ -113,7 +115,7 @@ private fun ClusterSpec.toHostSpecs(random: RandomGenerator): List { private var hostId = 0 private var globalCoreId = 0 -private fun HostJSONSpec.toHostSpecs( +private fun HostJSONSpec.toHostSpec( clusterId: Int, random: RandomGenerator, ): HostSpec { diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt new file mode 100644 index 000000000..5518e4f69 --- /dev/null +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt @@ -0,0 +1,7 @@ +package org.opendc.compute.topology.specs + +public data class ClusterSpec ( + val name: String, + val hostSpecs: List, + val powerSource: PowerSourceSpec +) diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt new file mode 100644 index 000000000..0ec861adc --- /dev/null +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt @@ -0,0 +1,11 @@ +package org.opendc.compute.topology.specs + +import java.util.UUID + +// TODO: add name to class +public data class PowerSourceSpec( + val uid: UUID, + val name: String = "unknown", + val meta: Map = emptyMap(), + val totalPower: Long +) diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt index 974bb4a3a..e14cdb246 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt @@ -34,7 +34,7 @@ import org.opendc.common.units.Power */ @Serializable public data class TopologySpec( - val clusters: List, + val clusters: List, val schemaVersion: Int = 1, ) @@ -46,10 +46,11 @@ public data class TopologySpec( * @param location Location of the cluster. This can impact the carbon intensity */ @Serializable -public data class ClusterSpec( +public data class ClusterJSONSpec( val name: String = "Cluster", val count: Int = 1, val hosts: List, + val powerSource: PowerSourceJSONSpec = PowerSourceJSONSpec.DFLT, val location: String = "NL", ) @@ -65,8 +66,8 @@ public data class ClusterSpec( @Serializable public data class HostJSONSpec( val name: String? = null, - val cpu: CPUSpec, - val memory: MemorySpec, + val cpu: CPUJSONSpec, + val memory: MemoryJSONSpec, val powerModel: PowerModelSpec = PowerModelSpec.DFLT, val count: Int = 1, ) @@ -81,7 +82,7 @@ public data class HostJSONSpec( * @param coreSpeed The speed of the cores */ @Serializable -public data class CPUSpec( +public data class CPUJSONSpec( val vendor: String = "unknown", val modelName: String = "unknown", val arch: String = "unknown", @@ -100,7 +101,7 @@ public data class CPUSpec( * @param memorySize The size of the memory Unit */ @Serializable -public data class MemorySpec( +public data class MemoryJSONSpec( val vendor: String = "unknown", val modelName: String = "unknown", val arch: String = "unknown", @@ -129,3 +130,26 @@ public data class PowerModelSpec( ) } } + +/** + * Definition of a power source used for JSON input. + * + * @property vendor + * @property modelName + * @property arch + * @property totalPower + */ +@Serializable +public data class PowerSourceJSONSpec( + val vendor: String = "unknown", + val modelName: String = "unknown", + val arch: String = "unknown", + val totalPower: Long +) { + public companion object { + public val DFLT: PowerSourceJSONSpec = + PowerSourceJSONSpec( + totalPower = 10000 + ) + } +} diff --git a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt index 3fd271757..9fa1a09a0 100644 --- a/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt +++ b/opendc-experiments/opendc-experiments-base/src/test/kotlin/org/opendc/experiments/base/ScenarioIntegrationTest.kt @@ -40,7 +40,7 @@ import org.opendc.compute.simulator.telemetry.ComputeMonitor import org.opendc.compute.simulator.telemetry.table.HostTableReader import org.opendc.compute.simulator.telemetry.table.ServiceTableReader import org.opendc.compute.topology.clusterTopology -import org.opendc.compute.topology.specs.HostSpec +import org.opendc.compute.topology.specs.ClusterSpec import org.opendc.compute.workload.ComputeWorkloadLoader import org.opendc.compute.workload.Task import org.opendc.compute.workload.sampleByLoad @@ -358,7 +358,7 @@ class ScenarioIntegrationTest { /** * Obtain the topology factory for the test. */ - private fun createTopology(name: String): List { + private fun createTopology(name: String): List { val stream = checkNotNull(object {}.javaClass.getResourceAsStream("/topologies/$name")) return stream.use { clusterTopology(stream) } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java index 00a69efe2..29f36d0dd 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java @@ -112,13 +112,16 @@ public double getCpuUsage() { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public SimMachine( - FlowGraph graph, MachineModel machineModel, CpuPowerModel cpuPowerModel, Consumer completion) { + FlowGraph graph, MachineModel machineModel, CpuPowerModel cpuPowerModel, Multiplexer powerMux, Consumer completion) { this.graph = graph; this.machineModel = machineModel; this.clock = graph.getEngine().getClock(); // Create the psu and cpu and connect them this.psu = new SimPsu(graph); + + graph.addEdge(this.psu, powerMux); + this.cpu = new SimCpu(graph, this.machineModel.getCpu(), 0); graph.addEdge(this.cpu, this.psu); diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java index 58a6b8475..79ff93c02 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java @@ -22,7 +22,6 @@ package org.opendc.simulator.compute.power; -import java.time.InstantSource; import org.opendc.simulator.compute.cpu.SimCpu; import org.opendc.simulator.engine.FlowEdge; import org.opendc.simulator.engine.FlowGraph; @@ -33,15 +32,13 @@ * A {@link SimPsu} implementation that estimates the power consumption based on CPU usage. */ public final class SimPowerSource extends FlowNode implements FlowSupplier { - private final InstantSource clock; - private long lastUpdate; private double powerDemand = 0.0f; private double powerSupplied = 0.0f; private double totalEnergyUsage = 0.0f; - private FlowEdge cpuEdge; + private FlowEdge muxEdge; private double capacity = Long.MAX_VALUE; @@ -55,7 +52,7 @@ public final class SimPowerSource extends FlowNode implements FlowSupplier { * @return true if the InPort is connected to an OutPort, false otherwise. */ public boolean isConnected() { - return cpuEdge != null; + return muxEdge != null; } /** @@ -94,9 +91,7 @@ public double getCapacity() { public SimPowerSource(FlowGraph graph) { super(graph); - this.clock = graph.getEngine().getClock(); - - lastUpdate = graph.getEngine().getClock().millis(); + lastUpdate = this.clock.millis(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -109,7 +104,7 @@ public long onUpdate(long now) { double powerSupply = this.powerDemand; if (powerSupply != this.powerSupplied) { - this.pushSupply(this.cpuEdge, powerSupply); + this.pushSupply(this.muxEdge, powerSupply); } return Long.MAX_VALUE; @@ -159,11 +154,11 @@ public void pushSupply(FlowEdge consumerEdge, double newSupply) { @Override public void addConsumerEdge(FlowEdge consumerEdge) { - this.cpuEdge = consumerEdge; + this.muxEdge = consumerEdge; } @Override public void removeConsumerEdge(FlowEdge consumerEdge) { - this.cpuEdge = null; + this.muxEdge = null; } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java index 381a87542..436c5c120 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java @@ -40,7 +40,7 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer private double totalEnergyUsage = 0.0; private FlowEdge cpuEdge; - private FlowEdge powerEdge; + private FlowEdge powerSupplyEdge; private double capacity = Long.MAX_VALUE; @@ -126,7 +126,7 @@ public void updateCounters(long now) { long duration = now - lastUpdate; if (duration > 0) { // Compute the energy usage of the psu - this.totalEnergyUsage += (double) (this.powerSupplied * duration * 0.001); + this.totalEnergyUsage += (this.powerSupplied * duration * 0.001); } } @@ -136,20 +136,12 @@ public void updateCounters(long now) { @Override public void pushDemand(FlowEdge supplierEdge, double newDemand) { - if (newDemand == this.powerDemand) { - return; - } - this.powerDemand = newDemand; - powerEdge.pushSupply(newDemand); + powerSupplyEdge.pushDemand(newDemand); } @Override public void pushSupply(FlowEdge consumerEdge, double newSupply) { - if (newSupply == this.powerSupplied) { - return; - } - this.powerSupplied = newSupply; cpuEdge.pushSupply(newSupply); } @@ -160,8 +152,10 @@ public void handleDemand(FlowEdge consumerEdge, double newPowerDemand) { return; } + updateCounters(); this.powerDemand = newPowerDemand; - this.invalidate(); + + pushDemand(this.powerSupplyEdge, newPowerDemand); } @Override @@ -170,8 +164,10 @@ public void handleSupply(FlowEdge supplierEdge, double newPowerSupply) { return; } + updateCounters(); this.powerSupplied = newPowerSupply; - this.invalidate(); + + pushSupply(this.cpuEdge, newPowerSupply); } @Override @@ -181,7 +177,7 @@ public void addConsumerEdge(FlowEdge consumerEdge) { @Override public void addSupplierEdge(FlowEdge supplierEdge) { - this.powerEdge = supplierEdge; + this.powerSupplyEdge = supplierEdge; } @Override @@ -191,6 +187,6 @@ public void removeConsumerEdge(FlowEdge consumerEdge) { @Override public void removeSupplierEdge(FlowEdge supplierEdge) { - this.powerEdge = null; + this.powerSupplyEdge = null; } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java index 59e38ce18..b269564de 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java @@ -196,22 +196,6 @@ public void makeSnapshot(long now) { this.invalidate(); } - /** - * Update the Fragments that are being used by the SimTraceWorkload - * @param newFragments - * @param offset - */ - public void updateFragments(LinkedList newFragments, long offset) { - this.remainingFragments = newFragments; - - // Start the first Fragment - this.currentFragment = this.remainingFragments.pop(); - pushDemand(this.machineEdge, (double) this.currentFragment.cpuUsage()); - this.startOfFragment = offset; - - this.invalidate(); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FlowGraph Related functionality //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt index 70152b2cc..4b029d729 100644 --- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt +++ b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt @@ -31,7 +31,9 @@ import org.opendc.compute.simulator.provisioner.setupComputeService import org.opendc.compute.simulator.provisioner.setupHosts import org.opendc.compute.simulator.scheduler.createComputeScheduler import org.opendc.compute.simulator.service.ComputeService +import org.opendc.compute.topology.specs.ClusterSpec import org.opendc.compute.topology.specs.HostSpec +import org.opendc.compute.topology.specs.PowerSourceSpec import org.opendc.compute.workload.ComputeWorkloadLoader import org.opendc.compute.workload.sampleByLoad import org.opendc.compute.workload.trace @@ -233,7 +235,7 @@ public class OpenDCRunner( private inner class SimulationTask( private val scenario: Scenario, private val repeat: Int, - private val topology: List, + private val topologyHosts: List, ) : RecursiveTask() { override fun compute(): WebComputeMonitor.Results { val monitor = WebComputeMonitor() @@ -262,6 +264,10 @@ public class OpenDCRunner( val scenario = scenario + val powerSourceSpec = PowerSourceSpec(UUID(0, 0), + totalPower = Long.MAX_VALUE) + val topology = listOf(ClusterSpec("cluster", topologyHosts, powerSourceSpec)) + Provisioner(dispatcher, seed).use { provisioner -> provisioner.runSteps( setupComputeService( From 7ec81274fe0f4c3b495424dd2043a4d628b1075f Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Wed, 30 Oct 2024 16:32:58 +0100 Subject: [PATCH 2/3] Added power sources to OpenDC. In the current form each Cluster has a single power source that is connected to all hosts in that cluster --- .../simulator/telemetry/table/PowerSourceTableReaderImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt index 98374fe23..aa2992c2b 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt @@ -76,7 +76,7 @@ public class PowerSourceTableReaderImpl( _hostsConnected = 0 _powerDraw = powerSource.powerDraw _energyUsage = powerSource.energyUsage - _carbonIntensity = carbonTrace.getCarbonIntensity(timestampAbsolute) + _carbonIntensity = 0.0 _carbonEmission = carbonIntensity * (energyUsage / 3600000.0) } From 10be8967d47d8f3379f4e150abc1756792657380 Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Wed, 30 Oct 2024 16:45:06 +0100 Subject: [PATCH 3/3] Ran spotless Kotlin and Java --- .../opendc/compute/simulator/host/SimHost.kt | 4 +-- .../provisioner/HostsProvisioningStep.kt | 7 +++-- .../telemetry/ComputeMetricReader.kt | 16 ++++++------ .../parquet/ParquetComputeMonitor.kt | 10 +++---- .../telemetry/table/HostTableReaderImpl.kt | 22 ++++++++++++++++ .../telemetry/table/PowerSourceTableReader.kt | 1 + .../table/PowerSourceTableReaderImpl.kt | 26 ++++++++++++++++--- .../telemetry/table/ServiceTableReaderImpl.kt | 22 ++++++++++++++++ .../telemetry/table/TaskTableReaderImpl.kt | 22 ++++++++++++++++ .../compute/topology/TopologyFactories.kt | 11 +++++--- .../compute/topology/specs/ClusterSpec.kt | 26 +++++++++++++++++-- .../compute/topology/specs/PowerSourceSpec.kt | 24 ++++++++++++++++- .../compute/topology/specs/TopologySpecs.kt | 4 +-- .../simulator/compute/machine/SimMachine.java | 6 ++++- .../org/opendc/web/runner/OpenDCRunner.kt | 7 +++-- 15 files changed, 174 insertions(+), 34 deletions(-) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt index c7b94f93c..32fcf2775 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/host/SimHost.kt @@ -62,7 +62,7 @@ public class SimHost( private val graph: FlowGraph, private val machineModel: MachineModel, private val powerModel: CpuPowerModel, - private val powerMux: Multiplexer + private val powerMux: Multiplexer, ) : AutoCloseable { /** * The event listeners registered with this host. @@ -132,7 +132,7 @@ public class SimHost( this.graph, this.machineModel, this.powerModel, - this.powerMux + this.powerMux, ) { cause -> hostState = if (cause != null) HostState.ERROR else HostState.DOWN } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt index 1d6e8a5fb..d2231f0de 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/provisioner/HostsProvisioningStep.kt @@ -52,8 +52,7 @@ public class HostsProvisioningStep internal constructor( val engine = FlowEngine.create(ctx.dispatcher) val graph = engine.newGraph() - for (cluster in clusterSpecs){ - + for (cluster in clusterSpecs) { // Create the Power Source to which hosts are connected // TODO: Add connection to totalPower val simPowerSource = SimPowerSource(graph) @@ -74,7 +73,7 @@ public class HostsProvisioningStep internal constructor( graph, hostSpec.model, hostSpec.cpuPowerModel, - powerMux + powerMux, ) require(simHosts.add(simHost)) { "Host with uid ${hostSpec.uid} already exists" } @@ -87,7 +86,7 @@ public class HostsProvisioningStep internal constructor( simHost.close() } - for (simPowerSource in simPowerSources){ + for (simPowerSource in simPowerSources) { // TODO: add close function // simPowerSource.close() } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt index 60385279f..fb7c8f895 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/ComputeMetricReader.kt @@ -87,7 +87,6 @@ public class ComputeMetricReader( */ private val powerSourceTableReaders = mutableMapOf() - /** * The background job that is responsible for collecting the metrics every cycle. */ @@ -148,13 +147,14 @@ public class ComputeMetricReader( this.service.clearTasksToRemove() for (simPowerSource in this.service.powerSources) { - val reader = this.powerSourceTableReaders.computeIfAbsent(simPowerSource) { - PowerSourceTableReaderImpl( - it, - startTime, - carbonTrace - ) - } + val reader = + this.powerSourceTableReaders.computeIfAbsent(simPowerSource) { + PowerSourceTableReaderImpl( + it, + startTime, + carbonTrace, + ) + } reader.record(now) this.monitor.record(reader.copy()) diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt index f8f5551c4..b3150018c 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/parquet/ParquetComputeMonitor.kt @@ -123,11 +123,11 @@ public class ParquetComputeMonitor( bufferSize = bufferSize, ), powerSourceExporter = - Exporter( - outputFile = File(base, "$partition/powerSource.parquet").also { it.parentFile.mkdirs() }, - columns = powerSourceExportColumns ?: Exportable.getAllLoadedColumns(), - bufferSize = bufferSize, - ), + Exporter( + outputFile = File(base, "$partition/powerSource.parquet").also { it.parentFile.mkdirs() }, + columns = powerSourceExportColumns ?: Exportable.getAllLoadedColumns(), + bufferSize = bufferSize, + ), serviceExporter = Exporter( outputFile = File(base, "$partition/service.parquet").also { it.parentFile.mkdirs() }, diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt index 8408f2b99..ab8c00360 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/HostTableReaderImpl.kt @@ -1,3 +1,25 @@ +/* + * 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.telemetry.table import org.opendc.compute.carbon.CarbonTrace diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt index eb76d2de4..cd2b2d2c8 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReader.kt @@ -36,6 +36,7 @@ public interface PowerSourceTableReader : Exportable { public fun record(now: Instant) public fun reset() + /** * The timestamp of the current entry of the reader relative to the start of the workload. */ diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt index aa2992c2b..91918ea8b 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/PowerSourceTableReaderImpl.kt @@ -1,3 +1,25 @@ +/* + * 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.telemetry.table import org.opendc.compute.carbon.CarbonTrace @@ -16,7 +38,7 @@ public class PowerSourceTableReaderImpl( override fun copy(): PowerSourceTableReader { val newPowerSourceTable = PowerSourceTableReaderImpl( - powerSource + powerSource, ) newPowerSourceTable.setValues(this) @@ -69,7 +91,6 @@ public class PowerSourceTableReaderImpl( * Record the next cycle. */ override fun record(now: Instant) { - _timestamp = now _timestampAbsolute = now + startTime @@ -84,7 +105,6 @@ public class PowerSourceTableReaderImpl( * Finish the aggregation for this cycle. */ override fun reset() { - previousEnergyUsage = _energyUsage _hostsConnected = 0 diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt index 909f76777..52a25021a 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/ServiceTableReaderImpl.kt @@ -1,3 +1,25 @@ +/* + * 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.telemetry.table import org.opendc.compute.simulator.service.ComputeService diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt index fdbec463f..5a0897f78 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/table/TaskTableReaderImpl.kt @@ -1,3 +1,25 @@ +/* + * 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.telemetry.table import org.opendc.compute.api.TaskState diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt index 205399662..76c653bf2 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/TopologyFactories.kt @@ -101,12 +101,15 @@ private fun ClusterJSONSpec.toClusterSpec(random: RandomGenerator): ClusterSpec random, ) } - ) + ) } - val powerSourceSpec = PowerSourceSpec(UUID(random.nextLong(), (clusterId).toLong()), - totalPower = this.powerSource.totalPower) + val powerSourceSpec = + PowerSourceSpec( + UUID(random.nextLong(), (clusterId).toLong()), + totalPower = this.powerSource.totalPower, + ) clusterId++ - return ClusterSpec(this.name, hostSpecs, powerSourceSpec); + return ClusterSpec(this.name, hostSpecs, powerSourceSpec) } /** diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt index 5518e4f69..3b49b2666 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/ClusterSpec.kt @@ -1,7 +1,29 @@ +/* + * 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.topology.specs -public data class ClusterSpec ( +public data class ClusterSpec( val name: String, val hostSpecs: List, - val powerSource: PowerSourceSpec + val powerSource: PowerSourceSpec, ) diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt index 0ec861adc..797706841 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/PowerSourceSpec.kt @@ -1,3 +1,25 @@ +/* + * 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.topology.specs import java.util.UUID @@ -7,5 +29,5 @@ public data class PowerSourceSpec( val uid: UUID, val name: String = "unknown", val meta: Map = emptyMap(), - val totalPower: Long + val totalPower: Long, ) diff --git a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt index e14cdb246..9acdf72a8 100644 --- a/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt +++ b/opendc-compute/opendc-compute-topology/src/main/kotlin/org/opendc/compute/topology/specs/TopologySpecs.kt @@ -144,12 +144,12 @@ public data class PowerSourceJSONSpec( val vendor: String = "unknown", val modelName: String = "unknown", val arch: String = "unknown", - val totalPower: Long + val totalPower: Long, ) { public companion object { public val DFLT: PowerSourceJSONSpec = PowerSourceJSONSpec( - totalPower = 10000 + totalPower = 10000, ) } } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java index 29f36d0dd..4602223ca 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java @@ -112,7 +112,11 @@ public double getCpuUsage() { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public SimMachine( - FlowGraph graph, MachineModel machineModel, CpuPowerModel cpuPowerModel, Multiplexer powerMux, Consumer completion) { + FlowGraph graph, + MachineModel machineModel, + CpuPowerModel cpuPowerModel, + Multiplexer powerMux, + Consumer completion) { this.graph = graph; this.machineModel = machineModel; this.clock = graph.getEngine().getClock(); diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt index 4b029d729..ca42f5669 100644 --- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt +++ b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt @@ -264,8 +264,11 @@ public class OpenDCRunner( val scenario = scenario - val powerSourceSpec = PowerSourceSpec(UUID(0, 0), - totalPower = Long.MAX_VALUE) + val powerSourceSpec = + PowerSourceSpec( + UUID(0, 0), + totalPower = Long.MAX_VALUE, + ) val topology = listOf(ClusterSpec("cluster", topologyHosts, powerSourceSpec)) Provisioner(dispatcher, seed).use { provisioner ->