Return-Path: Delivered-To: apmail-incubator-open-jpa-dev-archive@locus.apache.org Received: (qmail 36423 invoked from network); 29 May 2007 18:02:16 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 29 May 2007 18:02:16 -0000 Received: (qmail 47139 invoked by uid 500); 29 May 2007 18:02:20 -0000 Delivered-To: apmail-incubator-open-jpa-dev-archive@incubator.apache.org Received: (qmail 47116 invoked by uid 500); 29 May 2007 18:02:20 -0000 Mailing-List: contact open-jpa-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: open-jpa-dev@incubator.apache.org Delivered-To: mailing list open-jpa-dev@incubator.apache.org Received: (qmail 47107 invoked by uid 99); 29 May 2007 18:02:20 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 May 2007 11:02:20 -0700 X-ASF-Spam-Status: No, hits=1.5 required=10.0 tests=SPF_SOFTFAIL X-Spam-Check-By: apache.org Received-SPF: softfail (herse.apache.org: transitioning domain of dezzio@bea.com does not designate 62.13.136.40 as permitted sender) Received: from [62.13.136.40] (HELO outmail136040.authsmtp.co.uk) (62.13.136.40) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 May 2007 11:02:12 -0700 Received: from outmail128182.authsmtp.co.uk (outmail128182.authsmtp.co.uk [62.13.128.182]) by punt3.authsmtp.com (8.13.8/8.13.8/Kp) with ESMTP id l4TI1oKO024990 for ; Tue, 29 May 2007 19:01:50 +0100 (BST) Received: from [127.0.0.1] (cpe-74-75-208-205.maine.res.rr.com [74.75.208.205]) (authenticated bits=0) by mail.authsmtp.com (8.13.8/8.13.8/Kp) with ESMTP id l4TI1jma082590 for ; Tue, 29 May 2007 19:01:48 +0100 (BST) Message-ID: <465C6A8D.6050203@bea.com> Date: Tue, 29 May 2007 14:01:49 -0400 From: "David Ezzio (asmtp)" User-Agent: Thunderbird 1.5.0.10 (Windows/20070221) MIME-Version: 1.0 To: open-jpa-dev@incubator.apache.org Subject: Comparison Metrics for OpenJPA's ConcurrentHashMap Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Server-Quench: ac37651d-0e0e-11dc-a443-001185d377ca X-AuthRoute: OCdyYw0VAlZZQRYI CyQsBiJJDw4iIwtL GRIFaAlCKR8FWBp5 M0BRM1BaLFoGA1hB UjVTDkoLEgo/W2pq FlsYcgddYk1eXgxg UElDRlscEwF2Bhkf BB4WTBtychpEfWFw KxpmOglaBhkrdU5/ R0dUW2kEZGAuOTMc V0ZddldJcFZKKwJE awQsSSIJZWYaZnph Rl9uM2tuYj5WPg9S RxkEN1MJRkBDOzMg XREJBn0hGldNYD0+ KT4eAxEHVG0WNE4v K0EsX044OgQSLwRG d3Ns X-Authentic-SMTP: 61633133353031.squirrel.dmpriest.net.uk:671/Kp X-Report-SPAM: If SPAM / abuse - report it at: http://www.authsmtp.com/abuse X-Virus-Status: No virus detected - but ensure you scan with your own anti-virus system! X-Virus-Checked: Checked by ClamAV on apache.org Recently, I did some testing of Map implementations under concurrency. My primary purpose was to verify the reliability of OpenJPA's ConcurrentHashMap implementation. As I got into it, I saw the opportunity to get some performance metrics out of the test. The biggest part of my task was coming up with a reliable and useful testing framework. I design it with the following two factors in mind: First, I wanted to test the edge conditions where an entry had just been added or removed or where a key's value had just been updated. The idea is that a number of threads add, remove, and update entries, while other threads check to see if these recent modifications are visible (or in the case of removals, not visible). Second, I wanted the testing framework itself to be free of synchronization. If the testing framework used synchronization then it would tend to serialize the readers and writers and thereby mask concurrency issues in the map implementation under test. The testing framework uses a non-synchronizing, non-blocking FIFO queue as the mechanism for the writing threads to communicate their recent modifications to the reading threads. To prevent writing threads from overwriting recent modifications before they could be read and verified, the testing framework walks the hash map keys in in a linear (or in the case of updates, circular) order. By using a hash map with a large enough capacity, readers have the time to verify the recent modifications before the writer threads come back to modify that part of the key space again. Using an adapter for the map implementation, the testing framework starts five writer threads and ten reader threads at the same time. These threads run wide open for 30 seconds, except that the readers will give up their time slice if they find nothing on the queue. The HashMaps were all sized for the needed capacity upon creation, so no resizing occurred during testing. I got some interesting results. Four implementations were tested, Java's unsynchronized HashMap implementation, Java's synchronized HashMap implementation, Java's ConcurrentHashMap implementation, and OpenJPA's ConcurrentHashMap implementation. Only Java's unsynchronized HashMap failed, as expected, under test. Under test, this implementation demonstrates its inability to handle concurrency. The other three implementations worked flawlessly under test. The java.util.concurrent.ConcurrentHashMap implementation (available with Java 5 and 6) was the fastest implementation tested. Java's synchronized wrapper for the HashMap implementation is one to two orders of magnitude slower than Java's ConcurrentHashMap implementation. OpenJPA's ConcurrentHashMap compares equally with Java's ConcurrentHashMap in find operations and is 2-4 times slower in mutating operations. Implementation Add Remove Update Find-a Find-r Find-u ---------------+------+-------+--------+-------+-------+------ synchronized 103 35 50 40 37 54 concurrent 13.2 6.4 6.1 0.6 0.3 1.1 OpenJPA 29.8 26.6 27.9 0.6 0.6 0.6 Legend: synchronized: java.util.Collections.synchronizedMap(new java.util.HashMap()) concurrent: java.util.concurrent.ConcurrentHashMap OpenJPA: org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap Add: time for average add operation Remove: time for average remove operation Update: time for average update of new value for existing key Find-a: time to find a recent addition Find-r: time to NOT find a recent removal Find-u: time to find a recent update These times (in microseconds) are representative, but are not the average of several runs. The tests were run on a Dell Dual Core laptop under Windows. The performance meter was pegged during the tests. David Ezzio