001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.runtime;
006:
007: import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
008:
009: import com.tc.lang.TCThreadGroup;
010: import com.tc.lang.ThrowableHandler;
011: import com.tc.logging.TCLogging;
012: import com.tc.test.TCTestCase;
013: import com.tc.util.concurrent.ThreadUtil;
014:
015: import java.util.Vector;
016:
017: public class TCMemoryManagerImplTest extends TCTestCase implements
018: MemoryEventsListener {
019:
020: int usedThreshold = 70;
021: int usedCriticalThreshold = 90;
022: long sleepInterval = 50;
023: int lc = 2;
024: SynchronizedInt callCount = new SynchronizedInt(0);
025:
026: Vector v = new Vector();
027: private int lastCall;
028: private boolean lastIsBelowThreshold = false;
029: private Vector errors = new Vector();
030:
031: public void test() throws Throwable {
032: TCMemoryManager mm = new TCMemoryManagerImpl(usedThreshold,
033: usedCriticalThreshold, sleepInterval, lc, true,
034: new TCThreadGroup(new ThrowableHandler(TCLogging
035: .getLogger(TCMemoryManagerImplTest.class))));
036: mm.registerForMemoryEvents(this );
037: try {
038: hogMemory();
039: } catch (Throwable e) {
040: System.err.println("Got Exception : " + e);
041: printStats();
042: e.printStackTrace();
043: throw e;
044: }
045: assertTrue(callCount.get() > 0);
046: if (errors.size() > 0) {
047: System.err.println("Errors present in the run : "
048: + errors.size());
049: System.err.println("Errors = " + errors);
050: Throwable t = (Throwable) errors.get(0);
051: throw t;
052: }
053: }
054:
055: private void printStats() {
056: System.err.println("Vector size = " + v.size());
057: Runtime r = Runtime.getRuntime();
058: System.err.println("Memory details = Max = " + r.maxMemory()
059: + " Free =" + r.freeMemory());
060: }
061:
062: private void hogMemory() {
063: for (int i = 1; i < 500000; i++) {
064: byte[] b = new byte[10240];
065: v.add(b);
066: if (i % 10000 == 0) {
067: System.err.println("Created " + i
068: + " byte arrays - currently in vector = "
069: + v.size());
070: }
071: if (i % 50 == 0) {
072: ThreadUtil.reallySleep(1);
073: }
074: }
075: }
076:
077: public void memoryUsed(MemoryEventType type, MemoryUsage usage) {
078: int usedPercentage = usage.getUsedPercentage();
079: if (callCount.increment() % 10 == 1
080: || type == MemoryEventType.ABOVE_CRITICAL_THRESHOLD) {
081: System.err.println("Current used memory % : "
082: + usedPercentage + " vector size = " + v.size());
083: }
084:
085: if (this .usedThreshold > usedPercentage) {
086: if (type != MemoryEventType.BELOW_THRESHOLD) {
087: errors.add(new AssertionError(
088: "Used Percentage reported (" + usedPercentage
089: + ") is less than Used threshold ("
090: + usedThreshold + ") set, but type is "
091: + type));
092: } else if (lastIsBelowThreshold) {
093: errors
094: .add(new AssertionError(
095: type
096: + " is reported more often than it should be. Used % is "
097: + usedPercentage));
098: }
099: lastIsBelowThreshold = true;
100: this .lastCall = 0;
101: } else {
102: lastIsBelowThreshold = false;
103: }
104:
105: if (type == MemoryEventType.ABOVE_CRITICAL_THRESHOLD
106: && this .usedCriticalThreshold > usedPercentage) {
107: errors.add(new AssertionError(
108: "Received CRITICAL event with used < critical threshold : "
109: + usedPercentage + " < "
110: + this .usedCriticalThreshold));
111: } else if (type == MemoryEventType.ABOVE_THRESHOLD
112: && this .usedCriticalThreshold < usedPercentage) {
113: errors.add(new AssertionError(
114: "Received NORMAL event with used > critical threshold : "
115: + usedPercentage + " > "
116: + this .usedCriticalThreshold));
117: } else {
118: this .lastCall = 0;
119: }
120:
121: if (type == MemoryEventType.ABOVE_THRESHOLD) {
122: if (this .lastCall == usedPercentage) {
123: errors.add(new AssertionError(
124: "Recd two callbacks with same value ("
125: + usedPercentage + ")"));
126: } else if (Math.abs(this .lastCall - usedPercentage) < lc) {
127: errors.add(new AssertionError(
128: "Recd two callbacks with values less that least count ("
129: + usedPercentage + " , " + lastCall
130: + ") - LC = " + lc));
131: }
132: this .lastCall = usedPercentage;
133: }
134: releaseSomeMemory(usedPercentage);
135: }
136:
137: // Releases 10 % of the elements in the vector for 70 % used
138: private void releaseSomeMemory(int used) {
139: if (used < usedThreshold) {
140: return;
141: } else if (used > 90) {
142: v.clear();
143: return;
144: }
145: int percentToDelete = (100 - used) * 4;
146: synchronized (v) {
147: int toRemove = Math.min(v.size() * percentToDelete / 100, v
148: .size());
149: for (int i = 0; i < toRemove; i++) {
150: v.remove(v.size() - 1);
151: }
152: }
153: }
154:
155: }
|