Skip to content

Commit

Permalink
Support C federated tests with Rust RTI
Browse files Browse the repository at this point in the history
  • Loading branch information
chanijjani committed Feb 11, 2024
1 parent 2f0d82a commit b760e79
Show file tree
Hide file tree
Showing 12 changed files with 660 additions and 83 deletions.
28 changes: 0 additions & 28 deletions .github/workflows/all-misc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,3 @@ concurrency:
jobs:
check-diff:
uses: ./.github/workflows/check-diff.yml

# Test the Gradle build.
building:
needs: check-diff
uses: ./.github/workflows/build.yml
with:
all-platforms: ${{ !github.event.pull_request.draft }}
if: ${{ needs.check-diff.outputs.run_build == 'true' }}

# Run tests for the standalone compiler.
cli:
if: ${{ needs.check-diff.outputs.run_misc == 'true' }}
needs: check-diff
uses: ./.github/workflows/cli-tests.yml
with:
all-platforms: ${{ !github.event.pull_request.draft }}

# Run language server tests.
lsp:
if: ${{ needs.check-diff.outputs.run_misc == 'true' }}
needs: check-diff
uses: ./.github/workflows/lsp-tests.yml
with:
all-platforms: ${{ !github.event.pull_request.draft }}

check-labels:
uses: ./.github/workflows/check-labels.yml
if: ${{ github.event_name == 'pull_request' }}
25 changes: 0 additions & 25 deletions .github/workflows/all-targets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,3 @@ jobs:
uses: ./.github/workflows/only-c.yml
needs: check-diff
if: ${{ needs.check-diff.outputs.run_c == 'true' }}

cpp:
uses: ./.github/workflows/only-cpp.yml
needs: check-diff
if: ${{ needs.check-diff.outputs.run_cpp == 'true' }}

py:
uses: ./.github/workflows/only-py.yml
needs: check-diff
if: ${{ needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_c == 'true' }}

rs:
uses: ./.github/workflows/only-rs.yml
needs: check-diff
if: ${{ needs.check-diff.outputs.run_rs == 'true' }}

ts:
uses: ./.github/workflows/only-ts.yml
needs: check-diff
if: ${{ needs.check-diff.outputs.run_ts == 'true' }}

serialization:
if: ${{ needs.check-diff.outputs.run_c == 'true' || needs.check-diff.outputs.run_py == 'true' || needs.check-diff.outputs.run_ts == 'true' }}
needs: check-diff
uses: ./.github/workflows/serialization-tests.yml
48 changes: 48 additions & 0 deletions .github/workflows/c-tests-with-rust-rti.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: C tests

on:
workflow_call:
inputs:
compiler-ref:
required: false
type: string
runtime-ref:
required: false
type: string
use-cpp:
required: false
type: boolean
default: false
scheduler:
required: false
type: string
all-platforms:
required: false
default: true
type: boolean

