Jian Li
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
...@@ -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
......