Speed-related improvements in the periodic FlowManager::mapReader()
thread that periodically reads the Network MAP state and performs
the appropriate actions: pushes state into the switches and
recomputes the Shortest Paths.
Below are the measurement numbers BEFORE and AFTER the optimization.
The setup is 8 node cluster, there are NO changes in the
network, and all Flow Entries have been added to the switches.
I.e., those are numbers in steady setup how long
time it takes to process the state.
Note that the relationship to the number of flows is not linear:
* BEFORE OPTIMIZATION:
Measurement numbers for periodic flow processing (8 node cluster)
- 42 flows
Time: 3 sec
Rate: 15 flows/sec
- 252 flows
Time: 9-11 sec
Rate: 25-30 flows/sec
On one controller (devw7), it might take up to 13 seconds.
- 1050 flows
Time: 25-27 seconds
Rate: 40 flows/sec
* AFTER OPTIMIZATION:
Measurement numbers for 1050 flows are:
- 42 flows
Time: 2-3 sec
Rate: 18-20 flows/sec
- 252 flows
Time: 3-4 sec
Rate: 60-70 flows/sec
- 1050 flows
Time: 9-10 seconds
Rate: 115-120 flow/sec
I.e., the improvements for larger number of flows
(252 and 1050) are close to 3x.
All the improvements are very trivial:
Just reorder the fetching of the related Vertex attributes at the time
they are needed, and eliminate additional attribute fetching if
the Vertex is going to be ignored anyway.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 9a5129f..03f4ce7 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -131,23 +131,16 @@
conn.utils().getAllFlowEntries(conn);
for (IFlowEntry flowEntryObj : allFlowEntries) {
counterAllFlowEntries++;
- String flowEntryIdStr = flowEntryObj.getFlowEntryId();
- String userState = flowEntryObj.getUserState();
String switchState = flowEntryObj.getSwitchState();
- String dpidStr = flowEntryObj.getSwitchDpid();
- if ((flowEntryIdStr == null) ||
- (userState == null) ||
- (switchState == null) ||
- (dpidStr == null)) {
- log.debug("IGNORING Flow Entry entry with null fields");
- continue;
- }
- FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
- Dpid dpid = new Dpid(dpidStr);
-
- if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
+ if ((switchState == null) ||
+ (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
continue; // Ignore the entry: nothing to do
+ }
+ String dpidStr = flowEntryObj.getSwitchDpid();
+ if (dpidStr == null)
+ continue;
+ Dpid dpid = new Dpid(dpidStr);
IOFSwitch mySwitch = mySwitches.get(dpid.value());
if (mySwitch == null)
continue; // Ignore the entry: not my switch
@@ -164,6 +157,9 @@
// to cover the more common scenario.
// TODO: This is error prone and needs to be fixed!
//
+ String userState = flowEntryObj.getUserState();
+ if (userState == null)
+ continue;
if (userState.equals("FE_USER_DELETE")) {
// An entry that needs to be deleted.
deleteFlowEntries.add(flowEntryObj);
@@ -232,7 +228,6 @@
conn.utils().removeFlowEntry(conn, flowEntryObj);
}
-
//
// Fetch and recompute the Shortest Path for those
// Flow Paths this controller is responsible for.
@@ -249,29 +244,10 @@
if (dataPathSummaryStr.isEmpty())
continue; // No need to maintain this flow
- // Fetch the fields needed to recompute the shortest path
- String flowIdStr = flowPathObj.getFlowId();
String srcDpidStr = flowPathObj.getSrcSwitch();
- Short srcPortShort = flowPathObj.getSrcPort();
- String dstDpidStr = flowPathObj.getDstSwitch();
- Short dstPortShort = flowPathObj.getDstPort();
- if ((flowIdStr == null) ||
- (srcDpidStr == null) ||
- (srcPortShort == null) ||
- (dstDpidStr == null) ||
- (dstPortShort == null)) {
- log.debug("IGNORING Flow Path entry with null fields");
+ if (srcDpidStr == null)
continue;
- }
-
- FlowId flowId = new FlowId(flowIdStr);
Dpid srcDpid = new Dpid(srcDpidStr);
- Port srcPort = new Port(srcPortShort);
- Dpid dstDpid = new Dpid(dstDpidStr);
- Port dstPort = new Port(dstPortShort);
- SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
- SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
-
//
// Use the source DPID as a heuristic to decide
// which controller is responsible for maintaining the
@@ -284,6 +260,22 @@
if (mySwitch == null)
continue; // Ignore: not my responsibility
+ // Fetch the fields needed to recompute the shortest path
+ Short srcPortShort = flowPathObj.getSrcPort();
+ String dstDpidStr = flowPathObj.getDstSwitch();
+ Short dstPortShort = flowPathObj.getDstPort();
+ if ((srcPortShort == null) ||
+ (dstDpidStr == null) ||
+ (dstPortShort == null)) {
+ continue;
+ }
+
+ Port srcPort = new Port(srcPortShort);
+ Dpid dstDpid = new Dpid(dstDpidStr);
+ Port dstPort = new Port(dstPortShort);
+ SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+ SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+
counterMyFlowPaths++;
//
@@ -309,8 +301,6 @@
if (dataPathSummaryStr.equals(newDataPathSummaryStr))
continue; // Nothing changed
- log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
- flowId.toString());
reconcileFlow(flowPathObj, dataPath);
}
topoRouteService.dropShortestPathTopo();