java


how to test the performance of compareAndSet between synchronized


I wnat to use CAS to improve my code ,but i doubt it can get better performance,so i do a test. here is the test code,this jmh code is reliable?
#OutputTimeUnit(TimeUnit.MILLISECONDS)
#BenchmarkMode(Mode.SampleTime)
#Warmup(iterations = 5)
#Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS)
#Threads(20)
#Fork(1)
#State(Scope.Benchmark)
public class CASBench {
private int id=24;
private static Object[] lockObj;
private static AtomicReference<Integer>[] locks;
static {
lockObj = new Object[100];
for (int i = 0; i < lockObj.length; i++) {
lockObj[i] = new Object();
}
locks = new AtomicReference[100];
for (int i = 0; i < locks.length; i++) {
locks[i] = new AtomicReference<Integer>(null);
}
}
#Benchmark
public void sync() throws Exception {
int index = id % 100;
synchronized (lockObj[index]) {
test();
}
}
#Benchmark
public void cas() throws Exception {
AtomicReference<Integer> lock = locks[id % 100];
while (!lock.compareAndSet(null, id)) {
}
test();
lock.compareAndSet(id, null);
}
public void test() throws Exception {
int sum=0;
for(int i=0;i<100;i++){
sum += i;
}
}
}
and i get jmh test result:
Benchmark Mode Cnt Score Error Units
CASBench.cas sample 25866638 0.014 ± 0.001 ms/op
CASBench.cas:cas·p0.00 sample ≈ 10⁻⁶ ms/op
CASBench.cas:cas·p0.50 sample ≈ 10⁻⁴ ms/op
CASBench.cas:cas·p0.90 sample 0.001 ms/op
CASBench.cas:cas·p0.95 sample 0.001 ms/op
CASBench.cas:cas·p0.99 sample 0.001 ms/op
CASBench.cas:cas·p0.999 sample 0.002 ms/op
CASBench.cas:cas·p0.9999 sample 38.164 ms/op
CASBench.cas:cas·p1.00 sample 813.695 ms/op
CASBench.sync sample 26257757 0.011 ± 0.001 ms/op
CASBench.sync:sync·p0.00 sample ≈ 10⁻⁶ ms/op
CASBench.sync:sync·p0.50 sample ≈ 10⁻⁴ ms/op
CASBench.sync:sync·p0.90 sample 0.001 ms/op
CASBench.sync:sync·p0.95 sample 0.001 ms/op
CASBench.sync:sync·p0.99 sample 0.005 ms/op
CASBench.sync:sync·p0.999 sample 1.883 ms/op
CASBench.sync:sync·p0.9999 sample 15.270 ms/op
CASBench.sync:sync·p1.00 sample 45.810 ms/op
can I get this conclusion,in this case synchronized is better?
Well your test are incorrect indeed as far as I can tell. First your benchmarks should return a value, as specified in the samples here or use BlackHoles.
Than there are two ways to test this, first when there is contention and there isn't.
Let's see what happens under contention, it's simpler to grasp:
#OutputTimeUnit(TimeUnit.NANOSECONDS)
#BenchmarkMode(Mode.AverageTime)
#Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
#Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
#State(Scope.Benchmark)
public class Contention {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.jvmArgs("-ea")
.shouldFailOnError(true)
.include(Contention.class.getSimpleName()).build();
new Runner(opt).run();
}
private AtomicInteger atomic;
private Object lock = new Object();
private int i = 0;
#Setup
public void setUp() {
atomic = new AtomicInteger(0);
}
#Fork(1)
#Threads(10)
#Benchmark
public int incrementAtomic() {
return atomic.incrementAndGet();
}
#Fork(1)
#Threads(10)
#Benchmark
public int incrementSync() {
synchronized (lock) {
++i;
}
return i;
}
}
The code should be pretty much self-explanatory; with a slight explanation here :
State(Scope.Benchmark)
If you change that to : State(Scope.Thread) each thread will get it's own lock and as such this code would be skewed by biased-locking.
What that means that if you would run this code with :
State(Scope.Thread)
Your output would be very much the same. Something like this:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.Contention.incrementAtomic avgt 5 36.526 ± 6.548 ns/op
casVSsynchronized.Contention.incrementSync avgt 5 23.655 ± 3.393 ns/op
Running it with:
#State(Scope.Benchmark)
Shows an entire different picture. Under contention CAS performs way better as you can see from results:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.Contention.incrementAtomic avgt 5 212.997 ± 42.902 ns/op
casVSsynchronized.Contention.incrementSync avgt 5 457.896 ± 46.811 ns/op
Than I have a bit of a more complicated test (which might need more restrictive reviews from jmh devs probably):
import java.util.concurrent.TimeUnit;
#OutputTimeUnit(TimeUnit.NANOSECONDS)
#BenchmarkMode(Mode.AverageTime)
#Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
#Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
public class CASSync {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.jvmArgs("-ea")
.shouldFailOnError(true)
.include(CASSync.class.getSimpleName()).build();
new Runner(opt).run();
}
#State(Scope.Thread)
static public class AtomicHolder {
AtomicInteger i = null;
#Setup(Level.Invocation)
public void setUp() {
i = new AtomicInteger(0);
}
#TearDown(Level.Invocation)
public void tearDown() {
assert i.intValue() == 1;
i = null;
}
}
#State(Scope.Thread)
static public class SyncHolder {
int i = 0;
Object lock = null;
#Setup(Level.Invocation)
public void setUp() {
lock = new Object();
i = 0;
}
#TearDown(Level.Invocation)
public void tearDown() {
assert i == 1;
lock = null;
}
}
#Benchmark
#Fork(1)
public boolean cas(AtomicHolder holder) {
return holder.i.compareAndSet(0, 1);
}
#Benchmark
#Fork(1)
public boolean sync(SyncHolder holder) {
synchronized (holder.lock) {
++holder.i;
}
return holder.i == 1;
}
}
This one tests the case when there is no contention at all (just like the first one), but this time getting rid of biased-locking. And the results:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.CASSync.cas avgt 5 44.003 ± 1.343 ns/op
casVSsynchronized.CASSync.sync avgt 5 50.744 ± 1.370 ns/o
My conclusion: for contended environments, CAS is way better. For the rest it's debatable.

