Skip to content

Commit bfa1ccd

Browse files
authored
optimize generation of multiport connects (#336)
1 parent c1dbc59 commit bfa1ccd

4 files changed

Lines changed: 113 additions & 6 deletions

File tree

include/reactor-uc/util.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,24 @@
44
#include "reactor-uc/port.h"
55
#include "reactor-uc/connection.h"
66

7+
/*!
8+
* @brief Connect one upstream port to one downstream port.
9+
*/
710
void lf_connect(Connection* connection, Port* upstream, Port* downstream);
811

12+
/*!
13+
* @brief Connect one upstream port to an array of downstream ports.
14+
*/
15+
void lf_grouped_connect(Connection* connection, Port* upstream, Port* downstream_array, int downstream_size);
16+
17+
/*!
18+
* @brief Connect an output port to a federated output connection.
19+
*/
920
void lf_connect_federated_output(Connection* connection, Port* output);
1021

22+
/*!
23+
* @brief Connect a federated input port to an input port.
24+
*/
1125
void lf_connect_federated_input(Connection* connection, Port* input);
1226

1327
#endif

lfc/core/src/main/kotlin/org/lflang/generator/uc/UcConnectionGenerator.kt

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package org.lflang.generator.uc
22

33
import java.util.*
4-
import kotlin.collections.HashSet
5-
import org.lflang.*
4+
import org.lflang.allConnections
65
import org.lflang.generator.PrependOperator
76
import org.lflang.generator.orNever
87
import org.lflang.generator.uc.UcInstanceGenerator.Companion.isAFederate
98
import org.lflang.generator.uc.UcPortGenerator.Companion.arrayLength
109
import org.lflang.generator.uc.UcPortGenerator.Companion.isArray
1110
import org.lflang.generator.uc.UcReactorGenerator.Companion.codeType
11+
import org.lflang.joinWithLn
1212
import org.lflang.lf.*
13+
import org.lflang.toText
1314

1415
/**
1516
* This generator creates code for configuring the connections between reactors. This is perhaps the
@@ -357,9 +358,9 @@ class UcConnectionGenerator(
357358

358359
private fun generateReactorCtorCode(conn: UcGroupedConnection) =
359360
if (conn.isLogical) {
360-
"LF_INITIALIZE_LOGICAL_CONNECTION(${reactor.codeType}, ${conn.getUniqueName()}, ${conn.bankWidth}, ${conn.portWidth})"
361+
"LF_INITIALIZE_LOGICAL_CONNECTION(${reactor.codeType}, ${conn.getUniqueName()}, ${conn.bankWidth}, ${conn.portWidth});"
361362
} else {
362-
"LF_INITIALIZE_DELAYED_CONNECTION(${reactor.codeType}, ${conn.getUniqueName()}, ${conn.delay}, ${conn.bankWidth}, ${conn.portWidth})"
363+
"LF_INITIALIZE_DELAYED_CONNECTION(${reactor.codeType}, ${conn.getUniqueName()}, ${conn.delay}, ${conn.bankWidth}, ${conn.portWidth});"
363364
}
364365

365366
private fun generateFederateCtorCode(conn: UcFederatedConnectionBundle) =
@@ -373,8 +374,87 @@ class UcConnectionGenerator(
373374
"""
374375
.trimMargin()
375376

376-
private fun generateConnectionStatements(conn: UcGroupedConnection) =
377-
conn.channels.joinToString(separator = "\n") { generateConnectChannel(conn, it) }
377+
private fun generateGroupedConnectChannel(
378+
groupedConn: UcGroupedConnection,
379+
src: UcChannel,
380+
dest: UcChannel,
381+
size: Int,
382+
) =
383+
"""|lf_grouped_connect((Connection *) &self->${groupedConn.getUniqueName()}[${src.getCodeBankIdx()}][${src.getCodePortIdx()}], (Port *) ${src.generateChannelPointer()}, (Port *) ${dest.generateChannelPort()}, ${size});
384+
"""
385+
.trimMargin()
386+
387+
private fun generateInterleavedConnectChannel(
388+
groupedConn: UcGroupedConnection,
389+
src: UcChannel,
390+
dest: UcChannel,
391+
maxBankSrc: Int,
392+
maxPortSrc: Int,
393+
) =
394+
"""
395+
|for(int j = 0; j < ${maxBankSrc}; j++) {
396+
| for(int i = 0; i < ${maxPortSrc}; i++) {
397+
| lf_connect((Connection *) &self->${groupedConn.getUniqueName()}[j][i], (Port *) &self->${src.varRef.container.name}[j].${src.varRef.name}[i], (Port *) &self->${dest.varRef.container.name}[i].${dest.varRef.name}[j]);
398+
| }
399+
|}
400+
"""
401+
.trimMargin()
402+
403+
// checks if the given list of Integers is continuously increasing.
404+
fun isContinuous(array: List<Int>): Boolean {
405+
return array.size != array[array.size - 1] + 1
406+
}
407+
408+
private fun generateOutboundConnection(
409+
conn: UcGroupedConnection,
410+
outgoingConns: List<UcConnectionChannel>
411+
): String {
412+
val groupedDownstreams = HashMap<Pair<VarRef, Int>, MutableList<UcConnectionChannel>>()
413+
outgoingConns.forEach { channel ->
414+
groupedDownstreams
415+
.getOrPut(Pair(channel.dest.varRef, channel.dest.bankIdx), { mutableListOf() })
416+
.add(channel)
417+
}
418+
419+
return groupedDownstreams
420+
.map { groupedDownstream ->
421+
groupedDownstream.value.sortBy { it.dest.portIdx }
422+
val sequential = groupedDownstream.value.map { it.dest.portIdx }
423+
424+
if (isContinuous(sequential) && sequential.size >= 4) {
425+
generateGroupedConnectChannel(
426+
conn,
427+
groupedDownstream.value[0].src,
428+
groupedDownstream.value[0].dest,
429+
groupedDownstream.value.size)
430+
} else {
431+
groupedDownstream.value.joinToString(separator = "\n") {
432+
generateConnectChannel(conn, it)
433+
}
434+
}
435+
}
436+
.joinToString(separator = "\n") { it }
437+
}
438+
439+
private fun generateConnectionStatements(conn: UcGroupedConnection): String {
440+
// A common wiring pattern enabled by the interleaved keyword uses two banks of reactors,
441+
// each with a port bank. The connections are interleaved so that src[j][i] is connected to
442+
// dest[i][j]. This optimization is performed only if more than four connections need to be
443+
// drawn.
444+
445+
return if (conn.channels.all {
446+
it.src.bankIdx == it.dest.portIdx && it.src.portIdx == it.dest.bankIdx
447+
} && conn.channels.size >= 4) {
448+
// here we need to calculate the maximum bank and port index, which will
449+
// become the bounds of the two for-loops.
450+
val maxBankIdx = conn.channels.maxOf { it.src.bankIdx } + 1
451+
val maxPortIdx = conn.channels.maxOf { it.src.portIdx } + 1
452+
generateInterleavedConnectChannel(
453+
conn, conn.channels[0].src, conn.channels[0].dest, maxBankIdx, maxPortIdx)
454+
} else {
455+
generateOutboundConnection(conn, conn.channels)
456+
}
457+
}
378458

379459
private fun generateConnectFederateOutputChannel(
380460
bundle: UcFederatedConnectionBundle,

lfc/core/src/main/kotlin/org/lflang/generator/uc/UcConnectionUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ class UcChannel(val varRef: VarRef, val portIdx: Int, val bankIdx: Int, val fede
159159
private val portInstance = "${varRef.name}[${getCodePortIdx()}]"
160160

161161
fun generateChannelPointer() = "&self->${reactorInstance}${portInstance}"
162+
163+
fun generateChannelPort() = "&self->${reactorInstance}${varRef.name}"
162164
}
163165

164166
/**

src/util.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ void lf_connect(Connection* connection, Port* upstream, Port* downstream) {
99
connection->register_downstream(connection, downstream);
1010
}
1111

12+
void lf_grouped_connect(Connection* connection, Port* upstream, Port* downstream_array, int downstream_size) {
13+
for (int i = 0; i < downstream_size; i++) {
14+
if (connection->upstream == NULL) {
15+
validate(upstream->conns_out_registered < upstream->conns_out_size);
16+
upstream->conns_out[upstream->conns_out_registered++] = connection;
17+
}
18+
connection->upstream = upstream;
19+
connection->register_downstream(connection, &downstream_array[i]);
20+
}
21+
}
22+
1223
void lf_connect_federated_output(Connection* connection, Port* output) {
1324
validate(output->conns_out_registered < output->conns_out_size);
1425
output->conns_out[output->conns_out_registered++] = connection;

0 commit comments

Comments
 (0)