1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
|
/*
* 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 kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.opendc.common.units.DataRate
import org.opendc.common.units.DataSize
import org.opendc.common.units.Frequency
import org.opendc.common.units.Power
import org.opendc.simulator.compute.power.batteries.BatteryAggregator
import org.opendc.simulator.compute.power.batteries.SimBattery
import org.opendc.simulator.compute.power.batteries.policy.BatteryPolicy
import org.opendc.simulator.compute.power.batteries.policy.DoubleThresholdBatteryPolicy
import org.opendc.simulator.compute.power.batteries.policy.RunningMeanBatteryPolicy
import org.opendc.simulator.compute.power.batteries.policy.RunningMeanPlusBatteryPolicy
import org.opendc.simulator.compute.power.batteries.policy.SingleThresholdBatteryPolicy
import org.opendc.simulator.compute.virtualization.VirtualizationOverheadModelFactory.VirtualizationOverheadModelEnum
import org.opendc.simulator.engine.engine.FlowEngine
import org.opendc.simulator.engine.graph.distributionPolicies.FlowDistributorFactory.DistributionPolicy
/**
* Definition of a Topology modeled in the simulation.
*
* @param clusters List of the clusters in this topology
*/
@Serializable
public data class TopologySpec(
val clusters: List<ClusterJSONSpec>,
)
/**
* Definition of a compute cluster modeled in the simulation.
*
* @param name The name of the cluster.
* @param hosts List of the different hosts (nodes) available in this cluster
*/
@Serializable
public data class ClusterJSONSpec(
val name: String = "Cluster",
val count: Int = 1,
val hosts: List<HostJSONSpec>,
val powerSource: PowerSourceJSONSpec = PowerSourceJSONSpec.DFLT,
val battery: BatteryJSONSpec? = null,
)
/**
* Definition of a compute host modeled in the simulation.
*
* @param name The name of the host.
* @param cpu The CPU available in this cluster
* @param memory The amount of RAM memory available in Byte
* @param count The power model used to determine the power draw of a host
* @param gpu The GPU available in this cluster (optional)
* @param cpuPowerModel The power model used to determine the power draw of the CPU
* @param gpuPowerModel The power model used to determine the power draw of the GPU
* @param cpuDistributionPolicy The distribution policy used to distribute CPU resources
* @param gpuDistributionPolicy The distribution policy used to distribute GPU resources
*/
@Serializable
public data class HostJSONSpec(
val name: String = "Host",
val cpu: CPUJSONSpec,
val count: Int = 1,
val memory: MemoryJSONSpec,
val gpu: GPUJSONSpec? = null,
val cpuPowerModel: PowerModelSpec = PowerModelSpec.DFLT,
val gpuPowerModel: PowerModelSpec = PowerModelSpec.DFLT,
val cpuDistributionPolicy: DistributionPolicySpec = MaxMinFairnessDistributionPolicySpec(),
val gpuDistributionPolicy: DistributionPolicySpec = MaxMinFairnessDistributionPolicySpec(),
)
/**
* Definition of a compute CPU modeled in the simulation.
*
* @param modelName The model name of the device.
* @param vendor The vendor of the storage device.
* @param arch The micro-architecture of the processor node.
* @param count The number of CPUs of this type in the host.
* @param coreCount The number of cores in the CPU.
* @param coreSpeed The speed of the cores.
*/
@Serializable
public data class CPUJSONSpec(
val modelName: String = "unknown",
val vendor: String = "unknown",
val arch: String = "unknown",
val count: Int = 1,
val coreCount: Int,
val coreSpeed: Frequency,
)
/**
* Definition of a compute Memory modeled in the simulation.
*
* @param modelName The model name of the device.
* @param vendor The vendor of the storage device.
* @param arch The micro-architecture of the processor node.
* @param memorySize The size of the memory Unit
* @param memorySpeed The speed of the cores
*/
@Serializable
public data class MemoryJSONSpec(
val modelName: String = "unknown",
val vendor: String = "unknown",
val arch: String = "unknown",
val memorySize: DataSize,
val memorySpeed: Frequency = Frequency.ofMHz(-1),
)
@Serializable
public data class GPUJSONSpec(
val count: Int = 1,
val coreCount: Int,
val coreSpeed: Frequency,
val memorySize: DataSize = DataSize.ofMiB(-1),
val memoryBandwidth: DataRate = DataRate.ofKibps(-1),
val vendor: String = "unknown",
val modelName: String = "unknown",
val architecture: String = "unknown",
val virtualizationOverHeadModel: VirtualizationOverheadModelSpec = NoVirtualizationOverheadModelSpec(),
)
@Serializable
public data class PowerModelSpec(
val modelType: String,
val power: Power = Power.ofWatts(400),
val maxPower: Power,
val idlePower: Power,
val calibrationFactor: Double = 1.0,
val asymUtil: Double = 0.0,
val dvfs: Boolean = true,
) {
init {
require(maxPower >= idlePower) { "The max power of a power model can not be less than the idle power" }
}
public companion object {
public val DFLT: PowerModelSpec =
PowerModelSpec(
modelType = "linear",
power = Power.ofWatts(350),
maxPower = Power.ofWatts(400.0),
idlePower = Power.ofWatts(200.0),
calibrationFactor = 1.0,
asymUtil = 0.0,
dvfs = true,
)
}
}
@Serializable
public sealed interface DistributionPolicySpec {
public val type: DistributionPolicy
}
@Serializable
@SerialName("BEST_EFFORT")
public data class BestEffortDistributionPolicySpec(
override val type: DistributionPolicy = DistributionPolicy.BEST_EFFORT,
val updateIntervalLength: Long = 1000L,
) : DistributionPolicySpec
@Serializable
@SerialName("EQUAL_SHARE")
public data class EqualShareDistributionPolicySpec(
override val type: DistributionPolicy = DistributionPolicy.EQUAL_SHARE,
) : DistributionPolicySpec
@Serializable
@SerialName("FIRST_FIT")
public data class FirstFitDistributionPolicySpec(
override val type: DistributionPolicy = DistributionPolicy.FIRST_FIT,
) : DistributionPolicySpec
@Serializable
@SerialName("FIXED_SHARE")
public data class FixedShareDistributionPolicySpec(
override val type: DistributionPolicy = DistributionPolicy.FIXED_SHARE,
val shareRatio: Double = 1.0,
) : DistributionPolicySpec
public fun DistributionPolicySpec.toDistributionPolicy(): DistributionPolicy {
return when (this) {
is BestEffortDistributionPolicySpec ->
DistributionPolicy.BEST_EFFORT.apply {
setProperty("updateIntervalLength", updateIntervalLength)
}
is EqualShareDistributionPolicySpec -> DistributionPolicy.EQUAL_SHARE
is FixedShareDistributionPolicySpec ->
DistributionPolicy.FIXED_SHARE.apply {
setProperty("shareRatio", shareRatio)
}
is FirstFitDistributionPolicySpec -> DistributionPolicy.FIRST_FIT
is MaxMinFairnessDistributionPolicySpec -> DistributionPolicy.MAX_MIN_FAIRNESS
}
}
@Serializable
@SerialName("MAX_MIN_FAIRNESS")
public data class MaxMinFairnessDistributionPolicySpec(
override val type: DistributionPolicy = DistributionPolicy.MAX_MIN_FAIRNESS,
) : DistributionPolicySpec
@Serializable
public sealed interface VirtualizationOverheadModelSpec {
public val type: VirtualizationOverheadModelEnum
}
@Serializable
@SerialName("NONE")
public data class NoVirtualizationOverheadModelSpec(
override val type: VirtualizationOverheadModelEnum =
VirtualizationOverheadModelEnum.NONE,
) : VirtualizationOverheadModelSpec
@Serializable
@SerialName("CONSTANT")
public data class ConstantVirtualizationOverheadModelSpec(
override val type: VirtualizationOverheadModelEnum = VirtualizationOverheadModelEnum.CONSTANT,
val percentageOverhead: Double? = -1.0,
) : VirtualizationOverheadModelSpec
@Serializable
@SerialName("SHARE_BASED")
public data class ShareBasedVirtualizationOverheadModelSpec(
override val type: VirtualizationOverheadModelEnum = VirtualizationOverheadModelEnum.SHARE_BASED,
) : VirtualizationOverheadModelSpec
public fun VirtualizationOverheadModelSpec.toVirtualizationOverheadModel(): VirtualizationOverheadModelEnum {
return when (this) {
is NoVirtualizationOverheadModelSpec -> VirtualizationOverheadModelEnum.NONE
is ConstantVirtualizationOverheadModelSpec ->
VirtualizationOverheadModelEnum.CONSTANT.apply {
if (percentageOverhead != null) {
// -1.0 is used to indicate that no percentage overhead is specified
if (percentageOverhead != -1.0 && (percentageOverhead < 0.0 || percentageOverhead > 1.0)) {
throw IllegalArgumentException("Percentage overhead must be between 0.0 and 1.0")
}
setProperty("percentageOverhead", percentageOverhead)
}
}
is ShareBasedVirtualizationOverheadModelSpec -> VirtualizationOverheadModelEnum.SHARE_BASED
}
}
/**
* Definition of a power source used for JSON input.
*
* @property maxPower in Watt
*/
@Serializable
public data class PowerSourceJSONSpec(
val name: String = "PowerSource",
val maxPower: Long = Long.MAX_VALUE,
val carbonTracePath: String? = null,
) {
public companion object {
public val DFLT: PowerSourceJSONSpec =
PowerSourceJSONSpec()
}
}
/**
* Definition of a battery used for JSON input.
*
* @property name The name of the battery
* @property capacity The capacity of the battery in kWh
* @property chargingSpeed The charging speed of the battery in W
* @property initialCharge The initial charge in the battery
* @property batteryPolicy The policy used to decide when the battery charges and discharges
* @property embodiedCarbon The embodied carbon needed to create the battery in gram
* @property expectedLifetime The expected lifetime of the battery in years
*
*/
@Serializable
public data class BatteryJSONSpec(
val name: String = "Battery",
var capacity: Double,
val chargingSpeed: Double,
var initialCharge: Double = 0.0,
val batteryPolicy: BatteryPolicyJSONSpec,
var embodiedCarbon: Double = 0.0,
var expectedLifetime: Double = 0.0,
)
@Serializable
public sealed interface BatteryPolicyJSONSpec
@Serializable
@SerialName("single")
public data class SingleBatteryPolicyJSONSpec(
val carbonThreshold: Double,
) : BatteryPolicyJSONSpec
@Serializable
@SerialName("double")
public data class DoubleBatteryPolicyJSONSpec(
val lowerThreshold: Double,
val upperThreshold: Double,
) : BatteryPolicyJSONSpec
@Serializable
@SerialName("runningMean")
public data class RunningMeanPolicyJSONSpec(
val startingThreshold: Double,
val windowSize: Int,
) : BatteryPolicyJSONSpec
@Serializable
@SerialName("runningMeanPlus")
public data class RunningMeanPlusPolicyJSONSpec(
val startingThreshold: Double,
val windowSize: Int,
) : BatteryPolicyJSONSpec
@Serializable
@SerialName("runningMedian")
public data class RunningMedianPolicyJSONSpec(
val startingThreshold: Double,
val windowSize: Int,
) : BatteryPolicyJSONSpec
@Serializable
@SerialName("runningQuartiles")
public data class RunningQuartilesPolicyJSONSpec(
val startingThreshold: Double,
val windowSize: Int,
) : BatteryPolicyJSONSpec
public fun createSimBatteryPolicy(
batterySpec: BatteryPolicyJSONSpec,
engine: FlowEngine,
battery: SimBattery,
batteryAggregator: BatteryAggregator,
): BatteryPolicy {
return when (batterySpec) {
is SingleBatteryPolicyJSONSpec ->
SingleThresholdBatteryPolicy(
engine,
battery,
batteryAggregator,
batterySpec.carbonThreshold,
)
is DoubleBatteryPolicyJSONSpec ->
DoubleThresholdBatteryPolicy(
engine,
battery,
batteryAggregator,
batterySpec.lowerThreshold,
batterySpec.upperThreshold,
)
is RunningMeanPolicyJSONSpec ->
RunningMeanBatteryPolicy(
engine,
battery,
batteryAggregator,
batterySpec.startingThreshold,
batterySpec.windowSize,
)
is RunningMeanPlusPolicyJSONSpec ->
RunningMeanPlusBatteryPolicy(
engine,
battery,
batteryAggregator,
batterySpec.startingThreshold,
batterySpec.windowSize,
)
else -> throw IllegalArgumentException("Unknown battery policy")
}
}
|