Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enclave connections and enclave coordination in the C++ target #1665

Merged
merged 45 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ef489d3
generate a wrapper reactor for enclave
cmnrd Feb 28, 2023
d4abdfc
Merge branch 'cpp-no-keepalive' into enclave-connections
cmnrd Mar 9, 2023
7764cfe
Merge branch 'fix-lfc' into enclave-connections
cmnrd Mar 9, 2023
3eeaf50
use a struct instead of a reactor to wrap enclaves
cmnrd Mar 9, 2023
619a766
first support for simple enclave communication
cmnrd Mar 9, 2023
b1d6dca
add test case
cmnrd Mar 9, 2023
3e45d41
Merge branch 'master' into enclave-connections
cmnrd Mar 14, 2023
b7f2d00
update reactor-cpp
cmnrd Mar 14, 2023
ae3f4bd
Merge branch 'master' into enclave-connections
cmnrd Mar 17, 2023
b8cadb8
Merge branch 'clem.new-equals-initializers' into enclave-connections
cmnrd Mar 18, 2023
07adeac
add simple enclave communication test
cmnrd Mar 18, 2023
9aaa80e
add test combining simple enclave communication with other events
cmnrd Mar 18, 2023
36fc361
updater reactor-cpp
cmnrd Mar 18, 2023
46db052
code generation for delayed and physical enclave connections
cmnrd Mar 18, 2023
06f36fd
add tests for physical and delayed enclave connections
cmnrd Mar 18, 2023
3fb05f5
first (incomplete) implementation of enclave multiport connections
cmnrd Mar 18, 2023
d5f90f2
update reactor-cpp
cmnrd Mar 18, 2023
6612910
add various multiport tests
cmnrd Mar 18, 2023
bd27e1f
formatting
cmnrd Mar 18, 2023
9c114c3
fix NPE
cmnrd Mar 20, 2023
85a21ef
disable keepalive warning in C++
cmnrd Mar 21, 2023
e17852d
update reactor-cpp and add new tests
cmnrd Mar 21, 2023
97632d8
update reactor-cpp and at tests covering sparse upstream events
cmnrd Mar 21, 2023
4d8bf85
format tests
cmnrd Mar 24, 2023
68e89e6
Merge branch 'master' into enclave-connections
cmnrd Mar 28, 2023
9cabad2
update reactor-cpp
cmnrd Mar 28, 2023
a7afcee
update reactor-cpp
cmnrd Mar 31, 2023
9626826
add tests with cycles
cmnrd Mar 31, 2023
58c6b0f
Merge branch 'master' into enclave-connections
cmnrd Apr 20, 2023
0d0fc3d
Merge branch 'master' into enclave-connections
cmnrd May 8, 2023
a36d8a3
update reactor-cpp
cmnrd May 8, 2023
de0af0c
unify connection generation using a lambda function
cmnrd May 8, 2023
d6c4e5a
allow connections where not all ports belong to enclaves
cmnrd May 8, 2023
814e0bf
use vector of unique pointers to store connections
cmnrd May 8, 2023
3d84b6c
format test
cmnrd May 8, 2023
c0b5127
only reserve if we have a dedicated connection vector
cmnrd May 10, 2023
3b49f12
update reactor-cpp
cmnrd May 10, 2023
fa0e058
bugfix
cmnrd May 10, 2023
f7261ea
another C++ syntax fix
cmnrd May 10, 2023
aae5cae
relax deadline
cmnrd May 10, 2023
0554c99
fix test file
cmnrd May 12, 2023
a305596
relax more deadlines and update timings
cmnrd May 12, 2023
48898a2
update reactor-cpp
cmnrd May 12, 2023
b7d0cd1
update reactor-cpp
cmnrd May 15, 2023
036625c
update reactor-cpp
cmnrd May 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 9 additions & 44 deletions org.lflang/src/lib/cpp/lfutil.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ class LFScope {
void request_stop() const { return environment()->sync_shutdown(); }
};

