Skip to content

Commit

Permalink
Merge pull request #1663 from lf-lang/fed-target-conf
Browse files Browse the repository at this point in the history
Refactoring of part of the federated package
  • Loading branch information
lhstrh authored Mar 20, 2023
2 parents 26149d0 + 88823b1 commit ab3e0c5
Show file tree
Hide file tree
Showing 33 changed files with 806 additions and 674 deletions.
102 changes: 102 additions & 0 deletions org.lflang.tests/src/org/lflang/tests/compiler/TargetConfigTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.lflang.tests.compiler;

import com.google.inject.Inject;
import com.google.inject.Provider;
import java.nio.file.Files;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.xtext.generator.JavaIoFileSystemAccess;
import org.eclipse.xtext.testing.InjectWith;
import org.eclipse.xtext.testing.extensions.InjectionExtension;
import org.eclipse.xtext.testing.util.ParseHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.lflang.federated.generator.FedFileConfig;
import org.lflang.generator.GeneratorUtils;
import org.lflang.generator.LFGenerator;
import org.lflang.generator.LFGeneratorContext.Mode;
import org.lflang.generator.MainContext;
import org.lflang.lf.Model;
import org.lflang.tests.LFInjectorProvider;

@ExtendWith(InjectionExtension.class)
@InjectWith(LFInjectorProvider.class)

/**
* Tests for checking that target properties adequately translate into the target configuration.
*/
class TargetConfigTests {

@Inject
ParseHelper<Model> parser;

@Inject
LFGenerator generator;

@Inject
JavaIoFileSystemAccess fileAccess;

@Inject
Provider<ResourceSet> resourceSetProvider;

private void assertHasTargetProperty(Model model, String name) {
Assertions.assertNotNull(model);
Assertions.assertTrue(
model.getTarget().getConfig().getPairs().stream().anyMatch(
p -> p.getName().equals(name)
)
);
}

/**
* Check that tracing target property affects the target configuration.
* @throws Exception
*/
@Test
public void testParsing() throws Exception {
assertHasTargetProperty(parser.parse("""
target C {
tracing: true
}
"""), "tracing");
}

/**
* Check that when a federation has the "tracing" target property set, the generated federates
* will also have it set.
* @throws Exception
*/
@Test
public void testFederation() throws Exception {
fileAccess.setOutputPath("src-gen");

Model federation = parser.parse("""
target C {
tracing: true
}
reactor Foo {
}
federated reactor {
a = new Foo()
b = new Foo()
}
""", URI.createFileURI("tmp/src/Federation.lf"), resourceSetProvider.get());
assertHasTargetProperty(federation, "tracing");

var resource = federation.eResource();
var context = new MainContext(Mode.STANDALONE, resource, fileAccess, () -> false);

if (GeneratorUtils.isHostWindows()) return;

generator.doGenerate(resource, fileAccess, context);

String lfSrc = Files.readAllLines(
((FedFileConfig)context.getFileConfig()).getSrcPath().resolve("a.lf")
).stream().reduce("\n", String::concat);
Model federate = parser.parse(lfSrc);
assertHasTargetProperty(federate, "tracing");
}
}
90 changes: 85 additions & 5 deletions org.lflang/src/org/lflang/TargetConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;

import org.lflang.TargetProperty.BuildType;
Expand All @@ -38,7 +39,9 @@
import org.lflang.TargetProperty.LogLevel;
import org.lflang.TargetProperty.Platform;
import org.lflang.TargetProperty.SchedulerOption;
import org.lflang.TargetProperty.UnionType;
import org.lflang.generator.rust.RustTargetConfig;
import org.lflang.lf.KeyValuePair;
import org.lflang.lf.TargetDecl;

