mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
ip-node: add implementation of StreamGraph for automatic routing
This commit is contained in:
parent
5f0d181a8e
commit
967e39e36c
3 changed files with 87 additions and 24 deletions
|
@ -29,6 +29,10 @@ class Vertex {
|
|||
public:
|
||||
using Identifier = std::size_t;
|
||||
|
||||
const Identifier&
|
||||
getIdentifier() const
|
||||
{ return id; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<< (std::ostream& stream, const Vertex& vertex)
|
||||
{ return stream << vertex.id; }
|
||||
|
@ -314,7 +318,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
VertexIdentifier lastVertexId;
|
||||
EdgeIdentifier lastEdgeId;
|
||||
|
||||
|
|
|
@ -43,6 +43,52 @@ namespace villas {
|
|||
namespace fpga {
|
||||
namespace ip {
|
||||
|
||||
class StreamVertex : public graph::Vertex {
|
||||
public:
|
||||
StreamVertex(const std::string& node, const std::string& port, bool isMaster) :
|
||||
nodeName(node), portName(port), isMaster(isMaster) {}
|
||||
|
||||
std::string getName() const
|
||||
{ return nodeName + "/" + portName + "(" + (isMaster ? "M" : "S") + ")"; }
|
||||
|
||||
friend std::ostream&
|
||||
operator<< (std::ostream& stream, const StreamVertex& vertex)
|
||||
{ return stream << vertex.getIdentifier() << ": " << vertex.getName(); }
|
||||
|
||||
public:
|
||||
std::string nodeName;
|
||||
std::string portName;
|
||||
bool isMaster;
|
||||
};
|
||||
|
||||
|
||||
class StreamGraph : public graph::DirectedGraph<StreamVertex> {
|
||||
public:
|
||||
StreamGraph() : graph::DirectedGraph<StreamVertex>("StreamGraph") {}
|
||||
|
||||
std::shared_ptr<StreamVertex>
|
||||
getOrCreateStreamVertex(const std::string& node,
|
||||
const std::string& port,
|
||||
bool isMaster)
|
||||
{
|
||||
for(auto& [vertexId, vertex] : vertices) {
|
||||
(void) vertexId;
|
||||
if(vertex->nodeName == node and vertex->portName == port and vertex->isMaster == isMaster)
|
||||
return vertex;
|
||||
}
|
||||
|
||||
// vertex not found, create new one
|
||||
auto vertex = std::make_shared<StreamVertex>(node, port, isMaster);
|
||||
addVertex(vertex);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern StreamGraph streamGraph;
|
||||
|
||||
|
||||
// TODO: reflect on interface that an IpNode exposes and how to design it to
|
||||
// blend in with VILLASnode software nodes
|
||||
class IpNode : public IpCore {
|
||||
|
@ -58,6 +104,14 @@ public:
|
|||
bool connect(std::string portName, const StreamPort& to);
|
||||
bool disconnect(std::string portName);
|
||||
|
||||
const StreamVertex&
|
||||
getMasterPort(const std::string& name) const
|
||||
{ return *portsMaster.at(name); }
|
||||
|
||||
const StreamVertex&
|
||||
getSlavePort(const std::string& name) const
|
||||
{ return *portsSlave.at(name); }
|
||||
|
||||
bool loopbackPossible() const;
|
||||
bool connectLoopback();
|
||||
|
||||
|
@ -65,8 +119,8 @@ private:
|
|||
std::pair<std::string, std::string> getLoopbackPorts() const;
|
||||
|
||||
protected:
|
||||
std::map<std::string, StreamPort> portsMaster;
|
||||
std::map<std::string, StreamPort> portsSlave;
|
||||
std::map<std::string, std::shared_ptr<StreamVertex>> portsMaster;
|
||||
std::map<std::string, std::shared_ptr<StreamVertex>> portsSlave;
|
||||
};
|
||||
|
||||
class IpNodeFactory : public IpCoreFactory {
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace fpga {
|
|||
namespace ip {
|
||||
|
||||
|
||||
StreamGraph streamGraph;
|
||||
|
||||
bool
|
||||
IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
|
||||
{
|
||||
|
@ -49,25 +51,28 @@ IpNodeFactory::configureJson(IpCore& ip, json_t* json_ip)
|
|||
return false;
|
||||
}
|
||||
|
||||
int port_num;
|
||||
try {
|
||||
port_num = std::stoi(tokens[1]);
|
||||
} catch(const std::invalid_argument&) {
|
||||
logger->error("Target port number is not an integer: '{}'", target_raw);
|
||||
return false;
|
||||
}
|
||||
|
||||
IpNode::StreamPort port;
|
||||
port.nodeName = tokens[0];
|
||||
port.portNumber = port_num;
|
||||
|
||||
const std::string role(role_raw);
|
||||
if(role == "master" or role == "initiator") {
|
||||
ipNode.portsMaster[name_raw] = port;
|
||||
} else /* slave */ {
|
||||
ipNode.portsSlave[name_raw] = port;
|
||||
}
|
||||
const bool isMaster = (role == "master" or role == "initiator");
|
||||
|
||||
|
||||
auto thisVertex = streamGraph.getOrCreateStreamVertex(
|
||||
ip.getInstanceName(),
|
||||
name_raw,
|
||||
isMaster);
|
||||
|
||||
auto connectedVertex = streamGraph.getOrCreateStreamVertex(
|
||||
tokens[0],
|
||||
tokens[1],
|
||||
not isMaster);
|
||||
|
||||
|
||||
if(isMaster) {
|
||||
streamGraph.addDefaultEdge(thisVertex->getIdentifier(),
|
||||
connectedVertex->getIdentifier());
|
||||
ipNode.portsMaster[name_raw] = thisVertex;
|
||||
} else /* slave */ {
|
||||
ipNode.portsSlave[name_raw] = thisVertex;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -79,7 +84,7 @@ IpNode::getLoopbackPorts() const
|
|||
for(auto& [masterName, masterTo] : portsMaster) {
|
||||
for(auto& [slaveName, slaveTo] : portsSlave) {
|
||||
// TODO: should we also check which IP both ports are connected to?
|
||||
if(masterTo.nodeName == slaveTo.nodeName) {
|
||||
if(masterTo->nodeName == slaveTo->nodeName) {
|
||||
return { masterName, slaveName };
|
||||
}
|
||||
}
|
||||
|
@ -105,11 +110,11 @@ IpNode::connectLoopback()
|
|||
logger->debug("master port: {}", ports.first);
|
||||
logger->debug("slave port: {}", ports.second);
|
||||
|
||||
logger->debug("switch at: {}", portMaster.nodeName);
|
||||
logger->debug("switch at: {}", portMaster->nodeName);
|
||||
|
||||
// TODO: verify this is really a switch!
|
||||
auto axiStreamSwitch = reinterpret_cast<ip::AxiStreamSwitch*>(
|
||||
card->lookupIp(portMaster.nodeName));
|
||||
card->lookupIp(portMaster->nodeName));
|
||||
|
||||
if(axiStreamSwitch == nullptr) {
|
||||
logger->error("Cannot find switch");
|
||||
|
@ -117,7 +122,7 @@ IpNode::connectLoopback()
|
|||
}
|
||||
|
||||
// switch's slave port is our master port and vice versa
|
||||
return axiStreamSwitch->connect(portMaster.portNumber, portSlave.portNumber);
|
||||
return axiStreamSwitch->connect(*portMaster, *portSlave);
|
||||
}
|
||||
|
||||
} // namespace ip
|
||||
|
|
Loading…
Add table
Reference in a new issue