1616
1717import org .jboss .byteman .rule .Rule ;
1818import org .jboss .byteman .rule .helper .Helper ;
19- import org .jboss .byteman .rule .Action ;
2019
21- import java .nio .ByteBuffer ;
22- import java .io .StringWriter ;
23- import java .lang .reflect .Method ;
2420import java .util .concurrent .locks .ReentrantLock ;
25- import java .util .regex .Matcher ;
26- import java .util .regex .Pattern ;
2721
2822
2923public class StressHelper extends Helper
3024{
31- static HashMap <String , Stress > stresses = new HashMap <String , Stress >();
25+ static HashMap <String , Stress > stresses = new HashMap <>();
3226
3327 protected StressHelper (Rule rule ) {
3428 super (rule );
@@ -37,6 +31,11 @@ protected StressHelper(Rule rule) {
3731 public static void uninstalled (Rule rule )
3832 {
3933 Stress stress = stresses .get (rule .getName ());
34+ if (stress == null )
35+ {
36+ Helper .verbose ("Stress reference not found for rule " + rule .getName () + ". All keys: " + stresses .keySet ());
37+ return ;
38+ }
4039 stress .quit ();
4140 stresses .remove (rule .getName ());
4241 }
@@ -66,6 +65,20 @@ public void injectMemStress(String name, String memType)
6665 stresses .put (name , stress );
6766 stress .load ();
6867 }
68+
69+ public void injectLimitedMemStress (String name , String memType , String heapMemoryUsage )
70+ {
71+ Stress stress = stresses .get (name );
72+ if (stress != null )
73+ {
74+ return ;
75+ }
76+
77+ stress = new MemoryStress (name , memType , heapMemoryUsage );
78+ stresses .put (name , stress );
79+ stress .load ();
80+ }
81+
6982}
7083
7184/*
@@ -87,7 +100,7 @@ class CPUStress implements Stress {
87100 CPUStress (String name , int cpuCount ) {
88101 this .name = name ;
89102 this .cpuCount = cpuCount ;
90- threads = new ArrayList <CPUStressThread >();
103+ threads = new ArrayList <>();
91104 }
92105
93106 public void load () {
@@ -108,47 +121,86 @@ public void quit() {
108121class MemoryStress implements Stress {
109122 private String name ;
110123 private String type ;
124+ private String heapStressPercentage ;
111125 private MemoryStressThread thread ;
112126
113127 MemoryStress (String name , String type ) {
128+ this (name , type , null );
129+ }
130+
131+ MemoryStress (String name , String type , String heapStressPercentage ) {
114132 this .name = name ;
115133 this .type = type ;
134+ this .heapStressPercentage = heapStressPercentage ;
116135 }
117136
118137 public void load () {
119- thread = new MemoryStressThread (name , type );
138+ Long heapMemoryToBeUsedUp = getMaxHeapUsageRequested ();
139+ thread = new MemoryStressThread (name , type , heapMemoryToBeUsedUp );
120140 thread .start ();
121141 }
122142
143+ private Long getMaxHeapUsageRequested () {
144+ if (heapStressPercentage == null ) {
145+ return null ;
146+ }
147+
148+ Double heapStressPercentageDouble = null ;
149+ Long heapMemoryToBeUsedUp = null ;
150+ long maxMemory = Runtime .getRuntime ().maxMemory ();
151+ if (heapStressPercentage .endsWith ("%" )) {
152+ heapStressPercentageDouble = Double .parseDouble (heapStressPercentage .substring (0 , heapStressPercentage .length () - 1 ));
153+ } else if (heapStressPercentage .toLowerCase ().endsWith ("mb" ) || heapStressPercentage .toLowerCase ().endsWith ("gb" )) {
154+ String unit = heapStressPercentage .substring (heapStressPercentage .length () - 2 ).toLowerCase ();
155+ double value = Double .parseDouble (heapStressPercentage .substring (0 , heapStressPercentage .length () - 2 ));
156+ if (unit .equals ("mb" )) {
157+ heapMemoryToBeUsedUp = (long )(value * 1024 * 1024 );
158+ } else if (unit .equals ("gb" )) {
159+ heapMemoryToBeUsedUp = (long )(value * 1024 * 1024 * 1024 );
160+ }
161+ } else if (heapStressPercentage .contains ("." )) {
162+ try {
163+ heapStressPercentageDouble = Double .parseDouble (heapStressPercentage );
164+ } catch (NumberFormatException e ) {
165+ Helper .verbose ("Failed to parse heapStressPercentage: " + heapStressPercentage );
166+ }
167+ } else {
168+ Helper .verbose ("Failed to parse heapStressPercentage: " + heapStressPercentage + ". Some examples that should work: 50%, 100MB, 1GB, 0.5" );
169+ }
170+ if (heapMemoryToBeUsedUp == null && heapStressPercentageDouble != null ) {
171+ heapMemoryToBeUsedUp = (long )(maxMemory * heapStressPercentageDouble );
172+ }
173+
174+ return heapMemoryToBeUsedUp ;
175+ }
176+
123177 public void quit () {
124178 thread .shutdown ();
125179 }
126180}
127181
128182interface StressRunnable extends Runnable {
129-
130- public void shutdown ();
131183}
132184
133185class CPUStressThread implements StressRunnable {
134186 private Thread t ;
135187 private String threadName ;
136188 private boolean flag ;
137-
189+
138190 private ReentrantLock lock = new ReentrantLock ();
139-
191+
140192 CPUStressThread ( String name ) {
141193 threadName = name ;
142194 flag = true ;
143195 Helper .verbose ("Creating thread " + threadName );
144196 }
145-
197+
146198 public void run () {
147199 Helper .verbose ("Running thread " + threadName );
148-
200+
149201 while (true ) {
150202 lock .lock ();
151- boolean exit = !flag ;
203+ boolean exit = !flag ;
152204 lock .unlock ();
153205 if (exit ) {
154206 break ;
@@ -157,10 +209,10 @@ public void run() {
157209
158210 Helper .verbose ("Exiting thread " + threadName );
159211 }
160-
212+
161213 public void start () {
162214 Helper .verbose ("Starting thread " + threadName );
163-
215+
164216 if (t == null ) {
165217 t = new Thread (this , threadName );
166218 t .start ();
@@ -180,27 +232,38 @@ class MemoryStressThread implements StressRunnable {
180232 private String threadName ;
181233 private boolean flag ;
182234 private String type ;
235+ private Long heapMemoryToBeUsedUp ;
183236
184237 private ReentrantLock lock = new ReentrantLock ();
185238
186- MemoryStressThread (String name , String type ) {
239+ MemoryStressThread (String name , String type , Long heapMemoryToBeUsedUp ) {
187240 threadName = name ;
188241 this .type = type ;
242+ this .heapMemoryToBeUsedUp = heapMemoryToBeUsedUp ;
189243 flag = true ;
190- Helper .verbose ("Creating thread " + threadName + ", type " + type );
244+ Helper .verbose ("Creating thread " + threadName + ", type " + type + ", heapMemoryToBeUsedUp " + heapMemoryToBeUsedUp + ", maxHeapSize " + Runtime .getRuntime ().maxMemory ());
245+ }
246+
247+ MemoryStressThread (String name , String type ) {
248+ this (name , type , null );
191249 }
192250
193251 public void run () {
194252 Helper .verbose ("Running thread " + threadName );
195- ArrayList <String > increaseSizeData = new ArrayList < String >();
196- ArrayList <ThreadTask > threadTasks = new ArrayList <ThreadTask >();
253+ List <String > increaseSizeData = new LinkedList < >();
254+ ArrayList <ThreadTask > threadTasks = new ArrayList <>();
197255 boolean oom = false ;
198256
257+ logMemoryStats ();
258+ long iteration = 0 ;
259+ long logIntervalIteration = 100000 ;
199260 while (true ) {
261+ iteration ++;
200262 lock .lock ();
201263 boolean exit = !flag ;
202264 lock .unlock ();
203265 if (exit ) {
266+ Helper .verbose ("stop memory stress thread, exit condition reached" );
204267 increaseSizeData = null ;
205268 for (int i = 0 ; i < threadTasks .size (); i ++) {
206269 threadTasks .get (i ).setStop (true );
@@ -210,18 +273,30 @@ public void run() {
210273 }
211274
212275 if (oom ) {
276+ Helper .verbose ("oom condition reached, pause a little - 500ms" );
213277 try {
214278 Thread .sleep (500 );
215279 } catch (Exception e ) {
216280 Helper .verbose ("exception: " + e );
217281 }
218282 } else {
219283 if (this .type .equals ("heap" )) {
220- try {
221- increaseSizeData .add ("123456" );
222- } catch (OutOfMemoryError e ) {
223- oom = true ;
224- Helper .verbose ("exception: " + e );
284+ if (shouldAddMoreHeapMemoryLoad (heapMemoryToBeUsedUp )) {
285+ logMemoryStatsIfIntervalReached (iteration , logIntervalIteration );
286+ try {
287+ increaseSizeData .add ("123456" );
288+ } catch (OutOfMemoryError e ) {
289+ oom = true ;
290+ Helper .verbose ("exception: " + e );
291+ }
292+ } else {
293+ Helper .verbose ("heap memory fill condition reached, pause a little - 5000ms" );
294+ logMemoryStats ();
295+ try {
296+ Thread .sleep (5000 );
297+ } catch (Exception e ) {
298+ Helper .verbose ("exception: " + e );
299+ }
225300 }
226301 } else if (this .type .equals ("stack" )) {
227302 try {
@@ -240,10 +315,34 @@ public void run() {
240315
241316 Helper .verbose ("Exiting thread " + threadName );
242317 }
243-
244- public void start () {
318+
319+ private void logMemoryStats () {
320+ logMemoryStatsIfIntervalReached (1 , 1 );
321+ }
322+
323+ private void logMemoryStatsIfIntervalReached (long iteration , long logIntervalIteration ) {
324+ if (iteration % logIntervalIteration == 0 ) {
325+ long maxHeapSize = Runtime .getRuntime ().maxMemory ();
326+ long freeHeapSize = Runtime .getRuntime ().freeMemory ();
327+ long totalHeapSize = Runtime .getRuntime ().totalMemory ();
328+ Helper .verbose ("heap memory stats: maxHeapSize " + maxHeapSize + ", freeHeapSize " + freeHeapSize + ", totalHeapSize " + totalHeapSize + ", heapMemoryToBeUsedUp " + heapMemoryToBeUsedUp + "; iteration " + iteration );
329+ }
330+ }
331+
332+ boolean shouldAddMoreHeapMemoryLoad (Long heapMemoryToBeUsedUp ) {
333+ if (heapMemoryToBeUsedUp == null || heapMemoryToBeUsedUp < 0 ) {
334+ return true ;
335+ }
336+
337+ long currentHeapSize = Runtime .getRuntime ().totalMemory ();
338+ long freeHeapSize = Runtime .getRuntime ().freeMemory ();
339+
340+ return heapMemoryToBeUsedUp > (currentHeapSize - freeHeapSize );
341+ }
342+
343+ public void start () {
245344 Helper .verbose ("Starting thread " + threadName );
246-
345+
247346 if (t == null ) {
248347 t = new Thread (this , threadName );
249348 t .start ();
0 commit comments