/**
Expand All @@ -50,12 +53,92 @@
*/
public class TargetConfig {

/**
* The target of this configuration (e.g., C, TypeScript, Python).
*/
public final Target target;

public TargetConfig(TargetDecl target) {
/**
* Create a new target configuration based on the given target declaration AST node only.
* @param target AST node of a target declaration.
*/
public TargetConfig(TargetDecl target) { // FIXME: eliminate this constructor if we can
this.target = Target.fromDecl(target);
}

/**
* Create a new target configuration based on the given commandline arguments and target
* declaration AST node.
* @param cliArgs Arguments passed on the commandline.
* @param target AST node of a target declaration.
* @param errorReporter An error reporter to report problems.
*/
public TargetConfig(
Properties cliArgs,
TargetDecl target,
ErrorReporter errorReporter
) {
this(target);
if (target.getConfig() != null) {
List<KeyValuePair> pairs = target.getConfig().getPairs();
TargetProperty.set(this, pairs != null ? pairs : List.of(), errorReporter);
}
if (cliArgs.containsKey("no-compile")) {
this.noCompile = true;
}
if (cliArgs.containsKey("docker")) {
var arg = cliArgs.getProperty("docker");
if (Boolean.parseBoolean(arg)) {
this.dockerOptions = new DockerOptions();
} else {
this.dockerOptions = null;
}
// FIXME: this is pretty ad-hoc and does not account for more complex overrides yet.
}
if (cliArgs.containsKey("build-type")) {
this.cmakeBuildType = (BuildType) UnionType.BUILD_TYPE_UNION.forName(cliArgs.getProperty("build-type"));
}
if (cliArgs.containsKey("logging")) {
this.logLevel = LogLevel.valueOf(cliArgs.getProperty("logging").toUpperCase());
}
if (cliArgs.containsKey("workers")) {
this.workers = Integer.parseInt(cliArgs.getProperty("workers"));
}
if (cliArgs.containsKey("threading")) {
this.threading = Boolean.parseBoolean(cliArgs.getProperty("threading"));
}
if (cliArgs.containsKey("target-compiler")) {
this.compiler = cliArgs.getProperty("target-compiler");
}
if (cliArgs.containsKey("tracing")) {
this.tracing = new TracingOptions();
}
if (cliArgs.containsKey("scheduler")) {
this.schedulerType = SchedulerOption.valueOf(
cliArgs.getProperty("scheduler")
);
this.setByUser.add(TargetProperty.SCHEDULER);
}
if (cliArgs.containsKey("target-flags")) {
this.compilerFlags.clear();
if (!cliArgs.getProperty("target-flags").isEmpty()) {
this.compilerFlags.addAll(List.of(
cliArgs.getProperty("target-flags").split(" ")
));
}
}
if (cliArgs.containsKey("runtime-version")) {
this.runtimeVersion = cliArgs.getProperty("runtime-version");
}
if (cliArgs.containsKey("external-runtime-path")) {
this.externalRuntimePath = cliArgs.getProperty("external-runtime-path");
}
if (cliArgs.containsKey(TargetProperty.KEEPALIVE.description)) {
this.keepalive = Boolean.parseBoolean(
cliArgs.getProperty(TargetProperty.KEEPALIVE.description));
}
}

/**
* Keep track of every target property that is explicitly set by the user.
*/
Expand Down Expand Up @@ -197,9 +280,6 @@ public TargetConfig(TargetDecl target) {
*
* This is now a wrapped class to account for overloaded definitions
* of defining platform (either a string or dictionary of values)
*
* @author Samuel Berkun
* @author Anirudh Rengarajan
*/
public PlatformOptions platformOptions = new PlatformOptions();

Expand Down Expand Up @@ -293,7 +373,7 @@ public static class ClockSyncOptions {
public int attenuation = 10;

/**
* Whether or not to collect statistics while performing clock synchronization.
* Whether to collect statistics while performing clock synchronization.
* This setting is only considered when clock synchronization has been activated.
* The default is true.
*/
Expand Down
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) {
* @param config The configuration object to update.
* @param properties AST node that holds all the target properties.
*/
public static void update(TargetConfig config, List<KeyValuePair> properties,ErrorReporter err) {
public static void update(TargetConfig config, List<KeyValuePair> properties, ErrorReporter err) {
properties.forEach(property -> {
TargetProperty p = forName(property.getName());
if (p != null) {
Expand Down
4 changes: 2 additions & 2 deletions org.lflang/src/org/lflang/ast/FormattingUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public static String render(EObject object, int lineLength) {
}

/** Return a function that renders AST nodes for the given target. */
public static Function<EObject, String> renderer(TargetDecl targetDecl) {
return object -> render(object, DEFAULT_LINE_LENGTH, Target.fromDecl(targetDecl), true);
public static Function<EObject, String> renderer(Target target) {
return object -> render(object, DEFAULT_LINE_LENGTH, target, true);
}

/**
Expand Down
33 changes: 13 additions & 20 deletions org.lflang/src/org/lflang/federated/extensions/CExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.lflang.federated.generator.FedConnectionInstance;
import org.lflang.federated.generator.FedFileConfig;
import org.lflang.federated.generator.FederateInstance;
import org.lflang.federated.launcher.RtiConfig;
import org.lflang.federated.serialization.FedROS2CPPSerialization;
import org.lflang.generator.CodeBuilder;
import org.lflang.generator.GeneratorBase;
Expand Down Expand Up @@ -83,18 +84,10 @@ public void initializeTargetConfig(
int numOfFederates, FederateInstance federate,
FedFileConfig fileConfig,
ErrorReporter errorReporter,
LinkedHashMap<String, Object> federationRTIProperties
RtiConfig rtiConfig
) throws IOException {
if(GeneratorUtils.isHostWindows()) {
errorReporter.reportError(
"Federated LF programs with a C target are currently not supported on Windows. " +
"Exiting code generation."
);
// Return to avoid compiler errors
return;
}

CExtensionUtils.handleCompileDefinitions(federate, numOfFederates, federationRTIProperties);
CExtensionUtils.handleCompileDefinitions(federate, numOfFederates, rtiConfig);

generateCMakeInclude(federate, fileConfig);

Expand Down Expand Up @@ -488,11 +481,11 @@ public String getNetworkBufferType() {
public String generatePreamble(
FederateInstance federate,
FedFileConfig fileConfig,
LinkedHashMap<String, Object> federationRTIProperties,
RtiConfig rtiConfig,
ErrorReporter errorReporter
) throws IOException {
// Put the C preamble in a `include/_federate.name + _preamble.h` file
String cPreamble = makePreamble(federate, fileConfig, federationRTIProperties, errorReporter);
String cPreamble = makePreamble(federate, fileConfig, rtiConfig, errorReporter);
String relPath = "include" + File.separator + "_" + federate.name + "_preamble.h";
Path fedPreamblePath = fileConfig.getSrcPath().resolve(relPath);
Files.createDirectories(fedPreamblePath.getParent());
Expand All @@ -509,7 +502,7 @@ public String generatePreamble(
protected String makePreamble(
FederateInstance federate,
FedFileConfig fileConfig,
LinkedHashMap<String, Object> federationRTIProperties,
RtiConfig rtiConfig,
ErrorReporter errorReporter) {

var code = new CodeBuilder();
Expand All @@ -532,7 +525,7 @@ protected String makePreamble(

code.pr(generateSerializationPreamble(federate, fileConfig));

code.pr(generateExecutablePreamble(federate, federationRTIProperties, errorReporter));
code.pr(generateExecutablePreamble(federate, rtiConfig, errorReporter));

code.pr(generateInitializeTriggers(federate, errorReporter));

Expand Down Expand Up @@ -582,12 +575,12 @@ private String generateInitializeTriggers(FederateInstance federate, ErrorReport
* Generate code for an executed preamble.
*
*/
private String generateExecutablePreamble(FederateInstance federate, LinkedHashMap<String, Object> federationRTIProperties, ErrorReporter errorReporter) {
private String generateExecutablePreamble(FederateInstance federate, RtiConfig rtiConfig, ErrorReporter errorReporter) {
CodeBuilder code = new CodeBuilder();

code.pr(generateCodeForPhysicalActions(federate, errorReporter));

code.pr(generateCodeToInitializeFederate(federate, federationRTIProperties));
code.pr(generateCodeToInitializeFederate(federate, rtiConfig));

code.pr(CExtensionUtils.allocateTriggersForFederate(federate));

Expand All @@ -600,10 +593,10 @@ void _lf_executable_preamble() {

/**
* Generate code to initialize the {@code federate}.
* @param federationRTIProperties Properties related to the RTI.
* @param rtiConfig
* @return The generated code
*/
private String generateCodeToInitializeFederate(FederateInstance federate, LinkedHashMap<String, Object> federationRTIProperties) {
private String generateCodeToInitializeFederate(FederateInstance federate, RtiConfig rtiConfig) {
CodeBuilder code = new CodeBuilder();
code.pr("// ***** Start initializing the federated execution. */");
code.pr(String.join("\n",
Expand Down Expand Up @@ -672,12 +665,12 @@ private String generateCodeToInitializeFederate(FederateInstance federate, Linke

code.pr(String.join("\n",
"// Connect to the RTI. This sets _fed.socket_TCP_RTI and _lf_rti_socket_UDP.",
"connect_to_rti("+addDoubleQuotes(federationRTIProperties.get("host").toString())+", "+ federationRTIProperties.get("port")+");"
"connect_to_rti("+addDoubleQuotes(rtiConfig.getHost())+", "+ rtiConfig.getPort()+");"
));

// Disable clock synchronization for the federate if it resides on the same host as the RTI,
// unless that is overridden with the clock-sync-options target property.
if (CExtensionUtils.clockSyncIsOn(federate, federationRTIProperties)) {
if (CExtensionUtils.clockSyncIsOn(federate, rtiConfig)) {
code.pr("synchronize_initial_physical_clock_with_rti(_fed.socket_TCP_RTI);");
}

Expand Down
Loading

0 comments on commit ab3e0c5

Please sign in to comment.