Murat Parlakisik
Committed by Gerrit Code Review

Shared system timer and executor services - monitoring

Change-Id: Ieaa889447dbcb78e4d27fe7409fae463177372b8
...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Property; ...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Property;
23 import org.apache.felix.scr.annotations.Reference; 23 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.metrics.MetricsService;
26 import org.onlab.util.SharedExecutors; 27 import org.onlab.util.SharedExecutors;
27 import org.onosproject.app.ApplicationService; 28 import org.onosproject.app.ApplicationService;
28 import org.onosproject.cfg.ComponentConfigService; 29 import org.onosproject.cfg.ComponentConfigService;
...@@ -80,6 +81,9 @@ public class CoreManager implements CoreService { ...@@ -80,6 +81,9 @@ public class CoreManager implements CoreService {
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected EventDeliveryService eventDeliveryService; 82 protected EventDeliveryService eventDeliveryService;
82 83
84 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 + protected MetricsService metricsService;
86 +
83 private static final int DEFAULT_POOL_SIZE = 30; 87 private static final int DEFAULT_POOL_SIZE = 30;
84 @Property(name = "sharedThreadPoolSize", intValue = DEFAULT_POOL_SIZE, 88 @Property(name = "sharedThreadPoolSize", intValue = DEFAULT_POOL_SIZE,
85 label = "Configure shared pool maximum size ") 89 label = "Configure shared pool maximum size ")
...@@ -90,6 +94,12 @@ public class CoreManager implements CoreService { ...@@ -90,6 +94,12 @@ public class CoreManager implements CoreService {
90 label = "Maximum number of millis an event sink has to process an event") 94 label = "Maximum number of millis an event sink has to process an event")
91 private int maxEventTimeLimit = DEFAULT_EVENT_TIME; 95 private int maxEventTimeLimit = DEFAULT_EVENT_TIME;
92 96
97 + private static final boolean DEFAULT_PERFORMANCE_CHECK = false;
98 + @Property(name = "sharedThreadPerformanceCheck", boolValue = DEFAULT_PERFORMANCE_CHECK,
99 + label = "Enable queue performance check on shared pool")
100 + private boolean calculatePoolPerformance = DEFAULT_PERFORMANCE_CHECK;
101 +
102 +
93 @Activate 103 @Activate
94 public void activate() { 104 public void activate() {
95 registerApplication(CORE_APP_NAME); 105 registerApplication(CORE_APP_NAME);
...@@ -177,8 +187,14 @@ public class CoreManager implements CoreService { ...@@ -177,8 +187,14 @@ public class CoreManager implements CoreService {
177 log.warn("maxEventTimeLimit must be greater than 1"); 187 log.warn("maxEventTimeLimit must be greater than 1");
178 } 188 }
179 189
180 - log.info("Settings: sharedThreadPoolSize={}, maxEventTimeLimit={}", 190 + Boolean performanceCheck = isPropertyEnabled(properties, "sharedThreadPerformanceCheck");
181 - sharedThreadPoolSize, maxEventTimeLimit); 191 + if (performanceCheck != null) {
192 + calculatePoolPerformance = performanceCheck;
193 + SharedExecutors.setCalculatePoolPerformance(calculatePoolPerformance, metricsService);
194 + }
195 +
196 + log.info("Settings: sharedThreadPoolSize={}, maxEventTimeLimit={}, calculatePoolPerformance={}",
197 + sharedThreadPoolSize, maxEventTimeLimit, calculatePoolPerformance);
182 } 198 }
183 199
184 200
...@@ -202,5 +218,26 @@ public class CoreManager implements CoreService { ...@@ -202,5 +218,26 @@ public class CoreManager implements CoreService {
202 return value; 218 return value;
203 } 219 }
204 220
221 + /**
222 + * Check property name is defined and set to true.
223 + *
224 + * @param properties properties to be looked up
225 + * @param propertyName the name of the property to look up
226 + * @return value when the propertyName is defined or return null
227 + */
228 + private static Boolean isPropertyEnabled(Dictionary<?, ?> properties,
229 + String propertyName) {
230 + Boolean value = null;
231 + try {
232 + String s = (String) properties.get(propertyName);
233 + value = isNullOrEmpty(s) ? null : s.trim().equals("true");
234 + } catch (ClassCastException e) {
235 + // No propertyName defined.
236 + value = null;
237 + }
238 + return value;
239 + }
240 +
241 +
205 242
206 } 243 }
......
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
15 */ 15 */
16 package org.onlab.util; 16 package org.onlab.util;
17 17
18 +import org.onlab.metrics.MetricsComponent;
19 +import org.onlab.metrics.MetricsFeature;
20 +import org.onlab.metrics.MetricsService;
21 +
18 import java.util.Collection; 22 import java.util.Collection;
19 import java.util.List; 23 import java.util.List;
20 import java.util.concurrent.Callable; 24 import java.util.concurrent.Callable;
...@@ -23,6 +27,9 @@ import java.util.concurrent.ExecutorService; ...@@ -23,6 +27,9 @@ import java.util.concurrent.ExecutorService;
23 import java.util.concurrent.Future; 27 import java.util.concurrent.Future;
24 import java.util.concurrent.TimeUnit; 28 import java.util.concurrent.TimeUnit;
25 import java.util.concurrent.TimeoutException; 29 import java.util.concurrent.TimeoutException;
30 +import com.codahale.metrics.Timer;
31 +
32 +
26 33
27 /** 34 /**
28 * Executor service wrapper for shared executors with safeguards on shutdown 35 * Executor service wrapper for shared executors with safeguards on shutdown
...@@ -34,6 +41,13 @@ class SharedExecutorService implements ExecutorService { ...@@ -34,6 +41,13 @@ class SharedExecutorService implements ExecutorService {
34 41
35 private ExecutorService executor; 42 private ExecutorService executor;
36 43
44 + private MetricsService metricsService = null;
45 +
46 + private MetricsComponent executorMetrics;
47 + private Timer queueMetrics = null;
48 + private Timer delayMetrics = null;
49 +
50 +
37 /** 51 /**
38 * Creates a wrapper for the given executor service. 52 * Creates a wrapper for the given executor service.
39 * 53 *
...@@ -63,6 +77,7 @@ class SharedExecutorService implements ExecutorService { ...@@ -63,6 +77,7 @@ class SharedExecutorService implements ExecutorService {
63 oldExecutor.shutdown(); 77 oldExecutor.shutdown();
64 } 78 }
65 79
80 +
66 @Override 81 @Override
67 public void shutdown() { 82 public void shutdown() {
68 throw new UnsupportedOperationException(NOT_ALLOWED); 83 throw new UnsupportedOperationException(NOT_ALLOWED);
...@@ -91,7 +106,31 @@ class SharedExecutorService implements ExecutorService { ...@@ -91,7 +106,31 @@ class SharedExecutorService implements ExecutorService {
91 106
92 @Override 107 @Override
93 public <T> Future<T> submit(Callable<T> task) { 108 public <T> Future<T> submit(Callable<T> task) {
94 - return executor.submit(task); 109 + Counter taskCounter = new Counter();
110 + taskCounter.reset();
111 + return executor.submit(() -> {
112 + T t = null;
113 + long queueWaitTime = (long) taskCounter.duration();
114 + String className;
115 + if (task instanceof CallableExtended) {
116 + className = ((CallableExtended) task).getRunnable().getClass().toString();
117 + } else {
118 + className = task.getClass().toString();
119 + }
120 + if (queueMetrics != null) {
121 + queueMetrics.update(queueWaitTime, TimeUnit.SECONDS);
122 + }
123 + taskCounter.reset();
124 + try {
125 + t = task.call();
126 + } catch (Exception e) { }
127 + long taskwaittime = (long) taskCounter.duration();
128 + if (delayMetrics != null) {
129 + delayMetrics.update(taskwaittime, TimeUnit.SECONDS);
130 + }
131 + return t;
132 + }
133 + );
95 } 134 }
96 135
97 @Override 136 @Override
...@@ -135,4 +174,47 @@ class SharedExecutorService implements ExecutorService { ...@@ -135,4 +174,47 @@ class SharedExecutorService implements ExecutorService {
135 executor.execute(command); 174 executor.execute(command);
136 } 175 }
137 176
177 + public void setCalculatePoolPerformance(boolean calculatePoolPerformance, MetricsService metricsSrv) {
178 + this.metricsService = metricsSrv;
179 + if (calculatePoolPerformance) {
180 + if (metricsService != null) {
181 + executorMetrics = metricsService.registerComponent("SharedExecutor");
182 + MetricsFeature mf = executorMetrics.registerFeature("*");
183 + queueMetrics = metricsService.createTimer(executorMetrics, mf, "Queue");
184 + delayMetrics = metricsService.createTimer(executorMetrics, mf, "Delay");
185 + }
186 + } else {
187 + metricsService = null;
188 + queueMetrics = null;
189 + delayMetrics = null;
190 + }
191 + }
192 +
193 + /**
194 + * CallableExtended class is used to get Runnable Object
195 + * from Callable Object.
196 + *
197 + */
198 + class CallableExtended implements Callable {
199 +
200 + private Runnable runnable;
201 +
202 + /**
203 + * Wrapper for Callable object .
204 + * @param runnable Runnable object
205 + */
206 + public CallableExtended(Runnable runnable) {
207 + this.runnable = runnable;
208 + }
209 + public Runnable getRunnable() {
210 + return runnable;
211 + }
212 +
213 + @Override
214 + public Object call() throws Exception {
215 + runnable.run();
216 + return null;
217 + }
218 + }
219 +
138 } 220 }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 16
17 package org.onlab.util; 17 package org.onlab.util;
18 18
19 +import org.onlab.metrics.MetricsService;
20 +
19 import java.util.Timer; 21 import java.util.Timer;
20 import java.util.concurrent.ExecutorService; 22 import java.util.concurrent.ExecutorService;
21 23
...@@ -93,6 +95,11 @@ public final class SharedExecutors { ...@@ -93,6 +95,11 @@ public final class SharedExecutors {
93 "onos-pool-executor-%d"))); 95 "onos-pool-executor-%d")));
94 } 96 }
95 97
98 +
99 + public static void setCalculatePoolPerformance(boolean calculatePoolPerformance, MetricsService metricsService) {
100 + poolThreadExecutor.setCalculatePoolPerformance(calculatePoolPerformance, metricsService);
101 + }
102 +
96 /** 103 /**
97 * Shuts down all shared timers and executors and therefore should be 104 * Shuts down all shared timers and executors and therefore should be
98 * called only by the framework. 105 * called only by the framework.
......