Skip to content

Commit 5ab92aa

Browse files
author
Matej Korosec
committed
BytemanHelper memory stress: add ability to define how much heap memory is used
Signed-off-by: Matej Korosec <ce-matej.korosec@beyondnow.com>
1 parent 1f69bf0 commit 5ab92aa

File tree

1 file changed

+129
-30
lines changed

1 file changed

+129
-30
lines changed

BytemanHelper/src/main/java/org/chaos_mesh/byteman/helper/StressHelper.java

Lines changed: 129 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,13 @@
1616

1717
import org.jboss.byteman.rule.Rule;
1818
import 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;
2420
import java.util.concurrent.locks.ReentrantLock;
25-
import java.util.regex.Matcher;
26-
import java.util.regex.Pattern;
2721

2822

2923
public 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() {
108121
class 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

128182
interface StressRunnable extends Runnable {
129-
130-
public void shutdown();
131183
}
132184

133185
class 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

Comments
 (0)