Related Links

Picking images with Cordova not working on some smartphones
check if two strings are permutation of each other?
Is it considered bad to not use the API?
Finding out who calls jvm shutdown hook
Duplicate String Array in java [duplicate]
Bitwise XOR operator and byte arrays
Right to left an activity without editing device locale
Populate a jlist from text file read through button
Java: rewrite comparator to Lambda - nullsafe
how to prevent getting same name with different ID on mysql Java
Spring application.properties via ldap
“Could not initialize class org.apache.xml.security.Init” in Glassfish 4.1.1
How to change XML SOAP envelop by using JAVA library?
Counting and resetting a Scanner
how to run a scheduler task for every 5 minutes
Convert String in EditText to Double

Categories

HOME
vim
client
osgi
clips
keycloak
omnet++
json.net
yahoo-oauth
umd
ckeditor
baqend
ebean
append
dax
modelica
qt-creator
circuit
saxon
physics-engine
java-7
react-css-modules
linkerd
maquette
gitignore
gtrendsr
protovis
azure-sql-database
environment-modules
hockeyapp
temporary-files
particles.js
email-templates
password-encryption
vao
.net-4.6.2
dotcover
rainbowtable
jlink
typescript1.8
pebble-watch
knockout-components
pg-dump
ifs
qtwebview
blacklist
specrun
google-cdn
removechild
azure-virtual-network
transmitfile
xml-attribute
qcustomplot
netmq
energy
reactive-banana
marching-cubes
ruby-2.2
varargs
service-accounts
ios9.1
umbraco6
tween
gadt
elliptic-curve
concurrent-collections
meteor-velocity
inbox
apc
listings
django-nonrel
comaddin
sharp-repository
mt
quickdialog
qtkit
bubble-chart
whoosh
mercurial-server
stage
qt-jambi
recent-documents
appendto
ecl
mongomapper
createwindow
zend-translate
sproutcore-2
mozilla-prism
user-friendly
memory-size
kdbg
data-driven
premature-optimization
.net-1.0

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App