Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

using semaphores in jmeter (block critical regions) #2012

Closed
asfimport opened this issue Sep 13, 2007 · 5 comments
Closed

using semaphores in jmeter (block critical regions) #2012

asfimport opened this issue Sep 13, 2007 · 5 comments

Comments

@asfimport
Copy link
Collaborator

Christoph (Bug 43384):
hi,

in our testplans, we needed a sort of "semaphore" mechanism, e.g.:

  • we have problems if more than 10 parallel logins to our webapp exists
  • we have a lot of threads that create, rename and delete channels. one thread
    can delete a channel that another thread tries to rename.

these are only 2 examples, but since we implemented this controller, we use it
very often.

for this improvement, JMeterUtils.java has methods for acquiring and releasing
semaphores. StandardJMeterEngine.java was patched to clear all semaphores when
starting a test (if someone stops the test and there exists a sempaphore that
was not released). Moreover, JMeterThread.java was patched, that all semaphores
in a threadgroup are released if the scheduler stops the test (before releasing
the semaphore with a sampler).

acquiring and releasing a semaphore can be either done by calling the 2 methods
acquireSemaphore and releaseSemaphore, or by using the 2 samplers that come
with the patch (Java Request). If you are interested in this Feature, i would
implement a SemaphoreSampler with a nice GUI :)

The sampler works like this:
With the "AcquireSemaphore" sampler, you can define the begin of the critical
region by calling the acquireSemaphore-function. It acquires the given number
of permits (count-parameter) from this semaphore, blocking until all are
available. When leaving the critical region, use the ReleaseSemaphore sampler
with the unique semaphore name as parameter.
setting the "count" parameter to "1" would cause this sampler to work like
a "mutex".

Semaphores are supported since Java 1.5, so the build script has to be updated
to build JMeter with Java Version 1.5.

greets,
chris

Votes in Bugzilla: 1
OS: other

Duplicates:

Duplicated by:

@asfimport
Copy link
Collaborator Author

Christoph (migrated from Bugzilla):
Created attachment jakarta-jmeter-2.3_Semaphores.java.patch: semaphore addon

jakarta-jmeter-2.3_Semaphores.java.patch
Index: jakarta-jmeter-2.3/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java
===================================================================
--- jakarta-jmeter-2.3/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java	(revision 1)
+++ jakarta-jmeter-2.3/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java	(working copy)
@@ -313,6 +313,9 @@
 		if (((TestPlan) plan[0]).isSerialized()) {
 			serialized = true;
 		}
+		
+		JMeterUtils.clearSemaphores();
+		
         JMeterContextService.startTest();
         try {
         	compileTree();
         	
Index: jakarta-jmeter-2.3/src/core/org/apache/jmeter/threads/JMeterThread.java
===================================================================
--- jakarta-jmeter-2.3/src/core/org/apache/jmeter/threads/JMeterThread.java	(revision 1)
+++ jakarta-jmeter-2.3/src/core/org/apache/jmeter/threads/JMeterThread.java	(working copy)
@@ -195,6 +195,8 @@
 		long delay = System.currentTimeMillis() - endTime;
 		if ((delay >= 0)) {
 			running = false;
+			//release all semaphores of threadgroup
+			org.apache.jmeter.util.JMeterUtils.releaseSemaphoresForThreadGroup(threadGroup.getName());
 		}
 	}
 
Index: jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/JMeterUtils.java
===================================================================
--- jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/JMeterUtils.java	(revision 1)
+++ jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/JMeterUtils.java	(working copy)
@@ -38,7 +38,11 @@
 import java.util.ResourceBundle;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.util.ArrayList;
 
+import java.util.concurrent.Semaphore;
+import java.util.HashMap;
+
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
@@ -86,6 +90,63 @@
 	// Provide Random numbers to whomever wants one
 	private static Random rand = new Random();
 
