blob: b02d5dae409412c1c7a0255fed417323f54fa5bf [file] [log] [blame]
/**
* *******************************************************************************
* Copyright (c) 2015-2021 Robert Bosch GmbH and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Robert Bosch GmbH - initial API and implementation
* *******************************************************************************
*/
package org.eclipse.app4mc.amalthea.validations.standard.tests
import java.util.List
import org.eclipse.app4mc.amalthea.model.Amalthea
import org.eclipse.app4mc.amalthea.model.InterruptController
import org.eclipse.app4mc.amalthea.model.ProcessingUnit
import org.eclipse.app4mc.amalthea.model.ProcessingUnitDefinition
import org.eclipse.app4mc.amalthea.model.SchedulerAllocation
import org.eclipse.app4mc.amalthea.model.Task
import org.eclipse.app4mc.amalthea.model.TaskScheduler
import org.eclipse.app4mc.amalthea.model.builder.AmaltheaBuilder
import org.eclipse.app4mc.amalthea.model.builder.HardwareBuilder
import org.eclipse.app4mc.amalthea.model.builder.MappingBuilder
import org.eclipse.app4mc.amalthea.model.builder.OperatingSystemBuilder
import org.eclipse.app4mc.amalthea.model.builder.SoftwareBuilder
import org.eclipse.app4mc.amalthea.validations.standard.EMFProfile
import org.eclipse.app4mc.amalthea.validations.standard.MappingProfile
import org.eclipse.app4mc.validation.core.Severity
import org.eclipse.app4mc.validation.core.ValidationDiagnostic
import org.eclipse.app4mc.validation.util.ValidationExecutor
import org.junit.Test
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertTrue
import org.eclipse.app4mc.amalthea.model.HwStructure
import org.eclipse.app4mc.amalthea.model.util.HardwareUtil
class MappingModelTests {
extension AmaltheaBuilder b1 = new AmaltheaBuilder
extension SoftwareBuilder b2 = new SoftwareBuilder
extension OperatingSystemBuilder b3 = new OperatingSystemBuilder
extension HardwareBuilder b4 = new HardwareBuilder
extension MappingBuilder b5 = new MappingBuilder
val executor = new ValidationExecutor( #[MappingProfile, EMFProfile] )
def List<ValidationDiagnostic> runExecutor(Amalthea model) {
executor.validate(model)
executor.results
}
def Amalthea createValidTestModel() {
amalthea [
softwareModel [
task [ name = "TestTask" ]
]
hardwareModel [
definition_ProcessingUnit [ name = "TestCoreDef" ]
structure [
name = "System"
module_ProcessingUnit [
name = "TestCore"
definition = _find(ProcessingUnitDefinition, "TestCoreDef")
]
]
]
osModel [
operatingSystem [ name = "TestOS"
taskScheduler [ name = "TestScheduler" ]
]
]
mappingModel [
taskAllocation [
task = _find(Task, "TestTask")
scheduler = _find(TaskScheduler, "TestScheduler")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "TestScheduler")
responsibility += _find(ProcessingUnit, "TestCore")
]
]
]
}
@Test
def void testTaskToSchedulerToCoreMapping() {
val model = createValidTestModel()
val validationResult = runExecutor(model)
val result = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
assertTrue(result.isEmpty)
}
@Test
def void testTaskToSchedulerToCoreMapping_UnmappedTasks() {
val model = createValidTestModel()
// add unmapped task
model.swModel.task [ name = "TestTask_left"]
val validationResult = runExecutor(model)
val result = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(result.contains("Unmapped task found: \"TestTask_left\""))
}
@Test
def void testTaskToSchedulerToCoreMapping_UnmappedScheduler() {
val model = createValidTestModel()
// add unmapped scheduler
model.osModel.operatingSystems.head.taskScheduler [ name = "TestScheduler_left"]
val validationResult = runExecutor(model)
val result = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(result.contains("Scheduler not responsible for any core: \"TestScheduler_left\""))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingSchedulerInTaskAlloc() {
val model = createValidTestModel()
// task allocation: remove reference to scheduler
model.mappingModel.taskAllocation.head.scheduler = null
val validationResult = runExecutor(model)
val result = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
assertTrue(result.contains("The required feature 'scheduler' of 'TaskAllocation' must be set"))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingTaskInTaskAlloc() {
val model = createValidTestModel()
// task allocation: remove reference to task
model.mappingModel.taskAllocation.head.task = null
val validationResult = runExecutor(model)
val errors = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
val warnings = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(errors.contains("The required feature 'task' of 'TaskAllocation' must be set"))
assertTrue(warnings.contains("Unmapped task found: \"TestTask\""))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingTaskAndSchedulerInTaskAlloc() {
val model = createValidTestModel()
// task allocation: remove references to scheduler and task
model.mappingModel.taskAllocation.head.scheduler = null
model.mappingModel.taskAllocation.head.task = null
val validationResult = runExecutor(model)
val errors = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
val warnings = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(errors.contains("The required feature 'scheduler' of 'TaskAllocation' must be set"))
assertTrue(errors.contains("The required feature 'task' of 'TaskAllocation' must be set"))
assertTrue(warnings.contains("Unmapped task found: \"TestTask\""))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingSchedulerInSchedulerAlloc() {
val model = createValidTestModel()
// scheduler allocation: remove references to scheduler
model.mappingModel.schedulerAllocation.head.scheduler = null
val validationResult = runExecutor(model)
val errors = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
val warnings = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(errors.contains("The required feature 'scheduler' of 'SchedulerAllocation' must be set"))
assertTrue(warnings.contains("Scheduler not responsible for any core: \"TestScheduler\""))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingCoreInSchedulerAlloc() {
val model = createValidTestModel()
// scheduler allocation: remove responsibilities
model.mappingModel.schedulerAllocation.head.responsibility.clear
val validationResult = runExecutor(model)
val result = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
assertTrue(result.contains("The feature 'responsibility' of 'SchedulerAllocation' with 0 values must have at least 1 values"))
}
@Test
def void testTaskToSchedulerToCoreMapping_MissingSchedulerAndCoreInSchedulerAlloc() {
val model = createValidTestModel()
// scheduler allocation: remove references to scheduler and responsibilities
model.mappingModel.schedulerAllocation.head.scheduler = null
model.mappingModel.schedulerAllocation.head.responsibility.clear
val validationResult = runExecutor(model)
val errors = validationResult.filter[it.severityLevel == Severity.ERROR].map[it.message].toList
val warnings = validationResult.filter[it.severityLevel == Severity.WARNING].map[it.message].toList
assertTrue(errors.contains("The required feature 'scheduler' of 'SchedulerAllocation' must be set"))
assertTrue(errors.contains("The feature 'responsibility' of 'SchedulerAllocation' with 0 values must have at least 1 values"))
assertTrue(warnings.contains("Scheduler not responsible for any core: \"TestScheduler\""))
}
@Test
def void testSchedulerAllocation_MultipleTopLevelSchedulerResponsibilities() {
val model = amalthea [
hardwareModel [
structure [
name = "System"
module_ProcessingUnit [ name = "core1" ]
module_ProcessingUnit [ name = "core2" ]
]
]
osModel [
operatingSystem [ name = "TestOS"
taskScheduler [ name = "scheduler_ok" ]
taskScheduler [ name = "child_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "scheduler_ok")
]
]
taskScheduler [ name = "scheduler_notOk" ]
interruptController [ name = "ic_ok" ]
interruptController [ name = "ic_notOk" ]
]
]
mappingModel [
schedulerAllocation [
scheduler = _find(TaskScheduler, "scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core1"), _find(ProcessingUnit, "core2")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "child_scheduler_ok")
responsibility += _find(ProcessingUnit, "core2")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "scheduler_notOk")
responsibility += _find(ProcessingUnit, "core2")
]
schedulerAllocation [
scheduler = _find(InterruptController, "ic_ok")
responsibility += #[_find(ProcessingUnit, "core1"), _find(ProcessingUnit, "core2")]
]
schedulerAllocation [
scheduler = _find(InterruptController, "ic_notOk")
responsibility += _find(ProcessingUnit, "core1")
]
]
]
val tlRespIssues = runExecutor(model).filter[it.validationID == "AM-Mapping-Scheduler-Allocation-Top-Level-Responsibility"]
assertTrue(tlRespIssues.size == 2)
val tlSchedResp = tlRespIssues.filter[(it.targetObject as SchedulerAllocation).scheduler instanceof TaskScheduler].head
val tlSchedName = (tlSchedResp.targetObject as SchedulerAllocation).scheduler.name
assertFalse(tlSchedName == "child_scheduler_ok")
assertTrue(tlSchedResp.message == "Processing Unit \"core2\" should have at most one top level scheduler that is responsible for it"
&& tlSchedName == "scheduler_notOk"
)
val iCResp = tlRespIssues.filter[(it.targetObject as SchedulerAllocation).scheduler instanceof InterruptController].head
val iCName = (iCResp.targetObject as SchedulerAllocation).scheduler.name
assertTrue(iCResp.message == "Processing Unit \"core1\" should have at most one interrupt controller that is responsible for it"
&& iCName == "ic_notOk"
)
}
@Test
def void testSchedulerAllocation_NestedResponsibilities_SimpleHierarchy() {
val model = amalthea [
hardwareModel [
structure [
name = "System"
module_ProcessingUnit [ name = "core1" ]
module_ProcessingUnit [ name = "core2" ]
module_ProcessingUnit [ name = "core3" ]
module_ProcessingUnit [ name = "core4" ]
]
]
osModel [
operatingSystem [ name = "TestOS"
taskScheduler [ name = "parent_scheduler_ok" ]
taskScheduler [ name = "child1_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "parent_scheduler_ok")
]
]
taskScheduler [ name = "child2_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "parent_scheduler_ok")
]
]
taskScheduler [ name = "child3_scheduler_notOk"
parentAssociation [
parent = _find(TaskScheduler, "parent_scheduler_ok")
]
]
]
]
mappingModel [
schedulerAllocation [
scheduler = _find(TaskScheduler, "parent_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core1"), _find(ProcessingUnit, "core2"), _find(ProcessingUnit, "core3")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "child1_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core1"), _find(ProcessingUnit, "core2")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "child2_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core2"), _find(ProcessingUnit, "core3")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "child3_scheduler_notOk")
responsibility += #[_find(ProcessingUnit, "core3"), _find(ProcessingUnit, "core4")]
]
]
]
val hierarchyIssues = runExecutor(model).filter[it.validationID == "AM-Mapping-Scheduler-Allocation-Hierarchy"]
assertTrue(hierarchyIssues.size == 1)
assertTrue(hierarchyIssues.head.message == "Scheduler Allocation for child Task Scheduler \"child3_scheduler_notOk\" "
+ "should only be responsible for a subset of processing units of its parent schedulers"
)
}
@Test
def void testSchedulerAllocation_NestedResponsibilities_DeeperHierarchy() {
val model = amalthea [
hardwareModel [
structure [
name = "System"
module_ProcessingUnit [ name = "core1" ]
module_ProcessingUnit [ name = "core2" ]
module_ProcessingUnit [ name = "core3" ]
module_ProcessingUnit [ name = "core4" ]
module_ProcessingUnit [ name = "core5" ]
module_ProcessingUnit [ name = "core6" ]
]
]
osModel [
operatingSystem [ name = "TestOS"
/*
* -- a1 -- a2
* / \ |
* b1 b2 b3
* / \ / | \ | \
* c1 c2 c3 c4 c5 c6 c7
* / \ ~~~~ | ~~~~
* d1 d2 d3
* ~~~~
*/
taskScheduler [ name = "a1_scheduler_ok" ]
taskScheduler [ name = "b1_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "a1_scheduler_ok")
]
]
taskScheduler [name = "c1_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "b1_scheduler_ok")
]
]
taskScheduler [name = "d1_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "c1_scheduler_ok")
]
]
taskScheduler [name = "d2_scheduler_notOk"
parentAssociation [
parent = _find(TaskScheduler, "c1_scheduler_ok")
]
]
taskScheduler [ name = "c2_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "b1_scheduler_ok")
]
]
taskScheduler [ name = "b2_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "a1_scheduler_ok")
]
]
taskScheduler [ name = "c3_scheduler_notOk"
parentAssociation [
parent = _find(TaskScheduler, "b2_scheduler_ok")
]
]
taskScheduler [ name = "c4_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "b2_scheduler_ok")
]
]
taskScheduler [name = "d3_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "c4_scheduler_ok")
]
]
taskScheduler [ name = "c5_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "b2_scheduler_ok")
]
]
taskScheduler [ name = "a2_scheduler_ok" ]
taskScheduler [ name = "b3_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "a2_scheduler_ok")
]
]
taskScheduler [ name = "c6_scheduler_notOk"
parentAssociation [
parent = _find(TaskScheduler, "b3_scheduler_ok")
]
]
taskScheduler [ name = "c7_scheduler_ok"
parentAssociation [
parent = _find(TaskScheduler, "b3_scheduler_ok")
]
]
]
]
mappingModel [
schedulerAllocation [
scheduler = _find(TaskScheduler, "a1_scheduler_ok")
responsibility += HardwareUtil.getModulesFromHWStructure(ProcessingUnit, _find(HwStructure, "System"))
responsibility -= _find(ProcessingUnit, "core6")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "b1_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core1"), _find(ProcessingUnit, "core2")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "c2_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core2"), _find(ProcessingUnit, "core3")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "c3_scheduler_notOk") // ancestors do not schedule core6
responsibility += #[_find(ProcessingUnit, "core4"), _find(ProcessingUnit, "core6")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "c5_scheduler_ok")
responsibility += #[_find(ProcessingUnit, "core4"), _find(ProcessingUnit, "core5")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "d1_scheduler_ok")
responsibility += _find(ProcessingUnit, "core3")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "d2_scheduler_notOk") // ancestors do not schedule core6
responsibility += _find(ProcessingUnit, "core6")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "a2_scheduler_ok")
responsibility += _find(ProcessingUnit, "core6")
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "c6_scheduler_notOk") // ancestors do not schedule core5
responsibility += #[_find(ProcessingUnit, "core5"), _find(ProcessingUnit, "core6")]
]
schedulerAllocation [
scheduler = _find(TaskScheduler, "c7_scheduler_ok")
responsibility += _find(ProcessingUnit, "core6")
]
]
]
val hierarchyIssues = runExecutor(model).filter[it.validationID == "AM-Mapping-Scheduler-Allocation-Hierarchy"].map[it.message].toList
assertTrue(hierarchyIssues.size == 3)
assertTrue(hierarchyIssues.contains("Scheduler Allocation for child Task Scheduler \"c3_scheduler_notOk\" "
+ "should only be responsible for a subset of processing units of its parent schedulers")
)
assertTrue(hierarchyIssues.contains("Scheduler Allocation for child Task Scheduler \"d2_scheduler_notOk\" "
+ "should only be responsible for a subset of processing units of its parent schedulers")
)
assertTrue(hierarchyIssues.contains("Scheduler Allocation for child Task Scheduler \"c6_scheduler_notOk\" "
+ "should only be responsible for a subset of processing units of its parent schedulers")
)
}
}