template<class T>
template<class PortPtr>
void bind_multiple_ports(
std::vector<reactor::Port<T>*>& left_ports,
std::vector<reactor::Port<T>*>& right_ports,
bool repeat_left) {

std::vector<PortPtr>& left_ports,
std::vector<PortPtr>& right_ports,
bool repeat_left,
std::function<void(PortPtr, PortPtr, std::size_t)> connect)
{
if (repeat_left) {
auto l_size = left_ports.size();
auto r_size = right_ports.size();
Expand All @@ -92,50 +93,14 @@ void bind_multiple_ports(
<< "Not all ports will be connected!";
}

std::size_t idx{0};
while (left_it != left_ports.end() && right_it != right_ports.end()) {
auto left = *left_it;
auto right = *right_it;
left->bind_to(right);
left_it++;
right_it++;
}
}

template<class T>
void bind_multiple_connections_with_ports(
std::vector<reactor::Connection<T>*>& connections,
std::vector<reactor::Port<T>*>& ports,
bool repeat_left) {

if (repeat_left) {
auto l_size = connections.size();
auto r_size = ports.size();
// divide and round up
auto repetitions = r_size / l_size + (r_size % l_size != 0);
// repeat repetitions-1 times
connections.reserve(repetitions * l_size);
for (std::size_t i{1}; i < repetitions; i++) {
std::copy_n(connections.begin(), l_size, std::back_inserter(connections));
}
}

auto left_it = connections.begin();
auto right_it = ports.begin();

if (connections.size() < ports.size()) {
reactor::log::Warn() << "There are more right ports than left ports. "
<< "Not all ports will be connected!";
} else if (connections.size() > ports.size()) {
reactor::log::Warn() << "There are more left ports than right ports. "
<< "Not all ports will be connected!";
}

while (left_it != connections.end() && right_it != ports.end()) {
auto left = *left_it;
auto right = *right_it;
left->bind_downstream_port(right);
connect(left, right, idx);
left_it++;
right_it++;
idx++;
}
}

Expand Down
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/Target.java
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ public String getSingleLineCommentPrefix() {
* program (and keepalive was not explicitly unset by the user).
*/
public boolean setsKeepAliveOptionAutomatically() {
return this != Rust;
return this != Rust && this != CPP;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ package org.lflang.generator.cpp

import org.lflang.*
import org.lflang.generator.PrependOperator
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.name
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.requiresConnectionClass
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType
import org.lflang.lf.Action
import org.lflang.lf.Connection
Expand Down Expand Up @@ -86,7 +89,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
// is in a bank, but not a multiport
"""
|for (auto& __lf_instance : ${container.name}) {
${" | "..generateCode("__lf_instance->${port.name}")}
${" | "..generateCode("__lf_instance->${if(container.isEnclave) "__lf_instance->" else ""}${port.name}")}
|}
""".trimMargin()
} else {
Expand Down Expand Up @@ -170,48 +173,51 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) {
* complex logic for finding the actual type, we return a decltype statement and let the C++ compiler do the job.
*/
private val VarRef.portType: String
get() = "reactor::Port<${dataType}>*"
get() = "reactor::Port<typename ${dataType}>*"

private fun declareMultiportConnection(c: Connection, idx: Int): String {
// It should be safe to assume that all ports have the same type. Thus we just pick the
// first left port to determine the type of the entire connection
val portType = c.leftPorts[0].portType

val leftPort = c.leftPorts[0].variable as Port
val dataType = leftPort.inferredType.cppType

// Generate code which adds all left hand ports and all right hand ports to a vector each. If we are handling multiports
// within a bank, then we normally iterate over all banks in an outer loop and over all ports in an inner loop. However,
// if the connection is a cross connection, than we change the order on the right side and iterate over ports before banks.
// if the connection is an interleaved connection, than we change the order on the right side and iterate over ports before banks.
return with(PrependOperator) {
if (!c.requiresConnectionClass) {
"""
|// connection $idx
|std::vector<$portType> __lf_left_ports_$idx;
${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }}
|std::vector<$portType> __lf_right_ports_$idx;
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
|lfutil::bind_multiple_ports(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated});
""".trimMargin()
} else {
"""
|// connection $idx
|std::vector<$portType> __lf_left_ports_$idx;
${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }}
|${c.name}.reserve(__lf_left_ports_$idx.size());
|for(size_t __lf_idx{0}; __lf_idx < __lf_left_ports_$idx.size(); __lf_idx++) {
| ${c.name}.emplace_back("${c.name}" + std::to_string(__lf_idx), this, ${c.delay.toCppTime()});
| ${c.name}.back().bind_upstream_port(__lf_left_ports_$idx[__lf_idx]);
|}
|std::vector<reactor::Connection<$dataType>*> __lf_connection_pointers_$idx;
|for (auto& connection : ${c.name}) {
| __lf_connection_pointers_$idx.push_back(&connection);
|}
|std::vector<$portType> __lf_right_ports_$idx;
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
|lfutil::bind_multiple_connections_with_ports(__lf_connection_pointers_$idx, __lf_right_ports_$idx, ${c.isIterated});
""".trimMargin()
}
"""
|// connection $idx
|std::vector<$portType> __lf_left_ports_$idx;
${" |"..c.leftPorts.joinWithLn { addAllPortsToVector(it, "__lf_left_ports_$idx") }}
|std::vector<$portType> __lf_right_ports_$idx;
${" |"..c.rightPorts.joinWithLn { addAllPortsToVector(it, "__lf_right_ports_$idx") }}
${" |"..if (c.requiresConnectionClass) "${c.name}.reserve(std::max(__lf_left_ports_$idx.size(), __lf_right_ports_$idx.size()));" else ""}
|lfutil::bind_multiple_ports<$portType>(__lf_left_ports_$idx, __lf_right_ports_$idx, ${c.isIterated},
${" |"..c.getConnectionLambda(portType)}
|);
""".trimMargin()
}
}

private fun Connection.getConnectionLambda(portType: String): String {
return when {
isEnclaveConnection -> """
[this]($portType left, $portType right, std::size_t idx) {
$name.push_back(std::make_unique<$cppType>(
"$name" + std::to_string(idx), right->environment()${if (delay != null) ", ${delay.toCppTime()}" else ""}));
$name.back()->bind_upstream_port(left);
$name.back()->bind_downstream_port(right);
}
""".trimIndent()

requiresConnectionClass -> """
[this]($portType left, $portType right, std::size_t idx) {
$name.push_back(std::make_unique<$cppType>("$name" + std::to_string(idx), this, ${delay.toCppTime()}));
$name.back()->bind_upstream_port(left);
$name.back()->bind_downstream_port(right);
}
""".trimIndent()

else -> "[]($portType left, $portType right, [[maybe_unused]]std::size_t idx) { left->bind_to(right); }"
}
}

Expand Down
54 changes: 39 additions & 15 deletions org.lflang/src/org/lflang/generator/cpp/CppConnectionGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.lflang.generator.cpp

import org.lflang.*
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.cppType
import org.lflang.generator.cpp.CppConnectionGenerator.Companion.isEnclaveConnection
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType
import org.lflang.lf.Connection
import org.lflang.lf.Port
Expand All @@ -25,13 +27,29 @@ class CppConnectionGenerator(private val reactor: Reactor) {
get() {
val leftPort = leftPorts.first()
return when {
isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>"
else -> throw IllegalArgumentException("Connection is neither physical nor delayed")
isEnclaveConnection -> when {
isPhysical -> "reactor::PhysicalEnclaveConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedEnclaveConnection<${leftPort.dataType}>"
else -> "reactor::EnclaveConnection<${leftPort.dataType}>"
}

isPhysical -> "reactor::PhysicalConnection<${leftPort.dataType}>"
delay != null -> "reactor::DelayedConnection<${leftPort.dataType}>"
else -> throw IllegalArgumentException("Unsupported connection type")
}
}

val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null
val Connection.isEnclaveConnection: Boolean
get() {
for (port in leftPorts + rightPorts) {
if (port.container?.isEnclave == true) {
return true
}
}
return false
}

val Connection.requiresConnectionClass: Boolean get() = isPhysical || delay != null || isEnclaveConnection;
}

fun generateDeclarations() =
Expand All @@ -42,18 +60,24 @@ class CppConnectionGenerator(private val reactor: Reactor) {
reactor.connections.mapNotNull { generateConstructorInitializer(it) }.joinLn()

private fun generateDecleration(connection: Connection): String? =
if (connection.requiresConnectionClass) {
if (connection.hasMultipleConnections) {
"std::vector<${connection.cppType}> ${connection.name};"
} else {
"${connection.cppType} ${connection.name};"
with(connection) {
if (requiresConnectionClass) {
if (hasMultipleConnections) {
"std::vector<std::unique_ptr<${connection.cppType}>> ${connection.name};"
} else {
"${connection.cppType} ${connection.name};"
}
} else null
}

private fun generateConstructorInitializer(connection: Connection): String? = with(connection) {
if (requiresConnectionClass && !hasMultipleConnections) {
when {
isEnclaveConnection && delay == null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get()}"""
isEnclaveConnection && delay != null -> """, $name{"$name", ${rightPorts[0].container.name}->__lf_env.get(), ${delay.toCppTime()}}"""
else -> """, $name{"$name", this, ${delay.toCppTime()}}"""
}
} else null
}

private fun generateConstructorInitializer(connection: Connection): String? =
if (connection.requiresConnectionClass && !connection.hasMultipleConnections) {
val delay = connection.delay.toCppTime()
val name = connection.name
""", $name{"$name", this, $delay}"""
} else null
}
8 changes: 6 additions & 2 deletions org.lflang/src/org/lflang/generator/cpp/CppExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.lflang.generator.cpp

import org.eclipse.emf.ecore.resource.Resource
import org.lflang.*
import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave
import org.lflang.lf.BuiltinTriggerRef
import org.lflang.lf.Expression
import org.lflang.lf.Port
Expand Down Expand Up @@ -111,8 +112,11 @@ val Reactor.templateName: String get() = if (isGeneric) "$name<${typeParms.joinT

/** Get a C++ code representation of the given variable */
val VarRef.name: String
get() = if (this.container == null) this.variable.name
else "${this.container.name}->${this.variable.name}"
get() = when {
container == null -> variable.name
container.isEnclave -> "${container.name}->__lf_instance->${variable.name}"
else -> "${container.name}->${variable.name}"
}

/** Get a C++ code representation of the given trigger */
val TriggerRef.name: String
Expand Down
Loading