+	// Provide a means to synchronize threads
+	private static HashMap<String, Pair> semaphores = new HashMap<String, Pair>();
+
+	public static void releaseAllSemaphores() {
+		Iterator it = semaphores.values().iterator();
+		//iterate trough hashmap and release all semaphores of current threadgroup
+		while (it.hasNext()) {
+			Pair pair = (Pair)it.next();
+			Semaphore sem = (Semaphore)pair.second;	
+			if (sem != null) {
+				sem.release();
+			}			
+		}
+	}
+
+	public static void releaseSemaphoresForThreadGroup(String tgroup) {
+		Iterator it = semaphores.values().iterator();
+		//iterate trough hashmap and release all semaphores of current threadgroup
+		while (it.hasNext()) {
+			Pair pair = (Pair)it.next();
+			Semaphore sem = (Semaphore)pair.second;
+			ArrayList al = (ArrayList)pair.first;
+			if (al.contains(tgroup)) {
+				if (sem != null) {
+					sem.release();
+				}
+			} 
+		}
+	}
+
+	public static void acquireSemaphore(String name, String tgroup, int count) throws java.lang.InterruptedException {
+		Pair pair = semaphores.get(name);
+		if (pair == null) {
+			//create arraylist with one element (name of threadgroup)
+			ArrayList al = new ArrayList();
+			al.add(tgroup);
+			pair = new Pair(al, new Semaphore(count, true));
+			semaphores.put(name, pair);
+		} else {
+			//add threadgroup-name to arraylist
+			((ArrayList)pair.first).add(tgroup);	
+		}
+		((Semaphore)pair.second).acquire();
+	}
+	
+	public static void releaseSemaphore(String name)  {
+		Pair pair = (Pair)semaphores.get(name);
+		Semaphore sem = (Semaphore)pair.second;
+		if (sem != null) {
+			sem.release();
+		}
+	}
+	
+	public static void clearSemaphores() {
+		semaphores.clear();
+	}
+
 	/**
 	 * Gets Perl5Matcher for this thread.
 	 */
@@ -1102,4 +1163,5 @@
 		}
 		return f;
 	}
+		
 }
 
Index: jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/Pair.java
===================================================================
--- jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/Pair.java	(revision 0)
+++ jakarta-jmeter-2.3/src/core/org/apache/jmeter/util/Pair.java	(revision 0)
@@ -0,0 +1,16 @@
+package org.apache.jmeter.util;
+
+public class Pair{
+
+	public Object first;
+	public Object second;
+
+	public Pair(){
+	}
+
+	public Pair(Object first, Object second){
+		this.first = first;
+		this.second = second;
+	}
+	
+}

Index: jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/AcquireSemaphore.java
===================================================================
--- jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/AcquireSemaphore.java	(revision 0)
+++ jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/AcquireSemaphore.java	(revision 0)
@@ -0,0 +1,62 @@
+package org.apache.jmeter.protocol.java.test;
+
+import java.io.Serializable;
+
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
+import org.apache.jmeter.samplers.SampleResult;
+
+public class AcquireSemaphore extends AbstractJavaSamplerClient implements Serializable {
+	
+	public static final String SEMAPHORE_NAME = "";
+	public static final int SEMAPHORE_COUNT = 1;
+
+	private String name;
+	private int count;
+	
+	public AcquireSemaphore() {		
+	}
+
+	public void setupTest(JavaSamplerContext context) {
+		name  = context.getParameter("Name", SEMAPHORE_NAME);
+		count = context.getIntParameter("Count", SEMAPHORE_COUNT);
+	}
+
+	public SampleResult runTest(JavaSamplerContext context) {			
+		JMeterContext jmctx = JMeterContextService.getContext();
+		String tgname = jmctx.getThreadGroup().getName();
+		SampleResult results = new SampleResult();
+		results.sampleStart();
+		try {
+			results.setSampleLabel(tgname);
+			org.apache.jmeter.util.JMeterUtils.acquireSemaphore(getName(), tgname, getCount());
+			results.setSuccessful(true);
+		} catch (Exception e) {			
+			results.setSuccessful(false);
+		} finally {
+			results.sampleEnd();
+		}
+		return results;
+	}
+
+	public void teardownTest(JavaSamplerContext context) {
+	}
+
+	public Arguments getDefaultParameters() {
+		Arguments params = new Arguments();
+		params.addArgument("Name", String.valueOf(SEMAPHORE_NAME));		
+		params.addArgument("Count", String.valueOf(SEMAPHORE_COUNT));	
+		return params;
+	}
+
+	private String getName() {
+		return name;
+	}
+
+	private int getCount() {
+		return count;
+	}
+}

