[PATCH 07/22] MICROROS, EE3: Fixed generation for ticks - Added new file for tick generation (microros/generators/MicroRosTicksUtilsGenerator.xtend) - Added extern "C" for C-code - Added debug printf
diff --git a/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.xtend b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.xtend new file mode 100644 index 0000000..2a67ab0 --- /dev/null +++ b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.xtend
@@ -0,0 +1,158 @@ +/** + ******************************************************************************** + * Copyright (c) 2022-2023 Robert Bosch GmbH. + * + * 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.slg.microros.generators + +import java.util.List +import org.eclipse.app4mc.amalthea.model.AmaltheaPackage +import org.eclipse.app4mc.slg.config.ConfigModel +import org.eclipse.app4mc.slg.config.TickType +import org.eclipse.emf.ecore.EClass + +class MicroRosTicksUtilsGenerator { + + public static val String LIB_NAME = "TICKS_UTILS"; + + // Suppress default constructor + private new() { + throw new IllegalStateException("Utility class"); + } + + static def String toCMake(List<String> srcFiles) + ''' + # «LIB_NAME» ################################################################ + #### + add_library(«LIB_NAME» STATIC + «FOR srcFile : srcFiles» + ${CMAKE_CURRENT_LIST_DIR}/_src/«srcFile» + «ENDFOR» + ) + + target_include_directories(«LIB_NAME» + PUBLIC ${CMAKE_CURRENT_LIST_DIR}/_inc/ + ) + ''' + + // ----- generate ticks ----- + static def String generateTicksDeclaration(EClass eClass) { + switch eClass { + case AmaltheaPackage.eINSTANCE.discreteValueConstant: ''' + void «execCall(eClass, "int ticks")»; + + ''' + case AmaltheaPackage.eINSTANCE.discreteValueStatistics: ''' + void «execCall(eClass, "double average, int lowerBound, int upperBound")»; + + ''' + default: { + "" + } + } + } + + static def String generateTicks(EClass eClass) { + switch eClass { + case AmaltheaPackage.eINSTANCE.discreteValueConstant: ''' + void «execCall(eClass, "int ticks")» { + burnTicks(ticks); + } + + ''' + case AmaltheaPackage.eINSTANCE.discreteValueStatistics: ''' + void «execCall(eClass, "double average, int lowerBound, int upperBound")» { + burnTicksStatistics(average, lowerBound, upperBound); + } + + ''' + default: { + "" + } + } + } + + static def String execCall(EClass eClass, String params) '''executeTicks_«eClass.name»(«params»)''' + + + // ----- burn ticks ----- + + static def String burnTicksDeclaration() ''' + void burnTicks(int ticks); + + ''' + + static def String burnTicks(String burnTicksBody) + ''' + void burnTicks(int ticks) { + debug_printf(" Burn %d ticks\n", ticks); + «burnTicksBody» + } + + ''' + + // ----- burn ticks statistics ----- + + static def String burnTicksStatisticsDeclaration() ''' + void burnTicksStatistics(double average, int lowerBound, int upperBound); + + ''' + + static def String burnTicksStatistics(ConfigModel configModel) + ''' + void burnTicksStatistics(double average, int lowerBound, int upperBound) { + debug_printf(" Burn ticks (average value=%d)\n", (int)average); + burnTicks(«chooseTicks(configModel)»); + } + + ''' + + // select statistics parameter according to configuration model + // TODO: choose final names of configuration parameters + private static def chooseTicks(ConfigModel configModel) { + switch configModel.defaultTickType { + case TickType.MINIMUM: "lowerBound" + case TickType.MAXIMUM: "upperBound" + case TickType.AVERAGE: "(int)average" + default: "(int)average" + } + } + + // ----- Default implementations ----- + + static def String burnTicksDefault() + ''' + // default implementation of tick burning + int numLoops = ticks / 400; + # if defined (__x86_64__) + for (int i = 0; i < numLoops; i++) { + «FOR i : 1..400» + __asm volatile("nop"); + «ENDFOR» + } + # elif defined (__x86_32__) + for (int i = 0; i < numLoops; i++) { + «FOR i : 1..400» + __asm volatile("mov r0, r0"); + «ENDFOR» + } + # elif defined (__aarch64__) + for (int i = 0; i < numLoops; i++) { + «FOR i : 1..400» + __asm volatile("mov x0, x0"); + «ENDFOR» + } + # endif + ''' + +}
diff --git a/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/transformers/MicroRosTicksUtilsTransformer.java b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/transformers/MicroRosTicksUtilsTransformer.java index b007044..9fe73e4 100644 --- a/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/transformers/MicroRosTicksUtilsTransformer.java +++ b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/src/org/eclipse/app4mc/slg/microros/transformers/MicroRosTicksUtilsTransformer.java
@@ -1,6 +1,6 @@ /** ******************************************************************************** - * Copyright (c) 2022 Robert Bosch GmbH. + * Copyright (c) 2022-2023 Robert Bosch GmbH. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -24,12 +24,14 @@ import java.util.Map; import org.eclipse.app4mc.amalthea.model.IDiscreteValueDeviation; +import org.eclipse.app4mc.amalthea.model.Tag; import org.eclipse.app4mc.slg.commons.m2t.CustomObjectsStore; -import org.eclipse.app4mc.slg.commons.m2t.generators.TicksUtilsGenerator; import org.eclipse.app4mc.slg.commons.m2t.transformers.SLGTranslationUnit; import org.eclipse.app4mc.slg.config.ConfigModel; import org.eclipse.app4mc.slg.config.PlatformArchitecture; +import org.eclipse.app4mc.slg.microros.generators.MicroRosTicksUtilsGenerator; import org.eclipse.app4mc.slg.ros2.transformers.RosBaseTransformer; +import org.eclipse.app4mc.slg.ros2.transformers.utils.RosModelUtils; import org.eclipse.app4mc.transformation.util.OutputBuffer; import org.eclipse.emf.ecore.EClass; @@ -42,11 +44,11 @@ @Inject private OutputBuffer outputBuffer; @Inject private CustomObjectsStore customObjsStore; - public SLGTranslationUnit transform(final IDiscreteValueDeviation value) { + public SLGTranslationUnit transform(final IDiscreteValueDeviation value, final Tag tag) { if (value == null) return new SLGTranslationUnit("UNSPECIFIED TICKS"); - return transformClass(value.eClass()); // hash according to class not instance + return transformClass(value.eClass(), tag); // hash according to class not instance } // ---------- generic part "def create new transform(...)" ---------- @@ -58,15 +60,16 @@ return this.transformCache; } - public SLGTranslationUnit transformClass(final EClass eClass) { - final List<Object> key = new ArrayList<>(Arrays.asList(eClass)); + public SLGTranslationUnit transformClass(final EClass eClass, final Tag tag) { + final String target = RosModelUtils.getROSTargetName(tag); + final List<Object> key = new ArrayList<>(Arrays.asList(eClass, target)); final SLGTranslationUnit tu; synchronized (transformCache) { if (transformCache.containsKey(key)) { return transformCache.get(key); } - tu = createTranslationUnit(eClass); + tu = createTranslationUnit(eClass, target); transformCache.put(key, tu); } @@ -79,11 +82,11 @@ // --------------------------------------------------- - protected SLGTranslationUnit createTranslationUnit(final EClass eClass) { + protected SLGTranslationUnit createTranslationUnit(final EClass eClass, final String target) { if (eClass == null) { return new SLGTranslationUnit("UNSPECIFIED TICKS"); } else { - String basePath = "MICROROS_SLG/synthetic_gen"; + String basePath = target + "/synthetic_gen"; String moduleName = "ticksUtils"; String call = "burnTicks(<params>)"; // unused return new SLGTranslationUnit(basePath, moduleName, call); @@ -97,17 +100,24 @@ protected void genFiles(SLGTranslationUnit tu, final EClass eClass) { if (isIncFileEmpty(tu)) { incAppend(tu, "#pragma once \n"); + incAppend(tu, "\n#ifdef __cplusplus \n extern \"C\" \n {\n#endif\n"); toH(tu); + incAppend(tu, MicroRosTicksUtilsGenerator.generateTicksDeclaration(eClass)); + incAppend(tu, "#ifdef __cplusplus \n }\n#endif\n\n"); } + if (isSrcFileEmpty(tu)) { + srcAppend(tu, "#include \"" + getIncFile(tu) + "\"\n"); + srcAppend(tu, "#include \"output_console.h\"\n"); + + srcAppend(tu, "\n#ifdef __cplusplus \n extern \"C\" \n {\n#endif\n"); toCPP(tu); + srcAppend(tu, MicroRosTicksUtilsGenerator.generateTicks(eClass)); + srcAppend(tu, "#ifdef __cplusplus \n }\n#endif\n\n"); } - srcAppend(tu, TicksUtilsGenerator.generateTicks(eClass)); - incAppend(tu, TicksUtilsGenerator.generateTicksDeclaration(eClass)); } protected void toCPP(SLGTranslationUnit tu) { - srcAppend(tu, "#include \"" + getIncFile(tu) + "\"\n"); final ConfigModel configModel = customObjsStore.<ConfigModel>getInstance(ConfigModel.class); @@ -120,23 +130,23 @@ final String ticksCodeSnippet = configModel.getCustomTickImpl().getValue(); final boolean ticksCodeEnabled = configModel.getCustomTickImpl().isEnable(); - final String burnTicksBody = ticksCodeEnabled ? ticksCodeSnippet : TicksUtilsGenerator.burnTicksDefault(); + final String burnTicksBody = ticksCodeEnabled ? ticksCodeSnippet : MicroRosTicksUtilsGenerator.burnTicksDefault(); - srcAppend(tu, TicksUtilsGenerator.burnTicks(burnTicksBody)); - srcAppend(tu, TicksUtilsGenerator.burnTicksStatistics(configModel)); + srcAppend(tu, MicroRosTicksUtilsGenerator.burnTicks(burnTicksBody)); + srcAppend(tu, MicroRosTicksUtilsGenerator.burnTicksStatistics(configModel)); } protected void toH(SLGTranslationUnit tu) { - incAppend(tu, TicksUtilsGenerator.burnTicksDeclaration()); - incAppend(tu, TicksUtilsGenerator.burnTicksStatisticsDeclaration()); + incAppend(tu, MicroRosTicksUtilsGenerator.burnTicksDeclaration()); + incAppend(tu, MicroRosTicksUtilsGenerator.burnTicksStatisticsDeclaration()); } - public void createCMake() { + public void createCMake(String target) { // Building rule: basePath + moduleName + "CMakeLists.txt" - String makeFilePath = "MICROROS_SLG/synthetic_gen/ticksUtils/CMakeLists.txt"; - outputBuffer.appendTo(OTHER_TYPE, makeFilePath, TicksUtilsGenerator.toCMake(getSrcFiles())); + String makeFilePath = target + "/synthetic_gen/ticksUtils/CMakeLists.txt"; + outputBuffer.appendTo(OTHER_TYPE, makeFilePath, MicroRosTicksUtilsGenerator.toCMake(getSrcFiles())); } }
diff --git a/load_generator/plugins/org.eclipse.app4mc.slg.ros2/xtend-gen/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.java b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/xtend-gen/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.java new file mode 100644 index 0000000..e04e4ba --- /dev/null +++ b/load_generator/plugins/org.eclipse.app4mc.slg.ros2/xtend-gen/org/eclipse/app4mc/slg/microros/generators/MicroRosTicksUtilsGenerator.java
@@ -0,0 +1,296 @@ +/** + * Copyright (c) 2022-2023 Robert Bosch GmbH. + * + * 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.slg.microros.generators; + +import com.google.common.base.Objects; +import java.util.List; +import org.eclipse.app4mc.amalthea.model.AmaltheaPackage; +import org.eclipse.app4mc.slg.config.ConfigModel; +import org.eclipse.app4mc.slg.config.TickType; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.xbase.lib.IntegerRange; + +@SuppressWarnings("all") +public class MicroRosTicksUtilsGenerator { + public static final String LIB_NAME = "TICKS_UTILS"; + + private MicroRosTicksUtilsGenerator() { + throw new IllegalStateException("Utility class"); + } + + public static String toCMake(final List<String> srcFiles) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("\t"); + _builder.append("# "); + _builder.append(MicroRosTicksUtilsGenerator.LIB_NAME, "\t"); + _builder.append(" ################################################################"); + _builder.newLineIfNotEmpty(); + _builder.append("\t"); + _builder.append("####"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("add_library("); + _builder.append(MicroRosTicksUtilsGenerator.LIB_NAME, "\t"); + _builder.append(" STATIC"); + _builder.newLineIfNotEmpty(); + { + for(final String srcFile : srcFiles) { + _builder.append("${CMAKE_CURRENT_LIST_DIR}/_src/"); + _builder.append(srcFile); + _builder.newLineIfNotEmpty(); + } + } + _builder.append(")"); + _builder.newLine(); + _builder.newLine(); + _builder.append("\t"); + _builder.append("target_include_directories("); + _builder.append(MicroRosTicksUtilsGenerator.LIB_NAME, "\t"); + _builder.newLineIfNotEmpty(); + _builder.append("\t "); + _builder.append("PUBLIC ${CMAKE_CURRENT_LIST_DIR}/_inc/"); + _builder.newLine(); + _builder.append("\t"); + _builder.append(")\t"); + _builder.newLine(); + return _builder.toString(); + } + + public static String generateTicksDeclaration(final EClass eClass) { + String _switchResult = null; + boolean _matched = false; + EClass _discreteValueConstant = AmaltheaPackage.eINSTANCE.getDiscreteValueConstant(); + if (Objects.equal(eClass, _discreteValueConstant)) { + _matched=true; + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void "); + String _execCall = MicroRosTicksUtilsGenerator.execCall(eClass, "int ticks"); + _builder.append(_execCall); + _builder.append(";"); + _builder.newLineIfNotEmpty(); + _builder.newLine(); + _switchResult = _builder.toString(); + } + if (!_matched) { + EClass _discreteValueStatistics = AmaltheaPackage.eINSTANCE.getDiscreteValueStatistics(); + if (Objects.equal(eClass, _discreteValueStatistics)) { + _matched=true; + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("void "); + String _execCall_1 = MicroRosTicksUtilsGenerator.execCall(eClass, "double average, int lowerBound, int upperBound"); + _builder_1.append(_execCall_1); + _builder_1.append(";"); + _builder_1.newLineIfNotEmpty(); + _builder_1.newLine(); + _switchResult = _builder_1.toString(); + } + } + if (!_matched) { + _switchResult = ""; + } + return _switchResult; + } + + public static String generateTicks(final EClass eClass) { + String _switchResult = null; + boolean _matched = false; + EClass _discreteValueConstant = AmaltheaPackage.eINSTANCE.getDiscreteValueConstant(); + if (Objects.equal(eClass, _discreteValueConstant)) { + _matched=true; + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void "); + String _execCall = MicroRosTicksUtilsGenerator.execCall(eClass, "int ticks"); + _builder.append(_execCall); + _builder.append(" {"); + _builder.newLineIfNotEmpty(); + _builder.append("\t"); + _builder.append("burnTicks(ticks);"); + _builder.newLine(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + _switchResult = _builder.toString(); + } + if (!_matched) { + EClass _discreteValueStatistics = AmaltheaPackage.eINSTANCE.getDiscreteValueStatistics(); + if (Objects.equal(eClass, _discreteValueStatistics)) { + _matched=true; + StringConcatenation _builder_1 = new StringConcatenation(); + _builder_1.append("void "); + String _execCall_1 = MicroRosTicksUtilsGenerator.execCall(eClass, "double average, int lowerBound, int upperBound"); + _builder_1.append(_execCall_1); + _builder_1.append(" {"); + _builder_1.newLineIfNotEmpty(); + _builder_1.append("\t"); + _builder_1.append("burnTicksStatistics(average, lowerBound, upperBound);"); + _builder_1.newLine(); + _builder_1.append("}"); + _builder_1.newLine(); + _builder_1.newLine(); + _switchResult = _builder_1.toString(); + } + } + if (!_matched) { + _switchResult = ""; + } + return _switchResult; + } + + public static String execCall(final EClass eClass, final String params) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("executeTicks_"); + String _name = eClass.getName(); + _builder.append(_name); + _builder.append("("); + _builder.append(params); + _builder.append(")"); + return _builder.toString(); + } + + public static String burnTicksDeclaration() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void burnTicks(int ticks);"); + _builder.newLine(); + _builder.newLine(); + return _builder.toString(); + } + + public static String burnTicks(final String burnTicksBody) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void burnTicks(int ticks) {"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("debug_printf(\" Burn %d ticks\\n\", ticks);"); + _builder.newLine(); + _builder.append("\t"); + _builder.append(burnTicksBody, "\t"); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + return _builder.toString(); + } + + public static String burnTicksStatisticsDeclaration() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void burnTicksStatistics(double average, int lowerBound, int upperBound);"); + _builder.newLine(); + _builder.newLine(); + return _builder.toString(); + } + + public static String burnTicksStatistics(final ConfigModel configModel) { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("void burnTicksStatistics(double average, int lowerBound, int upperBound) {"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("debug_printf(\" Burn ticks (average value=%d)\\n\", (int)average);"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("burnTicks("); + String _chooseTicks = MicroRosTicksUtilsGenerator.chooseTicks(configModel); + _builder.append(_chooseTicks, "\t"); + _builder.append(");"); + _builder.newLineIfNotEmpty(); + _builder.append("}"); + _builder.newLine(); + _builder.newLine(); + return _builder.toString(); + } + + private static String chooseTicks(final ConfigModel configModel) { + String _switchResult = null; + TickType _defaultTickType = configModel.getDefaultTickType(); + if (_defaultTickType != null) { + switch (_defaultTickType) { + case MINIMUM: + _switchResult = "lowerBound"; + break; + case MAXIMUM: + _switchResult = "upperBound"; + break; + case AVERAGE: + _switchResult = "(int)average"; + break; + default: + _switchResult = "(int)average"; + break; + } + } else { + _switchResult = "(int)average"; + } + return _switchResult; + } + + public static String burnTicksDefault() { + StringConcatenation _builder = new StringConcatenation(); + _builder.append("\t"); + _builder.append("// default implementation of tick burning"); + _builder.newLine(); + _builder.append("\t"); + _builder.append("int numLoops = ticks / 400; "); + _builder.newLine(); + _builder.append("#\tif defined (__x86_64__)"); + _builder.newLine(); + _builder.append(" \t"); + _builder.append("for (int i = 0; i < numLoops; i++) {"); + _builder.newLine(); + { + IntegerRange _upTo = new IntegerRange(1, 400); + for(final Integer i : _upTo) { + _builder.append(" \t\t"); + _builder.append("__asm volatile(\"nop\");"); + _builder.newLine(); + } + } + _builder.append(" \t\t"); + _builder.append("}"); + _builder.newLine(); + _builder.append("#\telif defined (__x86_32__) \t\t"); + _builder.newLine(); + _builder.append(" \t\t"); + _builder.append("for (int i = 0; i < numLoops; i++) {"); + _builder.newLine(); + { + IntegerRange _upTo_1 = new IntegerRange(1, 400); + for(final Integer i_1 : _upTo_1) { + _builder.append(" \t\t\t \t"); + _builder.append("__asm volatile(\"mov r0, r0\");"); + _builder.newLine(); + } + } + _builder.append(" \t\t\t\t"); + _builder.append("}"); + _builder.newLine(); + _builder.append("#\telif defined (__aarch64__) \t\t"); + _builder.newLine(); + _builder.append(" \t"); + _builder.append("for (int i = 0; i < numLoops; i++) {"); + _builder.newLine(); + { + IntegerRange _upTo_2 = new IntegerRange(1, 400); + for(final Integer i_2 : _upTo_2) { + _builder.append(" \t"); + _builder.append("__asm volatile(\"mov x0, x0\");"); + _builder.newLine(); + } + } + _builder.append("\t"); + _builder.append("}"); + _builder.newLine(); + _builder.append("#\tendif"); + _builder.newLine(); + return _builder.toString(); + } +}