commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Keith Boone (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (LANG-1355) TimeZone.getTimeZone() in FastDateParser causes resource contention
Date Mon, 02 Oct 2017 21:45:02 GMT

    [ https://issues.apache.org/jira/browse/LANG-1355?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16188905#comment-16188905
] 

Keith Boone commented on LANG-1355:
-----------------------------------

The format we are using most often is ISO8601, but would expect to see others based on offsets
from UTC/GMT.

I'm not using a microbenchmark framework but do have a small program that I used to test the
variations below.  It spawns a hundred threads that repeatedly hit the calls in question and
times the results a couple of ways.

This test creates higher load than what we would expect in normal use, but was good enough
to give me an idea what we might experience with it, as I was able to create a situation showing
the effects of the contention with this.

Note: InstantType comes from http://hapifhir.io, but is basically a data type that when copied,
converts an Instant from a Date back to a string of the appropriate precision, and when constructed,
parses the given string into a Date object (and saves the precision of the original string).
 The copy operation was in the stack trace of the locked threads we saw in our performance
testing beneath calls to FastDateParser.parse().  Note: Some code in hapifhir.io also pays
a penalty for its own internal use of TimeZone.getTimeZone() (in calls to a Date Formatter),
which is in part why I felt this needed to be an externally available API.

   Keith 

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.Date;

import org.hl7.fhir.instance.model.InstantType;

public class TimeZoneTester implements Runnable {
	private static int done = 0;
	private static Thread t[] = null;
	private static TimeZoneTester tester[] = null;
	private static long total;
	
	long timer = 0;
	long cpuTimer = 0;
	
	public static void main(String args[]) {
		 int numThreads = args.length > 0 ? Integer.parseInt(args[0]) : 4;
		 
		 t = new Thread[numThreads];
		 tester = new TimeZoneTester[numThreads];
		 
		 // Warm it up
		 runThisStuff(numThreads);

		 // Let it rip
		 runThisStuff(numThreads);
		 long sumTimer = 0, sumCPUTimer = 0;
		 for (int i = 0; i < numThreads; i++) {
			 System.out.printf("%6d\t%10d\t%10d\n", i, tester[i].timer, tester[i].cpuTimer);
			 sumTimer += tester[i].timer;
			 sumCPUTimer += tester[i].cpuTimer;
		 }
		 System.out.printf("Total\t%10d\t%10d\n", sumTimer, sumCPUTimer);
		 System.out.printf("Actual\t%10d\n", total);
		 System.out.printf("Master\t%10d\n", currentCPUTime());
	}
	
	static void runThisStuff(int numThreads) {
		 done = numThreads;

		 // Create all the threads.
		 for (int i = 0; i < t.length; i++) {
			 t[i] = new Thread(tester[i] = new TimeZoneTester());
			 t[i].setName("TimeZoneTester-" + i);
		 }
		 
		 
		 total = System.nanoTime();
		 for (int i = 0; i < t.length; i++) {
			 t[i].start();
		 }
		 while (done != 0) {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
			}
			System.out.printf("%d threads running\n", done);
		 }
		 total = System.nanoTime() - total;
	}
	
	public void run() {
		timer = System.nanoTime();
		InstantType i = new InstantType(new Date());
		for (int loop = 0; loop < 100000; loop++) {
			// Force use of parser
			i = i.copy();
		}
		timer = System.nanoTime() - timer;
		cpuTimer = currentCPUTime();
		synchronized (TimeZoneTester.class) {
			--done;
		}
	}
	
	private static final ThreadMXBean THREADING = ManagementFactory.getThreadMXBean();
	private static final boolean IS_THREAD_CPU_SUPPORTED = THREADING.isThreadCpuTimeSupported();
	
	public static final long currentCPUTime() {
		return IS_THREAD_CPU_SUPPORTED ? THREADING.getCurrentThreadCpuTime() : 0;
	}

}


> TimeZone.getTimeZone() in FastDateParser causes resource contention
> -------------------------------------------------------------------
>
>                 Key: LANG-1355
>                 URL: https://issues.apache.org/jira/browse/LANG-1355
>             Project: Commons Lang
>          Issue Type: Bug
>          Components: lang.time.*
>    Affects Versions: 3.6
>         Environment: Windows
>            Reporter: Keith Boone
>   Original Estimate: 48h
>  Remaining Estimate: 48h
>
> Under heavy load we are seeing contention in FastDateParser.parse() on calls to TimeZone.getTimeZone().
 TimeZone.getTimeZone() is a synchronized static in the Oracle JVM.
> Our proposed solution is to add a class TimeZoneCache containing a single method getTimeZone()
which gets the requested time zone from a ConcurrentMap, and if not present, looks it up via
TimeZone.getTimeZone() and caches it before returning it.
> Then replace calls to TimeZone.getTimeZone() in FastDateParser ( and whereever else)
to calls to TimeZoneCache.getTimeZone().  
> The reason to add a separate class is because it can also be used by other applications
which heavily parse or format or do other things where TimeZone is repeatedly needed.
> Under extreme load we have seen an 50:1 improvement in calls to FastDateParser.parse().
 This saves about a ms/call in our test environment, and reduces contention.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)

Mime
View raw message