jobs:
regular-tests:
strategy:
matrix:
platform: ${{ (inputs.all-platforms && fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]')) || fromJSON('["ubuntu-latest"]') }}
runs-on: ${{ matrix.platform }}
timeout-minutes: 120
steps:
- name: Check out lingua-franca repository
uses: actions/checkout@v3
with:
repository: chanijjani/lingua-franca
submodules: true
ref: ${{ inputs.compiler-ref }}
fetch-depth: 0
- name: Prepare build environment
uses: ./.github/actions/prepare-build-env
- name: Perform tests for C target with default scheduler
run: ./gradlew targetTest -Ptarget=C
if: ${{ !inputs.use-cpp && !inputs.scheduler }}
- name: Perform tests for C target with specified scheduler (no LSP tests)
run: |
echo "Specified scheduler: ${{ inputs.scheduler }}"
./gradlew targetTest -Ptarget=C -Dscheduler=${{ inputs.scheduler }}
if: ${{ !inputs.use-cpp && inputs.scheduler }}
31 changes: 2 additions & 29 deletions .github/workflows/only-c.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,8 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
# Run the C integration tests.
# Run the C integration tests with Rust RTI.
default:
uses: ./.github/workflows/c-tests.yml
uses: ./.github/workflows/c-tests-with-rust-rti.yml
with:
all-platforms: ${{ !github.event.pull_request.draft }}

# Run the C benchmark tests.
benchmarking:
uses: lf-lang/benchmarks-lingua-franca/.github/workflows/benchmark-tests.yml@main
with:
target: "C"

# Run the C Arduino integration tests.
arduino:
uses: ./.github/workflows/c-arduino-tests.yml
with:
all-platforms: ${{ !github.event.pull_request.draft }}

# Run the C Zephyr integration tests.
zephyr:
uses: ./.github/workflows/c-zephyr-tests.yml

# Run the CCpp integration tests.
ccpp:
uses: ./.github/workflows/c-tests.yml
with:
use-cpp: true
all-platforms: ${{ !github.event.pull_request.draft }}

# Run the Uclid-based LF Verifier benchmarks.
verifier:
uses: ./.github/workflows/c-verifier-tests.yml
14 changes: 14 additions & 0 deletions core/src/integrationTest/java/org/lflang/tests/RuntimeTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.lflang.tests;

import java.nio.file.Path;
import java.util.EnumSet;
import java.util.List;
import org.junit.jupiter.api.Assumptions;
Expand Down Expand Up @@ -142,6 +143,19 @@ public void runFederatedTests() {
false);
}

@Test
public void runFederatedTestsWithRustRti(Path rustRtiProjectPath) {
Assumptions.assumeTrue(supportsFederatedExecution(), Message.NO_FEDERATION_SUPPORT);
runTestsForTargetsWithRustRti(
Message.DESC_FEDERATED,
TestCategory.FEDERATED::equals,
Transformers::noChanges,
Configurators::noChanges,
TestLevel.EXECUTION,
false,
rustRtiProjectPath);
}

/** Run the tests for modal reactors. */
@Test
public void runModalTests() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*************
* Copyright (c) 2019, The University of California at Berkeley.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***************/
package org.lflang.tests.runtime;

import java.nio.file.Path;

import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.lflang.target.Target;
import org.lflang.tests.RuntimeTest;

/**
* Collection of tests for the C target.
*
* <p>Tests that are implemented in the base class are still overridden so that each test can be
* easily invoked individually from IDEs with JUnit support like Eclipse and IntelliJ. This is
* typically done by right-clicking on the name of the test method and then clicking "Run".*
*
* @author Marten Lohstroh
* @author Chanhee Lee
*/
public class RustRtiCTest extends RuntimeTest {

public RustRtiCTest() {
super(Target.C);
}

@Override
protected boolean supportsSingleThreadedExecution() {
return true;
}

@Override
protected boolean supportsFederatedExecution() {
return true;
}

@Override
protected boolean supportsDockerOption() {
return true;
}

@Test
@Override
public void runBasicTests() {
super.runBasicTests();
}

@Test
@Override
public void runGenericsTests() {
super.runGenericsTests();
}

@Test
@Override
public void runTargetSpecificTests() {
Assumptions.assumeFalse(isWindows(), Message.NO_WINDOWS_SUPPORT);
super.runTargetSpecificTests();
}

@Test
@Override
public void runMultiportTests() {
super.runMultiportTests();
}

@Test
@Override
public void runWithThreadingOff() {
super.runWithThreadingOff();
}

@Test
public void runFederatedTests(Path rustRtiProjectPath) {
Assumptions.assumeFalse(isWindows(), Message.NO_WINDOWS_SUPPORT);
super.runFederatedTestsWithRustRti(rustRtiProjectPath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.lflang.ast.ASTUtils;
import org.lflang.federated.launcher.FedLauncherGenerator;
import org.lflang.federated.launcher.RtiConfig;
import org.lflang.federated.launcher.RustRtiConfig;
import org.lflang.generator.CodeMap;
import org.lflang.generator.GeneratorArguments;
import org.lflang.generator.GeneratorResult.Status;
Expand Down Expand Up @@ -201,6 +202,96 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws
return false;
}

/**
* Produce LF code for each federate in a separate file, then invoke a target-specific code
* generator for each of those files.
*
* @param resource The resource that has the federated main reactor in it
* @param context The context in which to carry out the code generation.
* @return False if no errors have occurred, true otherwise.
*/
public boolean doGenerateForRustRTI(Resource resource, LFGeneratorContext context, Path rustRtiProjectPath) throws IOException {
if (!federatedExecutionIsSupported(resource)) return true;
cleanIfNeeded(context);

// In a federated execution, we need keepalive to be true,
// otherwise a federate could exit simply because it hasn't received
// any messages.
KeepaliveProperty.INSTANCE.override(targetConfig, true);

// Process command-line arguments
processCLIArguments(context);

// Find the federated reactor
Reactor federation = FedASTUtils.findFederatedReactor(resource);

// Make sure the RTI host is set correctly.
setRTIHost(federation);

// Create the FederateInstance objects.
ReactorInstance main = createFederateInstances(federation, context);

// Insert reactors that split multiports into many ports.
insertIndexers(main, resource);

// Clear banks so that each bank member becomes a single federate.
for (Instantiation instantiation : ASTUtils.allInstantiations(federation)) {
instantiation.setWidthSpec(null);
instantiation.setWidthSpec(null);
}

// Find all the connections between federates.
// For each connection between federates, replace it in the
// AST with an action (which inherits the delay) and three reactions.
// The action will be physical for physical connections and logical
// for logical connections.
replaceFederateConnectionsWithProxies(federation, main, resource);

FedEmitter fedEmitter =
new FedEmitter(
fileConfig,
ASTUtils.toDefinition(mainDef.getReactorClass()),
messageReporter,
rtiConfig);

// Generate LF code for each federate.
Map<Path, CodeMap> lf2lfCodeMapMap = new HashMap<>();
for (FederateInstance federate : federates) {
lf2lfCodeMapMap.putAll(fedEmitter.generateFederate(context, federate, federates.size()));
}

// Do not invoke target code generators if --no-compile flag is used.
if (context.getTargetConfig().get(NoCompileProperty.INSTANCE)) {
context.finish(Status.GENERATED, lf2lfCodeMapMap);
return false;
}

// If the RTI is to be built locally, set up a build environment for it.
prepareRtiBuildEnvironment(context);

Map<Path, CodeMap> codeMapMap =
compileFederates(
context,
lf2lfCodeMapMap,
subContexts -> {
createDockerFiles(context, subContexts);
generateLaunchScriptForRustRti(rustRtiProjectPath);
// If an error has occurred during codegen of any federate, report it.
subContexts.forEach(
c -> {
if (c.getErrorReporter().getErrorsOccurred()) {
context
.getErrorReporter()
.at(c.getFileConfig().srcFile)
.error("Failure during code generation of " + c.getFileConfig().srcFile);
}
});
});

context.finish(Status.COMPILED, codeMapMap);
return false;
}

/**
* Prepare a build environment for the rti alongside the generated sources of the federates.
*
Expand Down Expand Up @@ -229,6 +320,11 @@ private void generateLaunchScript() {
.doGenerate(federates, rtiConfig);
}

private void generateLaunchScriptForRustRti(Path rustRtiProjectPath) {
new FedLauncherGenerator(this.targetConfig, this.fileConfig, this.messageReporter)
.doGenerateForRustRTI(federates, new RustRtiConfig(rustRtiProjectPath));
}

/**
* Generate a Dockerfile for each federate and a docker-compose.yml for the federation.
*
Expand Down
Loading

0 comments on commit b760e79

Please sign in to comment.