Implemented a Performance Counter class
This commit is contained in:
parent
8ce73e3f50
commit
d2ea0e32bd
3 changed files with 320 additions and 1 deletions
|
|
@ -169,7 +169,8 @@ public class ClassUtil {
|
|||
* @return the first class in the stack that do not match the filter
|
||||
*/
|
||||
public static String getCallingClass(Class... filter){
|
||||
ArrayList filterStr = new ArrayList();
|
||||
ArrayList filterStr = new ArrayList(filter.length + 1);
|
||||
filterStr.add(ClassUtil.class.getName());
|
||||
for (Class clazz : filter)
|
||||
filterStr.add(clazz.getName());
|
||||
|
||||
|
|
|
|||
170
src/zutil/log/CounterManager.java
Normal file
170
src/zutil/log/CounterManager.java
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package zutil.log;
|
||||
|
||||
import zutil.ClassUtil;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* This class is used for performance measurements on an application.
|
||||
* The counter values will be published in JMX and can be viewed in JConsole.
|
||||
*/
|
||||
public class CounterManager {
|
||||
/** a two dimensional map [Class][Counter ID] for storing singleton objects **/
|
||||
private static HashMap<String, HashMap<String, Counter>> counters = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @param name a unique name/id of the counter
|
||||
* @return a singleton instance of the counter name with the calling class as context. Will always return a valid object.
|
||||
*/
|
||||
public static Counter getCounter(String name) {
|
||||
return getCounter(ClassUtil.getCallingClass(CounterManager.class), name);
|
||||
}
|
||||
/**
|
||||
* @param clazz the counter context
|
||||
* @param name a unique name/id of the counter
|
||||
* @return a singleton instance of the counter name. Will always return a valid object.
|
||||
*/
|
||||
public static Counter getCounter(Class clazz, String name) {
|
||||
return getCounter(clazz.getName(), name);
|
||||
}
|
||||
private static synchronized Counter getCounter(String clazz, String name) {
|
||||
Counter counter;
|
||||
if ( ! counters.containsKey(clazz) || ! counters.get(clazz).containsKey(name)) {
|
||||
// Get the platform MBeanServer
|
||||
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
||||
// Unique identification of MBeans
|
||||
counter = new Counter(name);
|
||||
|
||||
try {
|
||||
// Uniquely identify the MBeans and register them with the platform MBeanServer
|
||||
ObjectName objectName = new ObjectName(clazz + ":name=" + counter.getName());
|
||||
mbs.registerMBean(counter, objectName);
|
||||
// Register the singleton
|
||||
if ( ! counters.containsKey(clazz))
|
||||
counters.put(clazz, new HashMap<String, Counter>());
|
||||
counters.get(clazz).put(name, counter);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
counter = counters.get(clazz).get(name);
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MBean Counter definition for publishing data in JMX
|
||||
*/
|
||||
public interface CounterMBean {
|
||||
String getName();
|
||||
|
||||
int getValue();
|
||||
int getMax();
|
||||
int getMin();
|
||||
double getAverage();
|
||||
}
|
||||
|
||||
|
||||
public static class Counter implements CounterMBean{
|
||||
private final String name;
|
||||
private int max;
|
||||
private int min;
|
||||
private double average;
|
||||
private int sampleCount;
|
||||
private AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
|
||||
protected Counter(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public void add(int i){
|
||||
int prev = counter.getAndAdd(i);
|
||||
updateMetaData(prev + i);
|
||||
}
|
||||
public void set(int i){
|
||||
counter.getAndSet(i);
|
||||
updateMetaData(i);
|
||||
}
|
||||
public void increment(){
|
||||
int i = counter.incrementAndGet();
|
||||
updateMetaData(i);
|
||||
}
|
||||
public void decrement(){
|
||||
int i = counter.decrementAndGet();
|
||||
updateMetaData(i);
|
||||
}
|
||||
private void updateMetaData(int i){
|
||||
if (max < i)
|
||||
max = i;
|
||||
if (min > i)
|
||||
min = i;
|
||||
|
||||
average = (average*sampleCount + i) / ++sampleCount;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @return current value of the counter
|
||||
*/
|
||||
@Override
|
||||
public int getValue(){
|
||||
return counter.intValue();
|
||||
}
|
||||
/**
|
||||
* @return the maximum registered value over the lifetime of the counter
|
||||
*/
|
||||
@Override
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
/**
|
||||
* @return the minimum registered value over the lifetime of the counter
|
||||
*/
|
||||
@Override
|
||||
public int getMin() {
|
||||
return min;
|
||||
}
|
||||
/**
|
||||
* @return the average value of the counter
|
||||
*/
|
||||
@Override
|
||||
public double getAverage() {
|
||||
return average;
|
||||
}
|
||||
}
|
||||
}
|
||||
148
test/zutil/log/CounterManagerTest.java
Normal file
148
test/zutil/log/CounterManagerTest.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package zutil.log;
|
||||
|
||||
import org.junit.Test;
|
||||
import zutil.log.CounterManager.Counter;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class CounterManagerTest {
|
||||
|
||||
@Test
|
||||
public void singletonTest(){
|
||||
Counter c1 = CounterManager.getCounter("TestCounter");
|
||||
Counter c2 = CounterManager.getCounter("TestCounter");
|
||||
assertSame(c1, c2);
|
||||
|
||||
c1 = CounterManager.getCounter("TestCounter");
|
||||
c2 = CounterManager.getCounter(CounterManagerTest.class, "TestCounter");
|
||||
assertSame(c1, c2);
|
||||
|
||||
c1 = CounterManager.getCounter(CounterManagerTest.class, "TestCounter");
|
||||
c2 = CounterManager.getCounter(CounterManagerTest.class, "TestCounter");
|
||||
assertSame(c1, c2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addTest(){
|
||||
Counter c1 = CounterManager.getCounter("AddTestCounter");
|
||||
assertEquals(0, c1.getValue());
|
||||
|
||||
c1.add(10);
|
||||
assertEquals(10, c1.getValue());
|
||||
|
||||
c1.add(20);
|
||||
c1.add(30);
|
||||
assertEquals(60, c1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setTest(){
|
||||
Counter c1 = CounterManager.getCounter("SetTestCounter");
|
||||
assertEquals(0, c1.getValue());
|
||||
|
||||
c1.set(10);
|
||||
assertEquals(10, c1.getValue());
|
||||
|
||||
c1.set(20);
|
||||
c1.set(30);
|
||||
assertEquals(30, c1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementTest(){
|
||||
Counter c1 = CounterManager.getCounter("IncrementTestCounter");
|
||||
assertEquals(0, c1.getValue());
|
||||
|
||||
c1.increment();
|
||||
assertEquals(1, c1.getValue());
|
||||
|
||||
c1.increment();
|
||||
c1.increment();
|
||||
c1.increment();
|
||||
assertEquals(4, c1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementTest(){
|
||||
Counter c1 = CounterManager.getCounter("DecrementTestCounter");
|
||||
assertEquals(0, c1.getValue());
|
||||
|
||||
c1.decrement();
|
||||
assertEquals(-1, c1.getValue());
|
||||
|
||||
c1.decrement();
|
||||
c1.decrement();
|
||||
c1.decrement();
|
||||
assertEquals(-4, c1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void maxTest(){
|
||||
Counter c1 = CounterManager.getCounter("MaxTestCounter");
|
||||
assertEquals(0, c1.getMax());
|
||||
|
||||
c1.set(10);
|
||||
assertEquals(10, c1.getMax());
|
||||
|
||||
c1.set(50);
|
||||
assertEquals(50, c1.getMax());
|
||||
|
||||
c1.set(0);
|
||||
assertEquals(50, c1.getMax());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minTest(){
|
||||
Counter c1 = CounterManager.getCounter("MinTestCounter");
|
||||
assertEquals(0, c1.getMin());
|
||||
|
||||
c1.set(10);
|
||||
assertEquals(0, c1.getMin());
|
||||
|
||||
c1.set(-50);
|
||||
assertEquals(-50, c1.getMin());
|
||||
|
||||
c1.set(0);
|
||||
assertEquals(-50, c1.getMin());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void averageTest(){
|
||||
Counter c1 = CounterManager.getCounter("MinTestCounter");
|
||||
assertEquals(0, (int)c1.getAverage());
|
||||
|
||||
c1.set(10);
|
||||
assertEquals(10, (int)c1.getAverage());
|
||||
|
||||
c1.set(10);
|
||||
assertEquals(10, (int)c1.getAverage());
|
||||
|
||||
c1.set(70);
|
||||
assertEquals(30, (int)c1.getAverage());
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue