home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
jËzyki_programowania
/
clisp
/
src
/
archive
/
clisp.src.lha
/
src
/
time.d
< prev
next >
Wrap
Text File
|
1996-04-15
|
39KB
|
1,026 lines
# Zeitmessungsfunktionen für CLISP
# Bruno Haible 22.3.1995
#include "lispbibl.c"
#include "arilev0.c" # für high16, low16 in %%TIME,
# für divu in GET-UNIVERSAL-TIME,
# für mulu32 in GET-INTERNAL-RUN-TIME, GET-INTERNAL-REAL-TIME
# ------------------------------------------------------------------------------
# Zeitmessung
# Variablen für Zeitmessung:
#ifdef TIME_AMIGAOS
# (Grundeinheit ist 1/50 sec, ein 32-Bit-Zähler reicht also
# für 994d 4h 55m 45.92s, und keine LISP-Session dauert 2.7 Jahre.)
#endif
#ifdef TIME_MSDOS
# (Grundeinheit ist 1/100 sec, ein 32-Bit-Zähler reicht also
# für 497d 2h 27m 52.96s, und keine LISP-Session dauert 1.3 Jahre.)
#endif
#if defined(TIME_UNIX_TIMES) || defined(TIME_RISCOS)
# (Grundeinheit ist etwa 1/60 sec oder 1/100 sec, ein 32-Bit-Zähler reicht
# also eine ganze Weile.)
#endif
#if defined(TIME_UNIX) || defined(TIME_WIN32)
# Grundeinheit ist 1 µsec.
# (Egal, ob der Systemtakt nun - abhängig vom lokalen Stromnetz - 60 Hz
# oder 50 Hz beträgt oder eine genauere Uhr eingebaut ist.)
#endif
# Zeit, die abläuft:
local internal_time realstart_time; # Real-Time beim LISP-Start
#ifndef HAVE_RUN_TIME
# Zeit, die das LISP insgesamt verbraucht:
local uintL run_time = 0; # Runtime bisher insgesamt
local uintL runstop_time; # bei laufender Run-Time-Stoppuhr:
# Zeitpunkt des letzten Run/Stop-Wechsels
local boolean run_flag = FALSE; # /= 0 wenn die Run-Time-Stoppuhr läuft
#endif
#ifdef TIME_RELATIVE
# UP: greift die aktuelle Zeit ab
# get_time()
#ifdef TIME_AMIGAOS
# < uintL ergebnis : aktueller Stand des 50Hz-Zählers
global uintL get_time(void);
global uintL get_time()
{ var struct DateStamp datestamp;
begin_system_call();
DateStamp(&datestamp); # aktuelle Uhrzeit holen
end_system_call();
# und in Ticks ab 1.1.1978 00:00:00 umrechnen:
return ((uintL)(datestamp.ds_Days)*24*60 + (uintL)(datestamp.ds_Minute))
*60*ticks_per_second + (uintL)(datestamp.ds_Tick);
}
#endif
#ifdef TIME_MSDOS
# < uintL ergebnis : aktueller Stand des 100Hz-Zählers
global uintL get_time(void);
#if defined(DJUNIX) && 0 # Vorsicht: das geht eine Stunde nach!!
global uintL get_time()
{ var struct timeval real_time;
gettimeofday(&real_time,NULL);
return (uintL)(real_time.tv_sec) * 100
+ (uintL)((uintW)((uintL)(real_time.tv_usec) / 16) / 625); # tv_usec/10000
}
#endif
#if defined(DJUNIX) || defined(WATCOM) || defined(EMUNIX_OLD_8d) || defined(WINDOWS)
typedef struct { uintW year; # Jahr (1980..2099)
uintB month; # Monat (1..12)
uintB day; # Tag (1..31)
uintB hour; # Stunde (0..23)
uintB min; # Minute (0..59)
uintB sec; # Sekunde (0..59)
uintB hsec; # Hundertstel Sekunde (0..59)
}
internal_decoded_time;
local void get_decoded_time (internal_decoded_time* timepoint);
local void get_decoded_time(timepoint)
var reg1 internal_decoded_time* timepoint;
#if defined(DJUNIX) || defined(WATCOM) || (defined(EMUNIX) && defined(WINDOWS))
{ var union REGS in;
var union REGS out;
begin_system_call();
loop
{ # Datum-Teil holen:
in.regB.ah = 0x2A; # DOS Get Date
intdos(&in,&out);
timepoint->year = out.regW.cx;
timepoint->month = out.regB.dh;
timepoint->day = out.regB.dl;
# Uhrzeit-Teil holen:
in.regB.ah = 0x2C; # DOS Get Time
intdos(&in,&out);
timepoint->hour = out.regB.ch;
timepoint->min = out.regB.cl;
timepoint->sec = out.regB.dh;
timepoint->hsec = out.regB.dl;
# und auf Tageswechsel überprüfen:
if (!(timepoint->sec == 0)) break;
if (!(timepoint->min == 0)) break;
if (!(timepoint->hour == 0)) break;
in.regB.ah = 0x2A; # DOS Get Date
intdos(&in,&out);
if (timepoint->day == out.regB.dl) break;
# Datum hat sich zwischenzeitlich verändert -> wiederholen
}
end_system_call();
}
#endif
#if defined(EMUNIX) && !defined(WINDOWS)
# [ältere Version für EMX 0.8c, noch ohne ftime(): siehe emx08c-1.d]
{ var struct _dtd datetime;
# Uhrzeit holen:
begin_system_call();
__ftime(&datetime);
end_system_call();
# und nach *timepoint umfüllen:
timepoint->year = datetime.year;
timepoint->month = datetime.month;
timepoint->day = datetime.day;
timepoint->hour = datetime.hour;
timepoint->min = datetime.min;
timepoint->sec = datetime.sec;
timepoint->hsec = datetime.hsec;
}
#endif
global uintL get_time()
{ var internal_decoded_time timepoint;
get_decoded_time(&timepoint);
{local var uintW monthoffsets[12] = { # Jahrtag ab dem letzten 1. März
# Monat 1 2 3 4 5 6 7 8 9 10 11 12
306,337, 0,31,61,92,122,153,184,214,245,275,
};
var reg1 uintL UTTag;
timepoint.year -= 1980;
if (timepoint.month >= 3) { timepoint.year += 1; }
UTTag = (uintL)timepoint.year * 365 + (uintL)ceiling(timepoint.year,4)
+ (uintL)monthoffsets[timepoint.month-1] + (uintL)timepoint.day + 3345;
# Zeitzone mitberücksichtigen??
return (((UTTag * 24 + (uintL)timepoint.hour)
* 60 + (uintL)timepoint.min)
* 60 + (uintL)timepoint.sec)
* 100 + (uintL)timepoint.hsec;
}}
#endif
#if defined(EMUNIX_NEW_8e) && !defined(WINDOWS)
global uintL get_time()
{ var struct timeb real_time;
begin_system_call();
__ftime(&real_time);
end_system_call();
return (uintL)(real_time.time) * ticks_per_second
+ (uintL)((uintW)(real_time.millitm) / (1000/ticks_per_second));
}
#endif
#endif
#ifdef TIME_UNIX_TIMES
# < uintL ergebnis : aktueller Stand des CLK_TCK Hz - Zählers
local uintL get_time(void);
local uintL get_time()
{ var struct tms buffer;
return (uintL)times(&buffer);
}
#endif
#ifdef TIME_RISCOS
# < uintL ergebnis : aktueller Stand des CLK_TCK Hz - Zählers
global uintL get_time(void);
#include <sys/os.h>
global uintL get_time()
{ var int regs[10];
var os_error * err;
begin_system_call();
err = os_swi(0x42,regs);
if (err) { __seterr(err); OS_error(); }
end_system_call();
return (uintL)(regs[0]);
}
#endif
#ifndef HAVE_RUN_TIME
# UP: Hält die Run-Time-Stoppuhr an
# run_time_stop();
global void run_time_stop (void);
global void run_time_stop()
{ if (!run_flag) return; # Run-Time-Stoppuhr ist schon angehalten -> OK
# zuletzt verbrauchte Run-Time zur bisherigen Run-Time addieren:
run_time += get_time()-runstop_time;
run_flag = FALSE; # Run-Time-Stoppuhr steht
}
# UP: Läßt die Run-Time-Stoppuhr weiterlaufen
# run_time_restart();
global void run_time_restart (void);
global void run_time_restart()
{ if (run_flag) return; # Run-Time-Stoppuhr läuft schon -> OK
runstop_time = get_time(); # aktuelle Zeit abspeichern
run_flag = TRUE; # Run-Time-Stoppuhr läuft
}
#endif
# UP: Liefert die Real-Time
# get_real_time()
# < uintL ergebnis: Zeit seit LISP-System-Start (in 1/200 sec bzw. in 1/50 sec bzw. in 1/100 sec bzw. in 1/CLK_TCK sec)
global uintL get_real_time (void);
global uintL get_real_time()
{ return get_time()-realstart_time; }
#endif
#ifdef TIME_UNIX_TIMES
# UP: Liefert die Run-Time
# get_run_time(&runtime);
# < internal_time runtime: Run-Time seit LISP-System-Start (in Ticks)
# < uintL ergebnis: wie get_time()
global uintL get_run_time (internal_time* runtime);
global uintL get_run_time(runtime)
var reg1 internal_time* runtime;
{ var struct tms tms;
var reg2 uintL now_time;
begin_system_call();
now_time = times(&tms);
end_system_call();
*runtime = tms.tms_utime + tms.tms_stime; # User time + System time
return now_time; # vgl. get_time()
}
#endif
#ifdef TIME_UNIX
# UP: Liefert die Real-Time
# get_real_time()
# < internal_time* ergebnis: absolute Zeit
global internal_time* get_real_time (void);
global internal_time* get_real_time()
{
#ifdef HAVE_GETTIMEOFDAY
static union { struct timeval tv; internal_time it; } real_time;
begin_system_call();
if (!( gettimeofday(&real_time.tv,NULL) ==0)) { OS_error(); }
end_system_call();
return &real_time.it;
#elif defined(HAVE_FTIME)
static internal_time it;
var struct timeb timebuf;
begin_system_call();
ftime(&timebuf);
end_system_call();
it.tv_sec = timebuf.time;
it.tv_usec = (uintL)(timebuf.millitm) * (ticks_per_second/1000);
return
#endif
}
# UP: Liefert die Run-Time
# get_run_time(&runtime);
# < internal_time runtime: Run-Time seit LISP-System-Start (in Ticks)
global void get_run_time (internal_time* runtime);
global void get_run_time(runtime)
var reg1 internal_time* runtime;
{
#if defined(HAVE_GETRUSAGE)
var struct rusage rusage;
begin_system_call();
if (!( getrusage(RUSAGE_SELF,&rusage) ==0)) { OS_error(); }
end_system_call();
# runtime = rusage.ru_utime + rusage.ru_stime; # User time + System time
add_internal_time(rusage.ru_utime,rusage.ru_stime, *runtime);
#elif defined(HAVE_SYS_TIMES_H)
var reg2 uintL used_time; # verbrauchte Zeit, gemessen in 1/HZ Sekunden
var struct tms tms;
begin_system_call();
if (times(&tms) == (CLOCK_T)(-1))
{ used_time = 0; } # times scheitert -> used_time unbekannt
else
{ used_time = tms.tms_utime + tms.tms_stime; } # User time + System time
end_system_call();
# in Sekunden und Mikrosekunden umwandeln: # verwende HZ oder CLK_TCK ??
runtime->tv_sec = floor(used_time,HZ);
runtime->tv_usec = (used_time % HZ) * floor(2*1000000+HZ,2*HZ);
#endif
}
#endif
#ifdef TIME_WIN32
# UP: Liefert die Run-Time
# get_run_time(&runtime);
# < internal_time runtime: Run-Time seit LISP-System-Start (in Ticks)
global void get_run_time (internal_time* runtime);
global void get_run_time(
var reg1 internal_time* runtime)
{
var FILETIME creationft, exitft, kernelft, userft;
CLISP_LONGLONG total;
#ifdef ANSI
var clock_t clocks; # in seconds*CLOCKS_PER_SEC
#endif
begin_system_call();
if (GetProcessTimes(GetCurrentProcess(), &creationft, &exitft,
&kernelft, &userft))
{ CLISP_LONGLONG user,system;
end_system_call();
user = ((CLISP_LONGLONG)userft.dwHighDateTime << 32) + (userft.dwLowDateTime);
system = ((CLISP_LONGLONG)kernelft.dwHighDateTime << 32) + (kernelft.dwLowDateTime);
# DIV: milliseconds from 100-nanosecond intervals
total = (user + system) / 10;
}
# Otherwise, we seem to be running under Windows'95
#ifdef ANSI
# DIV! Microsoft posses ANSI clock()
else if( (clocks = clock()) != (clock_t)-1 ) # clocks available
{ end_system_call();
total = (CLISP_LONGLONG)clocks * (1000000/CLOCKS_PER_SEC);
}
#endif
else
{ end_system_call();
total = 0;
}
runtime->tv_sec = (uintL)floor(total,1000000);
runtime->tv_usec = (uintL)(total % 1000000);
}
# UP: Liefert die Real-Time
# get_real_time()
# < internal_time* ergebnis: absolute Zeit
global internal_time* get_real_time (void);
global internal_time* get_real_time()
{
static internal_time it;
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
{ unsigned long long usecs;
usecs = (unsigned long long)ft.dwHighDateTime << 32;
usecs |= ft.dwLowDateTime;
usecs /= 10;
it.tv_sec = usecs / 1000000;
it.tv_usec = usecs % 1000000;
return
}
}
#endif
# UP: Liefert die Run-Time
# get_running_times(×core);
# < timescore.runtime: Run-Time seit LISP-System-Start (in Ticks)
# < timescore.realtime: Real-Time seit LISP-System-Start (in Ticks)
# < timescore.gctime: GC-Time seit LISP-System-Start (in Ticks)
# < timescore.gccount: Anzahl der GC's seit LISP-System-Start
# < timescore.gcfreed: Größe des von den GC's bisher wiederbeschafften Platzes
global void get_running_times (timescore*);
global void get_running_times (tm)
var reg1 timescore* tm;
{
#ifndef HAVE_RUN_TIME
var reg2 uintL time = get_time();
tm->realtime = time - realstart_time;
tm->runtime = (run_flag ?
time - runstop_time + run_time : # Run-Time-Stoppuhr läuft noch
run_time # Run-Time-Stoppuhr steht
);
#endif
#if defined(TIME_UNIX) || defined(TIME_WIN32)
# Real-Time holen:
var reg2 internal_time* real_time = get_real_time();
tm->realtime.tv_sec = real_time->tv_sec - realstart_time.tv_sec;
tm->realtime.tv_usec = real_time->tv_usec;
# Run-Time holen:
get_run_time(&tm->runtime);
#endif
#ifdef TIME_UNIX_TIMES
# Run-Time und Real-Time auf einmal holen:
tm->realtime = get_run_time(&tm->runtime) - realstart_time; # vgl. get_real_time()
#endif
tm->gctime = gc_time;
tm->gccount = gc_count;
tm->gcfreed = gc_space;
}
#if defined(MSDOS)
# UP: Wandelt das in Decoded-Time um.
# convert_timedate(time,date,&timepoint)
# > uintW time: Uhrzeit
# Als Word: Bits 15..11: Stunde in {0,...,23},
# Bits 10..5: Minute in {0,...,59},
# Bits 4..0: Sekunde/2 in {0,...,29}.
# > uintW date: Datum
# Als Word: Bits 15..9: Jahr-1980 in {0,...,119},
# Bits 8..5: Monat in {1,...,12},
# Bits 4..0: Tag in {1,...,31}.
# < timepoint.Sekunden, timepoint.Minuten, timepoint.Stunden,
# timepoint.Tag, timepoint.Monat, timepoint.Jahr, jeweils als Fixnums
global void convert_timedate (uintW time, uintW date, decoded_time* timepoint);
global void convert_timedate(time,date, timepoint)
var reg2 uintW time;
var reg2 uintW date;
var reg1 decoded_time* timepoint;
{ timepoint->Sekunden = fixnum( (time & (bit(5) - 1)) << 1 );
time = time>>5;
timepoint->Minuten = fixnum( time & (bit(6) - 1));
time = time>>6;
timepoint->Stunden = fixnum( time);
timepoint->Tag = fixnum( date & (bit(5) - 1));
date = date>>5;
timepoint->Monat = fixnum( date & (bit(4) - 1));
date = date>>4;
timepoint->Jahr = fixnum( date+1980);
}
#endif
#ifdef AMIGAOS
# UP: Wandelt das Amiga-Zeitformat in Decoded-Time um.
# convert_time(&datestamp,&timepoint);
# > struct DateStamp datestamp: Uhrzeit
# datestamp.ds_Days : Anzahl Tage seit 1.1.1978
# datestamp.ds_Minute : Anzahl Minuten seit 00:00 des Tages
# datestamp.ds_Tick : Anzahl Ticks seit Beginn der Minute
# < timepoint.Sekunden, timepoint.Minuten, timepoint.Stunden,
# timepoint.Tag, timepoint.Monat, timepoint.Jahr, jeweils als Fixnums
# include "arilev0.c" # für Division
global void convert_time (struct DateStamp * datestamp, decoded_time* timepoint);
global void convert_time(datestamp,timepoint)
var reg2 struct DateStamp * datestamp;
var reg1 decoded_time* timepoint;
{ # Methode:
# ds_Tick durch ticks_per_second dividieren, liefert Sekunden.
# ds_Minute durch 60 dividierem liefert Stunden und (als Rest) Minuten.
# ds_Days in Tag, Monat, Jahr umrechnen:
# d := ds_Days - 790; # Tage seit 1.3.1980 (Schaltjahr)
# y := floor((4*d+3)/1461); # März-Jahre ab 1.3.1980
# d := d - floor(y*1461/4); # Tage ab letztem März-Jahres-Anfang
# (Diese Rechnung geht gut, solange jedes vierte Jahr ein Schaltjahr
# ist, d.h. bis zum Jahr 2099.)
# m := floor((5*d+2)/153); # Monat ab letztem März
# d := d - floor((153*m+2)/5); # Tag ab letztem Monatsanfang
# m := m+2; if (m>=12) then { m:=m-12; y:=y+1; } # auf Jahre umrechnen
# Tag d+1, Monat m+1, Jahr 1980+y.
{var reg3 uintL sec;
divu_3216_1616(datestamp->ds_Tick,ticks_per_second,sec=,_EMA_);
timepoint->Sekunden = fixnum(sec);
}
{var reg3 uintL std;
var reg4 uintL min;
divu_3216_1616(datestamp->ds_Minute,60,std=,min=);
timepoint->Minuten = fixnum(min);
timepoint->Stunden = fixnum(std);
}
{var reg5 uintL y;
var reg4 uintW m;
var reg3 uintW d;
divu_3216_1616(4*(datestamp->ds_Days - 424),1461,y=,d=); # y = März-Jahre ab 1.1.1979
d = floor(d,4); # Tage ab dem letzten März-Jahres-Anfang
divu_1616_1616(5*d+2,153,m=,d=); # m = Monat ab letztem März
d = floor(d,5); # Tag ab letztem Monatsanfang
# m=0..9 -> Monat März..Dezember des Jahres 1979+y,
# m=10..11 -> Monat Januar..Februar des Jahres 1980+y.
if (m<10) { m += 12; y -= 1; } # auf Jahre umrechnen
timepoint->Tag = fixnum(1+(uintL)d);
timepoint->Monat = fixnum(-9+(uintL)m);
timepoint->Jahr = fixnum(1980+y);
} }
#endif
#if defined(UNIX) || defined(MSDOS) || defined(RISCOS) || defined(WIN32_UNIX) || defined(WIN32_DOS)
# UP: Wandelt das System-Zeitformat in Decoded-Time um.
# convert_time(&time,&timepoint);
# > time_t time: Zeit im System-Zeitformat
# < timepoint.Sekunden, timepoint.Minuten, timepoint.Stunden,
# timepoint.Tag, timepoint.Monat, timepoint.Jahr, jeweils als Fixnums
global void convert_time (time_t* time, decoded_time* timepoint);
global void convert_time(time,timepoint)
var reg3 time_t* time;
var reg1 decoded_time* timepoint;
{ begin_system_call();
{var reg2 struct tm * tm = localtime(time); # decodieren
# (Das Zeitformat des Systems muß auch das System auseinandernehmen.)
end_system_call();
if (!(tm==NULL))
# localtime war erfolgreich
{ timepoint->Sekunden = fixnum(tm->tm_sec);
timepoint->Minuten = fixnum(tm->tm_min);
timepoint->Stunden = fixnum(tm->tm_hour);
timepoint->Tag = fixnum(tm->tm_mday);
timepoint->Monat = fixnum(1+tm->tm_mon);
timepoint->Jahr = fixnum(1900+tm->tm_year);
}
else
# gescheitert -> verwende 1.1.1900, 00:00:00 als Default
{ timepoint->Sekunden = Fixnum_0;
timepoint->Minuten = Fixnum_0;
timepoint->Stunden = Fixnum_0;
timepoint->Tag = Fixnum_1;
timepoint->Monat = Fixnum_1;
timepoint->Jahr = fixnum(1900);
}
}}
#endif
# UP: Initialisiert die Zeitvariablen beim LISP-System-Start.
# init_time();
global void init_time (void);
global void init_time()
{
# Es ist noch keine GC dagewesen -> hat auch noch keine Zeit verbraucht.
# gc_count=0;
# gc_time=0;
# gc_space=0;
#ifdef TIME_RELATIVE
realstart_time = get_time(); # Zeitzähler jetzt, beim Systemstart
#endif
#ifndef HAVE_RUN_TIME
# run_time = 0; # Noch keine Run-Time verbraucht,
# run_flag = FALSE; # denn System läuft noch nicht.
run_time_restart(); # Run-Time-Stoppuhr loslaufen lassen
#endif
#if defined(TIME_UNIX) || defined(TIME_WIN32)
realstart_time = *(get_real_time()); # Zeitzähler jetzt, beim Systemstart
#endif
#ifdef TIME_RELATIVE
# Start-Zeit holen und merken:
{ var decoded_time timepoint;
#ifdef AMIGAOS
{ var struct DateStamp datestamp; # aktuelle Uhrzeit
DateStamp(&datestamp);
convert_time(&datestamp,&timepoint); # in Decoded-Time umwandeln
}
#endif
#if defined(DJUNIX) && 0 # das geht eine Stunde nach!!
{ var struct timeval real_time;
gettimeofday(&real_time,NULL); # aktuelle Uhrzeit
convert_time(&real_time.tv_sec,&timepoint); # in Decoded-Time umwandeln
}
#endif
#if defined(DJUNIX) || defined(WATCOM) || defined(EMUNIX_OLD_8d) || defined(WINDOWS)
{ var internal_decoded_time idt;
get_decoded_time(&idt);
timepoint.Sekunden = fixnum(idt.sec);
timepoint.Minuten = fixnum(idt.min);
timepoint.Stunden = fixnum(idt.hour);
timepoint.Tag = fixnum(idt.day);
timepoint.Monat = fixnum(idt.month);
timepoint.Jahr = fixnum(idt.year);
}
#endif
#if defined(EMUNIX_NEW_8e) && !defined(WINDOWS)
{ var struct timeb real_time;
begin_system_call();
__ftime(&real_time); # aktuelle Uhrzeit
end_system_call();
convert_time(&real_time.time,&timepoint); # in Decoded-Time umwandeln
}
#endif
#if defined(UNIX) || defined(RISCOS) # TIME_UNIX_TIMES || TIME_RISCOS
{ var time_t real_time;
begin_system_call();
time(&real_time); # aktuelle Uhrzeit
end_system_call();
convert_time(&real_time,&timepoint); # in Decoded-Time umwandeln
}
#endif
set_start_time(&timepoint); # Start-Zeit merken
}
#endif
}
# ------------------------------------------------------------------------------
# Zeitfunktionen
#ifdef TIME_AMIGAOS
# Ein kleineres Bug:
# - Wrap-Around der Uhrzeit nach 2.7 Jahren.
# Decoded Time =
# Sekunde, Minute, Stunde, Tag, Monat, Jahr, Wochentag, Sommerzeit, Zeitzone
# Universal Time =
# Sekunden seit 1.1.1900
# Internal Time =
# 50stel Sekunden seit LISP-System-Start
#endif
#ifdef TIME_MSDOS
# Ein kleineres Bug:
# - Wrap-Around der Uhrzeit nach 1.36 Jahren.
# Decoded Time =
# Sekunde, Minute, Stunde, Tag, Monat, Jahr, Wochentag, Sommerzeit, Zeitzone
# Universal Time =
# Sekunden seit 1.1.1900
# Internal Time =
# 100stel Sekunden seit LISP-System-Start
#endif
#if defined(TIME_UNIX_TIMES) || defined(TIME_RISCOS)
# Zwei kleinere Bugs:
# - Wrap-Around der Uhrzeit nach vielen Tagen,
# - LISP-Uhr geht um max. 1 Sekunde nach gegenüber der wahren Uhr.
# Decoded Time =
# Sekunde, Minute, Stunde, Tag, Monat, Jahr, Wochentag, Sommerzeit, Zeitzone
# Universal Time =
# Sekunden seit 1.1.1900
# Internal Time =
# CLK_TCK-stel Sekunden seit LISP-System-Start
#endif
#if defined(TIME_UNIX) || defined(TIME_WIN32)
# Ein kleineres Bug:
# - %%TIME funktioniert nur für Zeitdifferenzen <= 194 Tagen.
# Decoded Time =
# Sekunde, Minute, Stunde, Tag, Monat, Jahr, Wochentag, Sommerzeit, Zeitzone
# Universal Time =
# Sekunden seit 1.1.1900
# Internal Time =
# Mikrosekunden seit LISP-System-Start
#endif
#ifdef TIME_RELATIVE
# Uhrzeit und Datum beim LISP-Start:
local decoded_time realstart_datetime;
# UP: Berechnet die Uhrzeit beim LISP-System-Start als Universal Time.
# calc_start_UT(&timepoint)
# > decoded_time timepoint: Zeit beim LISP-System-Start
# < ergebnis: Universal Time
# kann GC auslösen
local object calc_start_UT (decoded_time* timepoint);
local object calc_start_UT(timepoint)
var reg1 decoded_time* timepoint;
{ # (ENCODE-UNIVERSAL-TIME Sekunden Minuten Stunden Tag Monat Jahr) ausführen:
pushSTACK(timepoint->Sekunden);
pushSTACK(timepoint->Minuten);
pushSTACK(timepoint->Stunden);
pushSTACK(timepoint->Tag);
pushSTACK(timepoint->Monat);
pushSTACK(timepoint->Jahr);
funcall(S(encode_universal_time),6);
# als Start-Universal-Time abspeichern:
return O(start_UT) = value1;
}
# UP: Merkt sich die Uhrzeit beim LISP-System-Start.
# set_start_time(&timepoint);
# > timepoint: Zeit beim LISP-System-Start
# > timepoint.Sekunden in {0,...,59},
# > timepoint.Minuten in {0,...,59},
# > timepoint.Stunden in {0,...,23},
# > timepoint.Tag in {1,...,31},
# > timepoint.Monat in {1,...,12},
# > timepoint.Jahr in {1980,...,2999},
# > jeweils als Fixnums.
# kann GC auslösen
global void set_start_time (decoded_time* timepoint);
global void set_start_time(timepoint)
var reg1 decoded_time* timepoint;
{ # Start-Zeit merken:
realstart_datetime = *timepoint;
# und, wenn möglich, gleich in Universal Time umwandeln:
if (!eq(Symbol_function(S(encode_universal_time)),unbound))
# Ist ENCODE-UNIVERSAL-TIME definiert -> sofort in UT umwandeln:
{ calc_start_UT(timepoint); }
}
#endif
# Liefert die Uhrzeit in Sekunden (seit Systemstart bzw. 1.1.1900) als uintL.
local uintL real_time_sec (void);
local uintL real_time_sec()
{
#ifdef TIME_1
var reg2 uintL real_time = get_real_time();
# real_time := floor(real_time,ticks_per_second) :
#if (ticks_per_second == 1000000UL)
divu_3216_3216(real_time>>6,ticks_per_second>>6,real_time=,_EMA_);
#elif (ticks_per_second < bit(16))
divu_3216_3216(real_time,ticks_per_second,real_time=,_EMA_);
#else
divu_3232_3232(real_time,ticks_per_second,real_time=,_EMA_);
#endif
#endif
#ifdef TIME_2
var reg2 uintL real_time = (get_real_time())->tv_sec; # Sekunden
#if defined(TIME_UNIX) || defined(TIME_WIN32)
# real_time sind Sekunden seit 1.1.1970
real_time = 2208988800UL+real_time; # 25567*24*60*60 Sekunden zwischen 1.1.1900 und 1.1.1970
#endif
#endif
return real_time;
}
LISPFUNN(get_universal_time,0)
# (get-universal-time), CLTL S. 445
#ifdef TIME_RELATIVE
# (defun get-universal-time ()
# (+ (sys::get-start-time)
# (floor (get-internal-real-time) internal-time-units-per-second)
# ) )
{ var reg1 object start_time = O(start_UT);
if (nullp(start_time)) # Start-Universal-Time noch NIL ?
# nein -> schon berechnet.
# ja -> jetzt erst berechnen:
{ start_time = calc_start_UT(&realstart_datetime); }
# start_time = die Uhrzeit des LISP-System-Starts in Universal Time.
pushSTACK(start_time);
pushSTACK(UL_to_I(real_time_sec())); # Sekunden seit Systemstart
funcall(L(plus),2); # addieren
}
#endif
#ifdef TIME_ABSOLUTE
{ value1 = UL_to_I(real_time_sec()); mv_count=1; }
#endif
#if defined(UNIX) || defined(WIN32_UNIX)
LISPFUN(default_time_zone,0,1,norest,nokey,0,NIL)
# (sys::default-time-zone) liefert die aktuelle Zeitzone.
# (sys::default-time-zone UTstunde) liefert die aktuelle Zeitzone zu einem
# bestimmten Zeitpunkt.
# 1. Wert: Zeitzone mit Sommerzeit-Berücksichtigung.
# 2. Wert: Sommerzeit-p.
{ # Da die Zeitzone oft per TZ-Environment-Variable einstellbar ist, wird
# sie häufig außerhalb des Kernels verwaltet. Man hat nur per localtime()
# und gmtime() Zugriff auf sie.
# Methode:
# Zeitzone = (gmtime(t) - localtime(t))/3600.
# Sommerzeit-p wird dem Ergebnis von localtime(t) entnommen.
var reg4 object arg = popSTACK();
var time_t now;
if (posfixnump(arg)
&& (posfixnum_to_L(arg) > 613608) # arg > 1.1.1970
&& (posfixnum_to_L(arg) < 1314888) # arg < 1.1.2050
)
# bestimmter Zeitpunkt
# Annahme: time_t ist die Anzahl der Sekunden seit 1.1.1970. ??
{ now = (posfixnum_to_L(arg) - 613608) * 3600; }
else
# jetzt
{ begin_system_call(); time(&now); end_system_call(); }
{ var struct tm now_local;
var struct tm now_gm;
begin_system_call();
now_local = *(localtime(&now));
now_gm = *(gmtime(&now));
end_system_call();
# secondswest = mktime(now_gm) - mktime(now_local); wäre schön.
# mktime() ist allerdings nicht weit verbreitet. Unter SunOS4 müßte man
# timegm() nehmen. Daher tun wir's selber:
{var reg5 sintL dayswest = # Tage-Differenz, kann als 0,1,-1 angenommen werden
(now_gm.tm_year < now_local.tm_year ? -1 :
now_gm.tm_year > now_local.tm_year ? 1 :
(now_gm.tm_mon < now_local.tm_mon ? -1 :
now_gm.tm_mon > now_local.tm_mon ? 1 :
(now_gm.tm_mday < now_local.tm_mday ? -1 :
now_gm.tm_mday > now_local.tm_mday ? 1 :
0
)));
var reg3 sintL hourswest = 24*dayswest + (sintL)(now_gm.tm_hour - now_local.tm_hour);
var reg2 sintL minuteswest = 60*hourswest + (sintL)(now_gm.tm_min - now_local.tm_min);
var reg1 sintL secondswest = 60*minuteswest + (sintL)(now_gm.tm_sec - now_local.tm_sec);
# Zeitzone in Stunden = (Zeitzone in Sekunden / 3600) :
pushSTACK(L_to_I(secondswest));
pushSTACK(fixnum(3600));
funcall(L(durch),2);
# Sommerzeit-p entnehmen:
# tm_isdst < 0 bedeutet "unbekannt"; wir nehmen an, keine Sommerzeit.
value2 = (now_local.tm_isdst > 0 ? T : NIL);
mv_count=2;
} }}
#endif
LISPFUNN(get_internal_run_time,0)
# (GET-INTERNAL-RUN-TIME), CLTL S. 446
{ var timescore tm;
get_running_times(&tm); # Run-Time seit LISP-System-Start abfragen
#ifdef TIME_1
value1 = UL_to_I(tm.runtime); mv_count=1; # in Integer umwandeln
#endif
#ifdef TIME_2
{ var reg1 internal_time* tp = &tm.runtime; # Run-Time
# in Mikrosekunden umwandeln: tp->tv_sec * ticks_per_second + tp->tv_usec
#ifdef intQsize
value1 = UQ_to_I((uintQ)(tp->tv_sec) * ticks_per_second + (uintQ)(tp->tv_usec));
#else
{var reg3 uintL run_time_hi;
var reg2 uintL run_time_lo;
mulu32(tp->tv_sec,ticks_per_second, run_time_hi=,run_time_lo=);
if ((run_time_lo += tp->tv_usec) < tp->tv_usec) { run_time_hi += 1; }
value1 = L2_to_I(run_time_hi,run_time_lo);
}
#endif
mv_count=1;
}
#endif
}
LISPFUNN(get_internal_real_time,0)
# (GET-INTERNAL-REAL-TIME), CLTL S. 446
#ifdef TIME_1
{ value1 = UL_to_I(get_real_time()); # Real-Time seit LISP-System-Start, als Integer
mv_count=1;
}
#endif
#ifdef TIME_2
{ var reg1 internal_time* tp = get_real_time(); # Real-Time absolut
# in Mikrosekunden umwandeln: tp->tv_sec * ticks_per_second + tp->tv_usec
#ifdef intQsize
value1 = UQ_to_I((uintQ)(tp->tv_sec) * ticks_per_second + (uintQ)(tp->tv_usec));
#else
{var reg3 uintL real_time_hi;
var reg2 uintL real_time_lo;
mulu32(tp->tv_sec,ticks_per_second, real_time_hi=,real_time_lo=);
if ((real_time_lo += tp->tv_usec) < tp->tv_usec) { real_time_hi += 1; }
value1 = L2_to_I(real_time_hi,real_time_lo);
}
#endif
mv_count=1;
}
#endif
#ifdef SLEEP_1
LISPFUNN(sleep,1)
#if defined(TIME_MSDOS) || defined(RISCOS)
# (SYSTEM::%SLEEP delay) wartet delay/200 bzw. delay/100 Sekunden.
# Argument delay muß ein Integer >=0, <2^32 (TIME_MSDOS: sogar <2^31) sein.
{ var reg2 uintL delay = I_to_UL(popSTACK()); # Pausenlänge
#ifdef EMUNIX_PORTABEL
#ifdef EMUNIX_OLD_8e
if (!(_osmode == DOS_MODE))
#else
if (TRUE)
#endif
# Unter OS/2 (Multitasking!) nicht CPU-Zeit verbraten!
# select erlaubt eine wunderschöne Implementation von usleep():
{ loop
{ var reg4 uintL start_time = get_real_time();
{ var struct timeval timeout; # Zeitintervall
divu_3216_3216(delay,ticks_per_second, timeout.tv_sec =, timeout.tv_usec = 1000000/ticks_per_second * (uintL) );
begin_system_call();
{var reg1 int ergebnis = select(FD_SETSIZE,NULL,NULL,NULL,&timeout);
end_system_call();
if ((ergebnis<0) && !(errno==EINTR)) { OS_error(); }
}}
interruptp( { pushSTACK(S(sleep)); tast_break(); } ); # evtl. Break-Schleife aufrufen
{var reg3 uintL end_time = get_real_time();
var reg1 uintL slept = end_time - start_time; # so lang haben wir geschlafen
# Haben wir genug geschlafen?
if (slept >= delay) break;
# Wie lange müssen wir noch schlafen?
delay -= slept;
}}
}
else
#endif
{ var reg1 uintL endtime = get_real_time() + delay; # zur momentanen Real-Time addieren,
# ergibt Zeit, bis zu der zu warten ist.
# warten, bis die Real-Time bei endtime angelangt ist:
# (Attention: the MSDOS clock always advances 5 or 6 ticks at a time!)
do {} until ((sintL)(get_real_time()-endtime) >= 0);
}
value1 = NIL; mv_count=1; # 1 Wert NIL
}
#endif
#ifdef TIME_AMIGAOS
# (SYSTEM::%SLEEP delay) wartet delay/50 Sekunden.
# Argument delay muß ein Integer >=0, <2^32 sein.
{ var reg2 uintL delay = I_to_UL(popSTACK()); # Pausenlänge
if (delay>0) { begin_system_call(); Delay(delay); end_system_call(); }
value1 = NIL; mv_count=1; # 1 Wert NIL
}
#endif
#endif
#ifdef SLEEP_2
#ifdef TIME_UNIX_TIMES
# Ein sehr unvollkommener Ersatz für die gettimeofday-Funktion.
# Taugt nur für die Messung von Zeitdifferenzen!
local int gettimeofday (struct timeval * tp, void* tzp);
local int gettimeofday(tp,tzp)
var reg2 struct timeval * tp;
var void* tzp;
{ if (!(tp==NULL))
{ var reg1 uintL realtime = get_real_time();
# in Sekunden und Mikrosekunden umwandeln:
tp->tv_sec = floor(realtime,ticks_per_second);
tp->tv_usec = (realtime % ticks_per_second) * floor(2*1000000+ticks_per_second,2*ticks_per_second);
}
return 0;
}
#endif
LISPFUNN(sleep,2)
#if defined(TIME_UNIX) || defined(TIME_UNIX_TIMES)
# (SYSTEM::%SLEEP delay-seconds delay-useconds) wartet
# delay-seconds Sekunden und delay-useconds Mikrosekunden.
# Argument delay-seconds muß ein Fixnum >=0, <=16700000 sein,
# Argument delay-useconds muß ein Fixnum >=0, <=1000000 sein.
{ var reg3 uintL useconds = posfixnum_to_L(popSTACK());
var reg2 uintL seconds = posfixnum_to_L(popSTACK());
begin_system_call();
loop
{ var struct timeval start_time;
var struct timeval end_time;
if (!( gettimeofday(&start_time,NULL) ==0)) { OS_error(); }
#ifdef HAVE_SELECT
# select erlaubt eine wunderschöne Implementation von usleep():
{ var struct timeval timeout; # Zeitintervall
timeout.tv_sec = seconds; timeout.tv_usec = useconds;
{var reg1 int ergebnis;
ergebnis = select(FD_SETSIZE,NULL,NULL,NULL,&timeout);
if ((ergebnis<0) && !(errno==EINTR)) { OS_error(); }
}}
#else
if (seconds>0) { sleep(seconds); }
#ifdef HAVE_USLEEP
if (useconds>0) { usleep(useconds); }
#endif
#endif
interruptp(
{ end_system_call();
pushSTACK(S(sleep)); tast_break(); # evtl. Break-Schleife aufrufen
begin_system_call();
});
if (!( gettimeofday(&end_time,NULL) ==0)) { OS_error(); }
{# Überprüfen, ob wir genügend lang geschlafen haben, oder ob
# wir wegen eines Signals zu früh aufgeweckt wurden:
var struct timeval slept; # so lang haben wir geschlafen
# sozusagen sub_internal_time(end_time,start_time, slept);
slept.tv_sec = end_time.tv_sec - start_time.tv_sec;
if (end_time.tv_usec < start_time.tv_usec)
{ end_time.tv_usec += 1000000; slept.tv_sec -= 1; }
slept.tv_usec = end_time.tv_usec - start_time.tv_usec;
# Haben wir genug geschlafen?
if ((slept.tv_sec > seconds)
|| ((slept.tv_sec == seconds) && (slept.tv_usec >= useconds))
)
break;
# Wie lange müssen wir noch schlafen?
seconds -= slept.tv_sec;
if (useconds < slept.tv_usec) { seconds -= 1; useconds += 1000000; }
useconds -= slept.tv_usec;
#if !defined(HAVE_SELECT) && !defined(HAVE_USLEEP)
if (seconds==0) break; # CPU-Zeit fressende Warteschleife vermeiden
#endif
}}
end_system_call();
value1 = NIL; mv_count=1; # 1 Wert NIL
}
#elif defined(TIME_WIN32)
{ var reg3 uintL useconds = posfixnum_to_L(popSTACK());
var reg2 uintL seconds = posfixnum_to_L(popSTACK());
begin_system_call();
Sleep(seconds*1000+useconds/1000);
end_system_call();
value1 = NIL; mv_count=1;
}
#endif
#endif
LISPFUNN(time,0)
# (SYSTEM::%%TIME) liefert den bisherigen Time/Space-Verbrauch, ohne selbst
# Platz anzufordern (und damit eventuell selbst eine GC zu verursachen).
# 9 Werte:
# Real-Time (Zeit seit Systemstart) in 2 Werten,
# Run-Time (verbrauchte Zeit seit Systemstart) in 2 Werten,
# GC-Time (durch GC verbrauchte Zeit seit Systemstart) in 2 Werten,
# #ifdef TIME_AMIGAOS
# jeweils in 50stel Sekunden,
# jeweils (ldb (byte 16 16) time) und (ldb (byte 16 0) time).
# #endif
# #ifdef TIME_MSDOS
# jeweils in 100stel Sekunden,
# jeweils (ldb (byte 16 16) time) und (ldb (byte 16 0) time).
# #endif
# #if defined(TIME_UNIX_TIMES) || defined(TIME_RISCOS)
# jeweils in CLK_TCK-stel Sekunden,
# jeweils (ldb (byte 16 16) time) und (ldb (byte 16 0) time).
# #endif
# #ifdef TIME_UNIX
# jeweils in Mikrosekunden, jeweils ganze Sekunden und Mikrosekunden.
# #endif
# #ifdef TIME_WIN32
# jeweils in Mikrosekunden, jeweils ganze Sekunden und Mikrosekunden.
# #endif
# Space (seit Systemstart verbrauchter Platz, in Bytes)
# in 2 Werten: (ldb (byte 24 24) Space), (ldb (byte 24 0) Space).
# GC-Count (Anzahl der durchgeführten Garbage Collections).
{ var timescore tm;
get_running_times(&tm); # Run-Time abfragen
#ifdef TIME_1
#define as_2_values(time) \
pushSTACK(fixnum(high16(time))); \
pushSTACK(fixnum(low16(time)));
#endif
#ifdef TIME_2
#define as_2_values(time) \
pushSTACK(fixnum(time.tv_sec)); \
pushSTACK(fixnum(time.tv_usec));
#endif
as_2_values(tm.realtime); # erste zwei Werte: Real-Time
as_2_values(tm.runtime); # nächste zwei Werte: Run-Time
as_2_values(tm.gctime); # nächste zwei Werte: GC-Time
# nächste zwei Werte: Space
# tm.gcfreed = von der GC bisher wieder verfügbar gemachter Platz
{var reg1 uintL used = used_space(); # momentan belegter Platz
# beides addieren:
#ifdef intQsize
tm.gcfreed += used;
#else
if ((tm.gcfreed.lo += used) < used) { tm.gcfreed.hi += 1; }
#endif
}
# Jetzt ist tm.gcfreed = bisher insgesamt verbrauchter Platz
#if (oint_data_len<24)
#error "Funktion SYS::%%TIME anpassen!"
#endif
# In 24-Bit-Stücke zerhacken:
#ifdef intQsize
pushSTACK(fixnum( (tm.gcfreed>>24) & (bit(24)-1) ));
pushSTACK(fixnum( tm.gcfreed & (bit(24)-1) ));
#else
pushSTACK(fixnum( ((tm.gcfreed.hi << 8) + (tm.gcfreed.lo >> 24)) & (bit(24)-1) ));
pushSTACK(fixnum( tm.gcfreed.lo & (bit(24)-1) ));
#endif
# letzter Wert: GC-Count
pushSTACK(fixnum(tm.gccount));
funcall(L(values),9); # 9 Werte produzieren
}