/*
* Created on Apr 16, 2004
* Created by Alon Rohter
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.util;
import java.util.*;
/**
* Utility class to retrieve current system time,
* and catch clock backward time changes.
*/
public class
SystemTime
{
public static final long TIME_GRANULARITY_MILLIS = 25; //internal update time ms
private static SystemTimeProvider instance;
static{
try{
if ( System.getProperty( "azureus.time.use.raw.provider", "0" ).equals("1")){
instance = new RawProvider();
}else{
instance = new SteppedProvider();
}
}catch( Throwable e ){
// might be in applet...
instance = new SteppedProvider();
}
}
public static void
useRawProvider()
{
if ( !( instance instanceof RawProvider )){
instance = new RawProvider();
}
}
private static volatile List consumer_list = new ArrayList();
private static volatile List clock_change_list = new ArrayList();
private static highPrecisionCounter high_precision_counter;
private static long hpc_base_time;
private static long hpc_last_time;
protected interface
SystemTimeProvider
{
public long
getTime();
}
protected static class
SteppedProvider
implements SystemTimeProvider
{
private static final int STEPS_PER_SECOND = (int)(1000/TIME_GRANULARITY_MILLIS);
private final Thread updater;
private volatile long stepped_time;
private volatile long last_approximate_time;
private volatile int access_count;
private volatile int slice_access_count;
private volatile int access_average_per_slice;
private volatile int drift_adjusted_granularity;
private
SteppedProvider()
{
stepped_time = System.currentTimeMillis();
updater =
new Thread("SystemTime")
{
public void
run()
{
Average access_average = null;
Average drift_average = null;
long last_second = 0;
int tick_count = 0;
while( true ) {
stepped_time = System.currentTimeMillis();
List consumer_list_ref = consumer_list;
if ( last_second == 0 ){
last_second = stepped_time - 1000;
}else{
long offset = stepped_time - last_second;
if ( offset < 0 || offset > 5000 ){
// clock's changed
last_approximate_time = 0;
last_second = stepped_time - 1000;
access_average = null;
drift_average = null;
Iterator it = clock_change_list.iterator();
while( it.hasNext()){
((consumer)it.next()).consume( offset );
}
}
}
tick_count++;
if ( tick_count == STEPS_PER_SECOND ){
if ( access_average == null ){
access_average = Average.getInstance( 1000, 10 );
drift_average = Average.getInstance( 1000, 10 );
}
long drift = stepped_time - last_second -1000;
last_second = stepped_time;
drift_average.addValue( drift );
drift_adjusted_granularity = (int)( TIME_GRANULARITY_MILLIS + ( drift_average.getAverage() / STEPS_PER_SECOND ));
access_average.addValue( access_count );
access_average_per_slice = (int)( access_average.getAverage() / STEPS_PER_SECOND );
// System.out.println( "access count = " + access_count + ", average = " + access_average.getAverage() + ", per slice = " + access_average_per_slice + ", drift = " + drift +", average = " + drift_average.getAverage() + ", dag =" + drift_adjusted_granularity );
access_count = 0;
tick_count = 0;
}
slice_access_count = 0;
for (int i=0;i<consumer_list_ref.size();i++){
consumer cons = (consumer)consumer_list_ref.get(i);
try{
cons.consume( stepped_time );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
try{
Thread.sleep( TIME_GRANULARITY_MILLIS );
}catch(Exception e){
Debug.printStackTrace( e );
}
}
}
};
updater.setDaemon( true );
// we don't want this thread to lag much as it'll stuff up the upload/download rate mechanisms (for example)
updater.setPriority(Thread.MAX_PRIORITY);
updater.start();
}
public long
getTime()
{
long adjusted_time = stepped_time;
long temp = access_average_per_slice;
if ( temp > 0 ){
long x = (drift_adjusted_granularity*slice_access_count)/temp;
if ( x >= drift_adjusted_granularity ){
x = drift_adjusted_granularity-1;
}
adjusted_time += x;
}
access_count++;
slice_access_count++;
// make sure we don't go backwards
if ( adjusted_time < last_approximate_time ){
adjusted_time = last_approximate_time;
}else{
last_approximate_time = adjusted_time;
}
return( adjusted_time );
}
}
protected static class
RawProvider
implements SystemTimeProvider
{
private static final int STEPS_PER_SECOND = (int)(1000/TIME_GRANULARITY_MILLIS);
private final Thread updater;
private
RawProvider()
{
System.out.println( "SystemTime: using raw time provider" );
updater =
new Thread("SystemTime")
{
long last_time;
public void
run()
{
while( true ) {
long current_time = System.currentTimeMillis();
List consumer_list_ref = consumer_list;
if ( last_time != 0 ){
long offset = current_time - last_time;
if ( offset < 0 || offset > 5000 ){
// clock's changed
Iterator it = clock_change_list.iterator();
while( it.hasNext()){
((consumer)it.next()).consume( offset );
}
}
}
last_time = current_time;
for (int i=0;i<consumer_list_ref.size();i++){
consumer cons = (consumer)consumer_list_ref.get(i);
try{
cons.consume( current_time );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
try{
Thread.sleep( TIME_GRANULARITY_MILLIS );
}catch(Exception e){
Debug.printStackTrace( e );
}
}
}
};
updater.setDaemon( true );
// we don't want this thread to lag much as it'll stuff up the upload/download rate mechanisms (for example)
updater.setPriority(Thread.MAX_PRIORITY);
updater.start();
}
public long
getTime()
{
return( System.currentTimeMillis());
}
}
public static long
getCurrentTime()
{
return( instance.getTime());
}
public static long
getOffsetTime(long offsetMS) {
return instance.getTime() + offsetMS;
}
public static void
registerConsumer(
consumer c )
{
synchronized( instance ){
List new_list = new ArrayList( consumer_list );
new_list.add( c );
consumer_list = new_list;
}
}
public static void
unregisterConsumer(
consumer c )
{
synchronized( instance ){
List new_list = new ArrayList( consumer_list );
new_list.remove( c );
consumer_list = new_list;
}
}
public static void
registerClockChangeListener(
consumer c )
{
synchronized( instance ){
List new_list = new ArrayList( clock_change_list );
new_list.add( c );
clock_change_list = new_list;
}
}
public static void
unregisterClockChangeListener(
consumer c )
{
synchronized( instance ){
List new_list = new ArrayList( clock_change_list );
new_list.remove( c );
clock_change_list = new_list;
}
}
public interface
consumer
{
// for consumers this is the current time, for clock change listeners this is the delta
public void
consume(
long time );
}
public static long
getHighPrecisionCounter()
{
if ( high_precision_counter == null ){
AEDiagnostics.load15Stuff();
synchronized( SystemTime.class ){
long now = getCurrentTime();
if ( now < hpc_last_time ){
// clock's gone back, by at least
long gone_back_by_at_least = hpc_last_time - now;
// all we can do is move the logical start time back too to ensure that our
// counter doesn't got backwards
hpc_base_time -= gone_back_by_at_least;
}
hpc_last_time = now;
return((now - hpc_base_time) * 1000000 );
}
}else{
return( high_precision_counter.nanoTime());
}
}
public static void
registerHighPrecisionCounter(
highPrecisionCounter counter )
{
high_precision_counter = counter;
}
public interface
highPrecisionCounter
{
public long
nanoTime();
}
public static void
main(
String[] args )
{
for (int i=0;i<1;i++){
//final int f_i = i;
new Thread()
{
public void
run()
{
/*
Average access_average = Average.getInstance( 1000, 10 );
long last = SystemTime.getCurrentTime();
int count = 0;
while( true ){
long now = SystemTime.getCurrentTime();
long diff = now - last;
System.out.println( "diff=" + diff );
last = now;
access_average.addValue( diff );
count++;
if ( count == 33 ){
System.out.println( "AVERAGE " + f_i + " = " + access_average.getAverage());
count = 0;
}
try{
Thread.sleep( 3 );
}catch( Throwable e ){
}
}
*/
long start = SystemTime.getCurrentTime();
while( true ){
long now = SystemTime.getCurrentTime();
System.out.println( now - start );
try{
Thread.sleep(1000);
}catch( Throwable e ){
}
}
}
}.start();
}
}
}
|