Committed by
Ray Milkey
[ONOS-3724] Fix the Cbench regression issue
Control message monitoring brings some overhead to controller. In an extreme stressing environment (e.g., running Cbench), it leads potential performance degradation. This commit tries to mitigate the Cbench regression with two steps: 1. improve the monitoring performance by assigning more # of threads in each thread group. 2. make the control message listening feature optional. Change-Id: I4f7361b7c598c6de71d390eab78a20ada381d4dd
Showing
10 changed files
with
90 additions
and
27 deletions
... | @@ -65,6 +65,13 @@ public interface OpenFlowController { | ... | @@ -65,6 +65,13 @@ public interface OpenFlowController { |
65 | OpenFlowSwitch getEqualSwitch(Dpid dpid); | 65 | OpenFlowSwitch getEqualSwitch(Dpid dpid); |
66 | 66 | ||
67 | /** | 67 | /** |
68 | + * If this set to be true, all incoming events are monitored. | ||
69 | + * Other wise, only stats related incoming events are monitored | ||
70 | + * @param monitor monitoring flag | ||
71 | + */ | ||
72 | + void monitorAllEvents(boolean monitor); | ||
73 | + | ||
74 | + /** | ||
68 | * Register a listener for meta events that occur to OF | 75 | * Register a listener for meta events that occur to OF |
69 | * devices. | 76 | * devices. |
70 | * @param listener the listener to notify | 77 | * @param listener the listener to notify | ... | ... |
... | @@ -92,10 +92,10 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -92,10 +92,10 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
92 | protected OFFeaturesReply features; | 92 | protected OFFeaturesReply features; |
93 | protected OFDescStatsReply desc; | 93 | protected OFDescStatsReply desc; |
94 | 94 | ||
95 | - protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>(); | 95 | + protected Set<OpenFlowEventListener> ofOutgoingMsgListener = new CopyOnWriteArraySet<>(); |
96 | 96 | ||
97 | protected ExecutorService executorMsgs = | 97 | protected ExecutorService executorMsgs = |
98 | - Executors.newFixedThreadPool(2, groupedThreads("onos/of", "ctrl-msg-stats-%d")); | 98 | + Executors.newCachedThreadPool(groupedThreads("onos/of", "event-outgoing-msg-stats-%d")); |
99 | 99 | ||
100 | // messagesPendingMastership is used as synchronization variable for | 100 | // messagesPendingMastership is used as synchronization variable for |
101 | // all mastership related changes. In this block, mastership (including | 101 | // all mastership related changes. In this block, mastership (including |
... | @@ -167,14 +167,16 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -167,14 +167,16 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
167 | } | 167 | } |
168 | } | 168 | } |
169 | 169 | ||
170 | - // listen to outgoing control messages | 170 | + // listen to outgoing control messages only if listeners are registered |
171 | - msgs.forEach(m -> { | 171 | + if (ofOutgoingMsgListener.size() != 0) { |
172 | - if (m.getType() == OFType.PACKET_OUT || | 172 | + msgs.forEach(m -> { |
173 | - m.getType() == OFType.FLOW_MOD || | 173 | + if (m.getType() == OFType.PACKET_OUT || |
174 | - m.getType() == OFType.STATS_REQUEST) { | 174 | + m.getType() == OFType.FLOW_MOD || |
175 | - executorMsgs.submit(new OFMessageHandler(dpid, m)); | 175 | + m.getType() == OFType.STATS_REQUEST) { |
176 | - } | 176 | + executorMsgs.submit(new OFMessageHandler(dpid, m)); |
177 | - }); | 177 | + } |
178 | + }); | ||
179 | + } | ||
178 | } | 180 | } |
179 | 181 | ||
180 | private void sendMsgsOnChannel(List<OFMessage> msgs) { | 182 | private void sendMsgsOnChannel(List<OFMessage> msgs) { |
... | @@ -332,12 +334,12 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -332,12 +334,12 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
332 | 334 | ||
333 | @Override | 335 | @Override |
334 | public void addEventListener(OpenFlowEventListener listener) { | 336 | public void addEventListener(OpenFlowEventListener listener) { |
335 | - ofEventListener.add(listener); | 337 | + ofOutgoingMsgListener.add(listener); |
336 | } | 338 | } |
337 | 339 | ||
338 | @Override | 340 | @Override |
339 | public void removeEventListener(OpenFlowEventListener listener) { | 341 | public void removeEventListener(OpenFlowEventListener listener) { |
340 | - ofEventListener.remove(listener); | 342 | + ofOutgoingMsgListener.remove(listener); |
341 | } | 343 | } |
342 | 344 | ||
343 | @Override | 345 | @Override |
... | @@ -547,7 +549,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour | ... | @@ -547,7 +549,7 @@ public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour |
547 | 549 | ||
548 | @Override | 550 | @Override |
549 | public void run() { | 551 | public void run() { |
550 | - for (OpenFlowEventListener listener : ofEventListener) { | 552 | + for (OpenFlowEventListener listener : ofOutgoingMsgListener) { |
551 | listener.handleMessage(dpid, msg); | 553 | listener.handleMessage(dpid, msg); |
552 | } | 554 | } |
553 | } | 555 | } | ... | ... |
... | @@ -52,6 +52,10 @@ public class OpenflowControllerAdapter implements OpenFlowController { | ... | @@ -52,6 +52,10 @@ public class OpenflowControllerAdapter implements OpenFlowController { |
52 | } | 52 | } |
53 | 53 | ||
54 | @Override | 54 | @Override |
55 | + public void monitorAllEvents(boolean monitor) { | ||
56 | + } | ||
57 | + | ||
58 | + @Override | ||
55 | public void addListener(OpenFlowSwitchListener listener) { | 59 | public void addListener(OpenFlowSwitchListener listener) { |
56 | } | 60 | } |
57 | 61 | ... | ... |
... | @@ -17,6 +17,8 @@ package org.onosproject.openflow.controller.driver; | ... | @@ -17,6 +17,8 @@ package org.onosproject.openflow.controller.driver; |
17 | 17 | ||
18 | import org.junit.Before; | 18 | import org.junit.Before; |
19 | import org.junit.Test; | 19 | import org.junit.Test; |
20 | +import org.onosproject.openflow.controller.Dpid; | ||
21 | +import org.onosproject.openflow.controller.OpenFlowEventListener; | ||
20 | import org.projectfloodlight.openflow.protocol.OFMessage; | 22 | import org.projectfloodlight.openflow.protocol.OFMessage; |
21 | import org.jboss.netty.channel.Channel; | 23 | import org.jboss.netty.channel.Channel; |
22 | import java.util.ArrayList; | 24 | import java.util.ArrayList; |
... | @@ -65,6 +67,7 @@ public class AbstractOpenFlowSwitchTest { | ... | @@ -65,6 +67,7 @@ public class AbstractOpenFlowSwitchTest { |
65 | ofSwitch.executorMsgs = executorService; | 67 | ofSwitch.executorMsgs = executorService; |
66 | Channel channel = new ChannelAdapter(); | 68 | Channel channel = new ChannelAdapter(); |
67 | ofSwitch.setChannel(channel); | 69 | ofSwitch.setChannel(channel); |
70 | + ofSwitch.addEventListener(new OpenFlowEventListenerAdapter()); | ||
68 | } | 71 | } |
69 | 72 | ||
70 | /** | 73 | /** |
... | @@ -120,4 +123,11 @@ public class AbstractOpenFlowSwitchTest { | ... | @@ -120,4 +123,11 @@ public class AbstractOpenFlowSwitchTest { |
120 | public void processDriverHandshakeMessage(OFMessage m) { | 123 | public void processDriverHandshakeMessage(OFMessage m) { |
121 | } | 124 | } |
122 | } | 125 | } |
126 | + | ||
127 | + private class OpenFlowEventListenerAdapter implements OpenFlowEventListener { | ||
128 | + | ||
129 | + @Override | ||
130 | + public void handleMessage(Dpid dpid, OFMessage msg) { | ||
131 | + } | ||
132 | + } | ||
123 | } | 133 | } | ... | ... |
... | @@ -115,6 +115,12 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -115,6 +115,12 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
115 | protected ExecutorService executorMsgs = | 115 | protected ExecutorService executorMsgs = |
116 | Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d")); | 116 | Executors.newFixedThreadPool(32, groupedThreads("onos/of", "event-stats-%d")); |
117 | 117 | ||
118 | + protected ExecutorService executorPacketIn = | ||
119 | + Executors.newCachedThreadPool(groupedThreads("onos/of", "event-pkt-in-stats-%d")); | ||
120 | + | ||
121 | + protected ExecutorService executorFlowRemoved = | ||
122 | + Executors.newCachedThreadPool(groupedThreads("onos/of", "event-flow-removed-stats-%d")); | ||
123 | + | ||
118 | private final ExecutorService executorBarrier = | 124 | private final ExecutorService executorBarrier = |
119 | Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d")); | 125 | Executors.newFixedThreadPool(4, groupedThreads("onos/of", "event-barrier-%d")); |
120 | 126 | ||
... | @@ -133,6 +139,8 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -133,6 +139,8 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
133 | 139 | ||
134 | protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>(); | 140 | protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>(); |
135 | 141 | ||
142 | + protected boolean monitorAllEvents = false; | ||
143 | + | ||
136 | protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats = | 144 | protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats = |
137 | ArrayListMultimap.create(); | 145 | ArrayListMultimap.create(); |
138 | 146 | ||
... | @@ -210,6 +218,11 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -210,6 +218,11 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
210 | } | 218 | } |
211 | 219 | ||
212 | @Override | 220 | @Override |
221 | + public void monitorAllEvents(boolean monitor) { | ||
222 | + this.monitorAllEvents = monitor; | ||
223 | + } | ||
224 | + | ||
225 | + @Override | ||
213 | public void addListener(OpenFlowSwitchListener listener) { | 226 | public void addListener(OpenFlowSwitchListener listener) { |
214 | if (!ofSwitchListener.contains(listener)) { | 227 | if (!ofSwitchListener.contains(listener)) { |
215 | this.ofSwitchListener.add(listener); | 228 | this.ofSwitchListener.add(listener); |
... | @@ -272,13 +285,17 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -272,13 +285,17 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
272 | for (PacketListener p : ofPacketListener.values()) { | 285 | for (PacketListener p : ofPacketListener.values()) { |
273 | p.handlePacket(pktCtx); | 286 | p.handlePacket(pktCtx); |
274 | } | 287 | } |
275 | - executorMsgs.submit(new OFMessageHandler(dpid, msg)); | 288 | + if (monitorAllEvents) { |
289 | + executorPacketIn.submit(new OFMessageHandler(dpid, msg)); | ||
290 | + } | ||
276 | break; | 291 | break; |
277 | // TODO: Consider using separate threadpool for sensitive messages. | 292 | // TODO: Consider using separate threadpool for sensitive messages. |
278 | // ie. Back to back error could cause us to starve. | 293 | // ie. Back to back error could cause us to starve. |
279 | case FLOW_REMOVED: | 294 | case FLOW_REMOVED: |
280 | - executorMsgs.submit(new OFMessageHandler(dpid, msg)); | 295 | + if (monitorAllEvents) { |
281 | - break; | 296 | + executorFlowRemoved.submit(new OFMessageHandler(dpid, msg)); |
297 | + break; | ||
298 | + } | ||
282 | case ERROR: | 299 | case ERROR: |
283 | log.debug("Received error message from {}: {}", dpid, msg); | 300 | log.debug("Received error message from {}: {}", dpid, msg); |
284 | executorMsgs.submit(new OFMessageHandler(dpid, msg)); | 301 | executorMsgs.submit(new OFMessageHandler(dpid, msg)); | ... | ... |
... | @@ -53,7 +53,9 @@ public class OpenFlowControllerImplPacketsTest { | ... | @@ -53,7 +53,9 @@ public class OpenFlowControllerImplPacketsTest { |
53 | OpenFlowSwitch switch1; | 53 | OpenFlowSwitch switch1; |
54 | OpenFlowSwitchListenerAdapter switchListener; | 54 | OpenFlowSwitchListenerAdapter switchListener; |
55 | TestPacketListener packetListener; | 55 | TestPacketListener packetListener; |
56 | - TestExecutorService executorService; | 56 | + TestExecutorService statsExecutorService; |
57 | + TestExecutorService pktInExecutorService; | ||
58 | + TestExecutorService flowRmvExecutorService; | ||
57 | 59 | ||
58 | /** | 60 | /** |
59 | * Mock packet listener that accumulates packets. | 61 | * Mock packet listener that accumulates packets. |
... | @@ -108,12 +110,19 @@ public class OpenFlowControllerImplPacketsTest { | ... | @@ -108,12 +110,19 @@ public class OpenFlowControllerImplPacketsTest { |
108 | agent = controller.agent; | 110 | agent = controller.agent; |
109 | switchListener = new OpenFlowSwitchListenerAdapter(); | 111 | switchListener = new OpenFlowSwitchListenerAdapter(); |
110 | controller.addListener(switchListener); | 112 | controller.addListener(switchListener); |
113 | + controller.monitorAllEvents(true); | ||
111 | 114 | ||
112 | packetListener = new TestPacketListener(); | 115 | packetListener = new TestPacketListener(); |
113 | controller.addPacketListener(100, packetListener); | 116 | controller.addPacketListener(100, packetListener); |
114 | 117 | ||
115 | - executorService = new TestExecutorService(); | 118 | + statsExecutorService = new TestExecutorService(); |
116 | - controller.executorMsgs = executorService; | 119 | + pktInExecutorService = new TestExecutorService(); |
120 | + flowRmvExecutorService = new TestExecutorService(); | ||
121 | + | ||
122 | + controller.executorMsgs = statsExecutorService; | ||
123 | + controller.executorPacketIn = pktInExecutorService; | ||
124 | + controller.executorFlowRemoved = flowRmvExecutorService; | ||
125 | + | ||
117 | } | 126 | } |
118 | 127 | ||
119 | /** | 128 | /** |
... | @@ -151,8 +160,8 @@ public class OpenFlowControllerImplPacketsTest { | ... | @@ -151,8 +160,8 @@ public class OpenFlowControllerImplPacketsTest { |
151 | OFMessage packetInPacket = new MockOfPacketIn(); | 160 | OFMessage packetInPacket = new MockOfPacketIn(); |
152 | controller.processPacket(dpid1, packetInPacket); | 161 | controller.processPacket(dpid1, packetInPacket); |
153 | assertThat(packetListener.contexts(), hasSize(1)); | 162 | assertThat(packetListener.contexts(), hasSize(1)); |
154 | - assertThat(executorService.submittedMessages(), hasSize(1)); | 163 | + assertThat(pktInExecutorService.submittedMessages(), hasSize(1)); |
155 | - assertThat(executorService.submittedMessages().get(0), is(packetInPacket)); | 164 | + assertThat(pktInExecutorService.submittedMessages().get(0), is(packetInPacket)); |
156 | } | 165 | } |
157 | 166 | ||
158 | /** | 167 | /** |
... | @@ -163,8 +172,8 @@ public class OpenFlowControllerImplPacketsTest { | ... | @@ -163,8 +172,8 @@ public class OpenFlowControllerImplPacketsTest { |
163 | agent.addConnectedSwitch(dpid1, switch1); | 172 | agent.addConnectedSwitch(dpid1, switch1); |
164 | OfMessageAdapter errorPacket = new OfMessageAdapter(OFType.ERROR); | 173 | OfMessageAdapter errorPacket = new OfMessageAdapter(OFType.ERROR); |
165 | controller.processPacket(dpid1, errorPacket); | 174 | controller.processPacket(dpid1, errorPacket); |
166 | - assertThat(executorService.submittedMessages(), hasSize(1)); | 175 | + assertThat(statsExecutorService.submittedMessages(), hasSize(1)); |
167 | - assertThat(executorService.submittedMessages().get(0), is(errorPacket)); | 176 | + assertThat(statsExecutorService.submittedMessages().get(0), is(errorPacket)); |
168 | } | 177 | } |
169 | 178 | ||
170 | /** | 179 | /** |
... | @@ -175,7 +184,7 @@ public class OpenFlowControllerImplPacketsTest { | ... | @@ -175,7 +184,7 @@ public class OpenFlowControllerImplPacketsTest { |
175 | agent.addConnectedSwitch(dpid1, switch1); | 184 | agent.addConnectedSwitch(dpid1, switch1); |
176 | OFMessage flowRemovedPacket = new MockOfFlowRemoved(); | 185 | OFMessage flowRemovedPacket = new MockOfFlowRemoved(); |
177 | controller.processPacket(dpid1, flowRemovedPacket); | 186 | controller.processPacket(dpid1, flowRemovedPacket); |
178 | - assertThat(executorService.submittedMessages(), hasSize(1)); | 187 | + assertThat(flowRmvExecutorService.submittedMessages(), hasSize(1)); |
179 | - assertThat(executorService.submittedMessages().get(0), is(flowRemovedPacket)); | 188 | + assertThat(flowRmvExecutorService.submittedMessages().get(0), is(flowRemovedPacket)); |
180 | } | 189 | } |
181 | } | 190 | } | ... | ... |
... | @@ -277,6 +277,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -277,6 +277,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
277 | public void enableCtrlMsgMonitor() { | 277 | public void enableCtrlMsgMonitor() { |
278 | isCtrlMsgMonitor = true; | 278 | isCtrlMsgMonitor = true; |
279 | controller.addEventListener(inMsgListener); | 279 | controller.addEventListener(inMsgListener); |
280 | + controller.monitorAllEvents(isCtrlMsgMonitor); | ||
280 | for (OpenFlowSwitch sw : controller.getSwitches()) { | 281 | for (OpenFlowSwitch sw : controller.getSwitches()) { |
281 | sw.addEventListener(outMsgListener); | 282 | sw.addEventListener(outMsgListener); |
282 | } | 283 | } |
... | @@ -288,6 +289,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -288,6 +289,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
288 | */ | 289 | */ |
289 | public void disableCtrlMsgMonitor() { | 290 | public void disableCtrlMsgMonitor() { |
290 | isCtrlMsgMonitor = false; | 291 | isCtrlMsgMonitor = false; |
292 | + controller.monitorAllEvents(isCtrlMsgMonitor); | ||
291 | controller.removeEventListener(inMsgListener); | 293 | controller.removeEventListener(inMsgListener); |
292 | for (OpenFlowSwitch sw: controller.getSwitches()) { | 294 | for (OpenFlowSwitch sw: controller.getSwitches()) { |
293 | sw.removeEventListener(outMsgListener); | 295 | sw.removeEventListener(outMsgListener); |
... | @@ -343,7 +345,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -343,7 +345,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
343 | @Override | 345 | @Override |
344 | public void handleMessage(Dpid dpid, OFMessage msg) { | 346 | public void handleMessage(Dpid dpid, OFMessage msg) { |
345 | if (isCtrlMsgMonitor) { | 347 | if (isCtrlMsgMonitor) { |
346 | - // TODO: feed the control message stats via ControlMetricsServiceFactory | 348 | + // TODO: handle all incoming OF messages |
347 | } | 349 | } |
348 | } | 350 | } |
349 | } | 351 | } |
... | @@ -356,7 +358,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -356,7 +358,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
356 | @Override | 358 | @Override |
357 | public void handleMessage(Dpid dpid, OFMessage msg) { | 359 | public void handleMessage(Dpid dpid, OFMessage msg) { |
358 | if (isCtrlMsgMonitor) { | 360 | if (isCtrlMsgMonitor) { |
359 | - // TODO: feed the control message stats via ControlMetricsServiceFactory | 361 | + // TODO: handle all outgoing OF messages |
360 | } | 362 | } |
361 | } | 363 | } |
362 | } | 364 | } | ... | ... |
... | @@ -262,6 +262,10 @@ public class OpenFlowDeviceProviderTest { | ... | @@ -262,6 +262,10 @@ public class OpenFlowDeviceProviderTest { |
262 | } | 262 | } |
263 | 263 | ||
264 | @Override | 264 | @Override |
265 | + public void monitorAllEvents(boolean monitor) { | ||
266 | + } | ||
267 | + | ||
268 | + @Override | ||
265 | public void addListener(OpenFlowSwitchListener listener) { | 269 | public void addListener(OpenFlowSwitchListener listener) { |
266 | this.listener = listener; | 270 | this.listener = listener; |
267 | } | 271 | } | ... | ... |
... | @@ -289,6 +289,10 @@ public class OpenFlowGroupProviderTest { | ... | @@ -289,6 +289,10 @@ public class OpenFlowGroupProviderTest { |
289 | return null; | 289 | return null; |
290 | } | 290 | } |
291 | 291 | ||
292 | + @Override | ||
293 | + public void monitorAllEvents(boolean monitor) { | ||
294 | + } | ||
295 | + | ||
292 | } | 296 | } |
293 | 297 | ||
294 | private class TestGroupProviderRegistry implements GroupProviderRegistry { | 298 | private class TestGroupProviderRegistry implements GroupProviderRegistry { | ... | ... |
... | @@ -287,6 +287,10 @@ public class OpenFlowPacketProviderTest { | ... | @@ -287,6 +287,10 @@ public class OpenFlowPacketProviderTest { |
287 | } | 287 | } |
288 | 288 | ||
289 | @Override | 289 | @Override |
290 | + public void monitorAllEvents(boolean monitor) { | ||
291 | + } | ||
292 | + | ||
293 | + @Override | ||
290 | public void addListener(OpenFlowSwitchListener listener) { | 294 | public void addListener(OpenFlowSwitchListener listener) { |
291 | } | 295 | } |
292 | 296 | ... | ... |
-
Please register or login to post a comment