Index: jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/ReleaseSemaphore.java
===================================================================
--- jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/ReleaseSemaphore.java	(revision 0)
+++ jakarta-jmeter-2.3/src/protocol/java/org/apache/jmeter/protocol/java/test/ReleaseSemaphore.java	(revision 0)
@@ -0,0 +1,54 @@
+package org.apache.jmeter.protocol.java.test;
+
+import java.io.Serializable;
+
+import org.apache.jmeter.threads.JMeterContext;
+import org.apache.jmeter.threads.JMeterContextService;
+import org.apache.jmeter.config.Arguments;
+import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
+import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
+import org.apache.jmeter.samplers.SampleResult;
+
+public class ReleaseSemaphore extends AbstractJavaSamplerClient implements Serializable {
+	
+	public static final String SEMAPHORE_NAME = "";	
+
+	private String name;
+	
+	public ReleaseSemaphore() {		
+	}
+
+	public void setupTest(JavaSamplerContext context) {
+		name  = context.getParameter("Name", SEMAPHORE_NAME);		
+	}
+
+	public SampleResult runTest(JavaSamplerContext context) {			
+		JMeterContext jmctx = JMeterContextService.getContext();
+		String tgname = jmctx.getThreadGroup().getName();
+		SampleResult results = new SampleResult();
+		results.sampleStart();
+		try {
+			results.setSampleLabel(tgname);
+			org.apache.jmeter.util.JMeterUtils.releaseSemaphore(getName());			
+			results.setSuccessful(true);
+		} catch (Exception e) {			
+			results.setSuccessful(false);
+		} finally {
+			results.sampleEnd();
+		}
+		return results;
+	}
+
+	public void teardownTest(JavaSamplerContext context) {
+	}
+
+	public Arguments getDefaultParameters() {
+		Arguments params = new Arguments();
+		params.addArgument("Name", String.valueOf(SEMAPHORE_NAME));		
+		return params;
+	}
+
+	private String getName() {
+		return name;
+	}
+}

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
JMeter currently requires a minimum of Java 1.4.
We don't have plans to require Java 1.5 at present.

However the functionality would be useful.

I believe there is a library containing semaphores which runs on 1.4. Provided
that the license is compatible, we could use that.

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
See also #1581

@asfimport
Copy link
Collaborator Author

Sebb (migrated from Bugzilla):
(In reply to comment 0)

hi,

in our testplans, we needed a sort of "semaphore" mechanism, e.g.:

  • we have problems if more than 10 parallel logins to our webapp exists

That's a bug in the web-app ...

  • we have a lot of threads that create, rename and delete channels. one thread
    can delete a channel that another thread tries to rename.

Again that's something that independent users may encounter normally.

So I don't think these use cases are typical.

AFAICT, in your case, the semaphores are being used to avoid triggering the errors.

However, it may still be useful as a way of configuring a test.

I'm not sure that a sampler is the correct test element to use; that needs to be given more thought. Would a Timer be better? After all, that's the effect of the semaphore.

@asfimport
Copy link
Collaborator Author

@pmouawad (migrated from Bugzilla):
This bug has been marked as a duplicate of #3398

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant