diff options
Diffstat (limited to 'opendc-compute')
2 files changed, 102 insertions, 40 deletions
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt index 4b96872b..b9d02185 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimHost.kt @@ -109,6 +109,7 @@ public class SimHost( * The virtual machines running on the hypervisor. */ private val guests = HashMap<Server, Guest>() + private val _guests = mutableListOf<Guest>() override val state: HostState get() = _state @@ -199,7 +200,7 @@ public class SimHost( require(canFit(key)) { "Server does not fit" } val machine = hypervisor.createMachine(key.flavor.toMachineModel(), key.name) - Guest( + val newGuest = Guest( scope.coroutineContext, clock, this, @@ -208,6 +209,9 @@ public class SimHost( server, machine ) + + _guests.add(newGuest) + newGuest } if (start) { @@ -231,7 +235,7 @@ public class SimHost( override suspend fun delete(server: Server) { val guest = guests[server] ?: return - guest.terminate() + guest.delete() } override fun addListener(listener: HostListener) { @@ -253,7 +257,7 @@ public class SimHost( public suspend fun fail() { reset() - for (guest in guests.values) { + for (guest in _guests) { guest.fail() } } @@ -266,7 +270,7 @@ public class SimHost( // Wait for the hypervisor to launch before recovering the guests yield() - for (guest in guests.values) { + for (guest in _guests) { guest.recover() } } @@ -357,11 +361,17 @@ public class SimHost( var error = 0L var invalid = 0L - for ((_, guest) in guests) { + val guests = _guests.listIterator() + for (guest in guests) { when (guest.state) { ServerState.TERMINATED -> terminated++ ServerState.RUNNING -> running++ ServerState.ERROR -> error++ + ServerState.DELETED -> { + // Remove guests that have been deleted + this.guests.remove(guest.server) + guests.remove() + } else -> invalid++ } } @@ -380,8 +390,9 @@ public class SimHost( private fun collectCpuLimit(result: ObservableDoubleMeasurement) { result.observe(_cpuLimit) - for (guest in guests.values) { - guest.collectCpuLimit(result) + val guests = _guests + for (i in guests.indices) { + guests[i].collectCpuLimit(result) } } @@ -401,8 +412,9 @@ public class SimHost( result.observe(counters.cpuStealTime / 1000L, _stealState) result.observe(counters.cpuLostTime / 1000L, _lostState) - for (guest in guests.values) { - guest.collectCpuTime(result) + val guests = _guests + for (i in guests.indices) { + guests[i].collectCpuTime(result) } } @@ -423,8 +435,9 @@ public class SimHost( _downtime += duration } - for (guest in guests.values) { - guest.updateUptime(duration) + val guests = _guests + for (i in guests.indices) { + guests[i].updateUptime(duration) } } @@ -442,8 +455,9 @@ public class SimHost( result.observe(_uptime, _upState) result.observe(_downtime, _downState) - for (guest in guests.values) { - guest.collectUptime(result) + val guests = _guests + for (i in guests.indices) { + guests[i].collectUptime(result) } } @@ -457,8 +471,9 @@ public class SimHost( result.observe(_bootTime) } - for (guest in guests.values) { - guest.collectBootTime(result) + val guests = _guests + for (i in guests.indices) { + guests[i].collectBootTime(result) } } } diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt index 3ac165c8..5ea1860d 100644 --- a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt +++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/internal/Guest.kt @@ -24,6 +24,7 @@ package org.opendc.compute.simulator.internal import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.Attributes +import io.opentelemetry.api.common.AttributesBuilder import io.opentelemetry.api.metrics.ObservableDoubleMeasurement import io.opentelemetry.api.metrics.ObservableLongMeasurement import io.opentelemetry.semconv.resource.attributes.ResourceAttributes @@ -71,17 +72,7 @@ internal class Guest( /** * The attributes of the guest. */ - val attributes: Attributes = Attributes.builder() - .put(ResourceAttributes.HOST_NAME, server.name) - .put(ResourceAttributes.HOST_ID, server.uid.toString()) - .put(ResourceAttributes.HOST_TYPE, server.flavor.name) - .put(AttributeKey.longKey("host.num_cpus"), server.flavor.cpuCount.toLong()) - .put(AttributeKey.longKey("host.mem_capacity"), server.flavor.memorySize) - .put(AttributeKey.stringArrayKey("host.labels"), server.labels.map { (k, v) -> "$k:$v" }) - .put(ResourceAttributes.HOST_ARCH, ResourceAttributes.HostArchValues.AMD64) - .put(ResourceAttributes.HOST_IMAGE_NAME, server.image.name) - .put(ResourceAttributes.HOST_IMAGE_ID, server.image.uid.toString()) - .build() + val attributes: Attributes = GuestAttributes(this) /** * Start the guest. @@ -114,12 +105,12 @@ internal class Guest( } /** - * Terminate the guest. + * Delete the guest. * * This operation will stop the guest if it is running on the host and remove all resources associated with the * guest. */ - suspend fun terminate() { + suspend fun delete() { stop() state = ServerState.DELETED @@ -224,12 +215,10 @@ internal class Guest( private var _uptime = 0L private var _downtime = 0L - private val _upState = Attributes.builder() - .putAll(attributes) + private val _upState = attributes.toBuilder() .put(STATE_KEY, "up") .build() - private val _downState = Attributes.builder() - .putAll(attributes) + private val _downState = attributes.toBuilder() .put(STATE_KEY, "down") .build() @@ -263,20 +252,16 @@ internal class Guest( } } - private val _activeState = Attributes.builder() - .putAll(attributes) + private val _activeState = attributes.toBuilder() .put(STATE_KEY, "active") .build() - private val _stealState = Attributes.builder() - .putAll(attributes) + private val _stealState = attributes.toBuilder() .put(STATE_KEY, "steal") .build() - private val _lostState = Attributes.builder() - .putAll(attributes) + private val _lostState = attributes.toBuilder() .put(STATE_KEY, "lost") .build() - private val _idleState = Attributes.builder() - .putAll(attributes) + private val _idleState = attributes.toBuilder() .put(STATE_KEY, "idle") .build() @@ -300,4 +285,66 @@ internal class Guest( fun collectCpuLimit(result: ObservableDoubleMeasurement) { result.observe(_cpuLimit, attributes) } + + /** + * An optimized [Attributes] implementation. + */ + private class GuestAttributes(private val uid: String, private val attributes: Attributes) : Attributes by attributes { + /** + * Construct a [GuestAttributes] instance from a [Guest]. + */ + constructor(guest: Guest) : this( + guest.server.uid.toString(), + Attributes.builder() + .put(ResourceAttributes.HOST_NAME, guest.server.name) + .put(ResourceAttributes.HOST_ID, guest.server.uid.toString()) + .put(ResourceAttributes.HOST_TYPE, guest.server.flavor.name) + .put(AttributeKey.longKey("host.num_cpus"), guest.server.flavor.cpuCount.toLong()) + .put(AttributeKey.longKey("host.mem_capacity"), guest.server.flavor.memorySize) + .put(AttributeKey.stringArrayKey("host.labels"), guest.server.labels.map { (k, v) -> "$k:$v" }) + .put(ResourceAttributes.HOST_ARCH, ResourceAttributes.HostArchValues.AMD64) + .put(ResourceAttributes.HOST_IMAGE_NAME, guest.server.image.name) + .put(ResourceAttributes.HOST_IMAGE_ID, guest.server.image.uid.toString()) + .build() + ) + + override fun <T : Any?> get(key: AttributeKey<T>): T? { + // Optimize access to the HOST_ID key which is accessed quite often + if (key == ResourceAttributes.HOST_ID) { + @Suppress("UNCHECKED_CAST") + return uid as T? + } + return attributes.get(key) + } + + override fun toBuilder(): AttributesBuilder { + val delegate = attributes.toBuilder() + return object : AttributesBuilder { + + override fun putAll(attributes: Attributes): AttributesBuilder { + delegate.putAll(attributes) + return this + } + + override fun <T : Any?> put(key: AttributeKey<Long>, value: Int): AttributesBuilder { + delegate.put<T>(key, value) + return this + } + + override fun <T : Any?> put(key: AttributeKey<T>, value: T): AttributesBuilder { + delegate.put(key, value) + return this + } + + override fun build(): Attributes = GuestAttributes(uid, delegate.build()) + } + } + + override fun equals(other: Any?): Boolean = attributes == other + + // Cache hash code + private val _hash = attributes.hashCode() + + override fun hashCode(): Int = _hash + } } |
