![]() |
![]() |
#1 |
Registered User
Join Date: Sep 2007
Location: Melbourne/Australia
Posts: 4,455
|
Getting millisecond elapsed time using Bebbo's Amiga GCC toolchain
Hi,
Wonder if anyone can help. I need a fast way to tack how much time has passed in my main loop. I normally use https://www.tutorialspoint.com/c_sta...tion_clock.htm which has a high frequency on the old GCC 3.4 (milliseconds) but in my Bebbo build it seems to be limited to 50fps. I've hacked together the following code but I'm not really sure it's the best way to do it. Code:
gettimeofday(&lastFrameTime, NULL); while (true) { gettimeofday(¤tFrameTime, NULL); double elapsedtime = (currentFrameTime.tv_sec - lastFrameTime.tv_sec) * 1000.0; // sec to ms elapsedtime += (currentFrameTime.tv_usec - lastFrameTime.tv_usec) / 1000.0; // us to ms // Capture user input and update object positions. g_world->updateWorld(elapsedtime / 1000); g_world->updateFrame(); memcpy(&lastFrameTime, ¤tFrameTime, sizeof(struct timeval)); } Thanks ![]() |
![]() |
![]() |
#2 |
<optimized out>
Join Date: Sep 2020
Location: <optimized out>
Posts: 323
|
I don't have a lot of context, but if you're limited to 50 fps, maybe you're using the wrong CIA timer in your gettimeofday?
Anyway, in case it helps, this is how I do it, having taken over the system: Code:
ULONG GetCurrentTime(void) { ULONG hi = ciab->ciatodhi; // latch activated ULONG mid = ciab->ciatodmid; ULONG low = ciab->ciatodlow; // latch deactivated return ((hi << 8 | mid) << 8 | low) << 8; } Code:
Display_Show(); game.isPaused = FALSE; ULONG previousTime = GetCurrentTime(); ULONG lag = 0; Game_UpdateDisplay(); for (;;) { ULONG currentTime = GetCurrentTime(); ULONG elapsedTime = currentTime - previousTime; ULONG fps = (256 * CLOCK_CONSTANT) / (227 * elapsedTime); previousTime = currentTime; lag += elapsedTime; ULONG ticks = 0; while (lag >= TIMER_INCREMENT_PER_SIMULATION_STEP) { Game_ProcessUserInput(); if (game.exitRequested) break; Game_UpdateState(); lag -= TIMER_INCREMENT_PER_SIMULATION_STEP; ticks++; } if (game.exitRequested) break; Game_UpdateDisplay(); TinyText_MoveTo(80 - 8, 0); TinyText_PrintFormatted("%4ld fps", fps); TinyText_MoveTo(80 - 8, 1); TinyText_PrintFormatted("%4ld ipf", ticks); } game.isPaused = TRUE; PrintStatistics(); Code:
ciab->ciacrb &= ~CIACRBF_ALARM; |
![]() |
![]() |
#3 | |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,451
|
Quote:
No, I do not recommend accessing the hardware. Reading the E-clock has certain quirks the Os takes care of. |
|
![]() |
![]() |
#4 | |
Registered User
Join Date: Sep 2007
Location: Melbourne/Australia
Posts: 4,455
|
Quote:
Yep, I'm currently using gettimeofday (see my code snippet above). I would prefer to just use clock() but the resolution is too low with GCC 6.5 (at least in this build, not sure if it can be changed?). My code works fine, just looks messy and maybe slow. I don't want to take over the system, I normally try and write OS friendly code if possible. I did have a quick look at eclock, I'll try and get it working. I'm only interested in elapsed time per frame so it doesn't matter if it looses a few seconds over time. Do you have to do any setup code to use ReadEClock()? LoL, turns out that I was asking about this 13 years ago ![]() https://eab.abime.net/showthread.php?t=59705 This is also helpful.. https://eab.abime.net/showthread.php?t=59869 Last edited by NovaCoder; Yesterday at 01:55. |
|
![]() |
![]() |
#5 |
Computer Nerd
Join Date: Sep 2007
Location: Rotterdam/Netherlands
Age: 48
Posts: 3,938
|
|
![]() |
![]() |
#6 | |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 690
|
Quote:
luckily I stumbled across this thread... Better raise an issue at https://github.com/bebbo/libnix/issues - this warrants that I read it, but not that I fix/change it^^ I changed clock() to use ReadEClock() instead of DateStamp(). Should be live soon. |
|
![]() |
![]() |
#7 |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 690
|
|
![]() |
![]() |
#8 |
ex. demoscener "Bigmama"
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,659
|
Isn't clock() supposed to give you the cpu time used by the current process (I.e. not absolute time) ?
|
![]() |
![]() |
#9 | |
Registered User
Join Date: Sep 2007
Location: Melbourne/Australia
Posts: 4,455
|
Quote:
![]() |
|
![]() |
![]() |
#10 | |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 690
|
Quote:
"The clock() function shall return the implementation's best approximation to the processor time used by the process since the beginning of an implementation-defined era related only to the process invocation." ... "In order to measure the time spent in a program, clock() should be called at the start of the program and its return value subtracted from the value returned by subsequent calls." The time spent is not the used cpu time. |
|
![]() |
![]() |
#11 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,451
|
Argh! This is a dos private! It is not guaranteed to stay there. OpenDevice() is not asking for too much.
|
![]() |
![]() |
#12 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,451
|
Note that ReadEClock() is not long-time stable, but DateStamp() is, so it depends on what you want to do. If clock resolution matters, there is also clock_gettime(), which offers multiple clocks. One could be mapped to the E-clock, others to the system (VBI-based) clock.
|
![]() |
![]() |
#13 | |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 690
|
Quote:
I followed these docs |
|
![]() |
![]() |
#14 | |
ex. demoscener "Bigmama"
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,659
|
Quote:
![]() Also: https://www.gnu.org/software/libc/ma.../CPU-Time.html I was just asking in order to make people aware of the distinction between cpu time spent by the process and wall time regarding the clock() function. What you do with your c library is up to you, of course. |
|
![]() |
![]() |
#15 |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,451
|
Unfortunately AmigaOs has nothing to offer in terms of processor time. Since the OP used gettimeofday() which supplies wall-clock time, ReadEClock() is probably the best viable option for microsecond resolution.
|
![]() |
![]() |
#16 | |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 690
|
Quote:
I cited. And it also reads: "the implementation's best approximation". Right now this is the best approximation. Feel free to provide a better one. |
|
![]() |
![]() |
#17 | |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,570
|
Quote:
But gettimeofday() is no portable ISO-C. Before calling emulated POSIX or BSD functions you can also call Amiga-functions with much less overhead. ![]() It unfortunately is. And such a function should be in the OS. Maybe the OS3.3-team reads this... ![]() I remember I implemented a real clock() in vclib for MorphOS, because the OS provides it, which is quite nice: Code:
clock_t clock(void) { UQUAD ticks,cputime; NewGetSystemAttrs(&ticks,sizeof(ticks),SYSTEMINFOTYPE_LASTSECTICKS,TAG_DONE); NewGetTaskAttrs(FindTask(NULL),&cputime,sizeof(cputime), TASKINFOTYPE_CPUTIME,TAG_DONE); return (clock_t)((CLOCKS_PER_SEC * cputime) / ticks); } |
|
![]() |
![]() |
#18 |
Registered User
Join Date: Feb 2017
Location: Denmark
Posts: 1,289
|
FWIW even latest MSVC on Windows (probably due to backwards compatibility) also returns wall clock time since the process started (not the time used by the process) for clock(), and in DOS days it used the 18.2Hz timer so precision was not great.
Like phx mentions it very likely wouldn't make sense to use process time for OPs case. Don't think I've ever head of a game (intentionally) timed to the process-time.. Doesn't seem like there's any reason to overthink it. Just use EClock. I'm very sure the marginal drift is negligible. If not, then tie you timing to something that does matter (like audio playback). Use is pretty, simple, basic template: Code:
struct Device* TimerBase; static struct timerequest TimerRequest; static uint32_t TimerRate; uint64_t TimerRead(void) { struct EClockVal val; ReadEClock(&val); return (uint64_t)val.ev_hi << 32 | val.ev_lo; } .. /* Init */ if (OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)&TimerRequest, 0L)) /* Should not happen... */ TimerBase = TimerRequest.tr_node.io_Device; struct EClockVal val; TimerRate = ReadEClock(&val); /* Use TimerRead here..*/ /* Cleanup */ CloseDevice((struct IORequest*)&TimerRequest); |
![]() |
![]() |
#19 |
Registered User
Join Date: Aug 2010
Location: Germany
Posts: 540
|
Here is some code (proably not too complete) which I'm using to converting the EClock timer value into a reference time which increases monotonously. You need gcc or any other compiler which supports 64 bit integers to make it work.
Code:
#include <proto/timer.h> #include <proto/exec.h> #include <string.h> #define OK 0 ULONG EClockFrequency; unsigned long long EClockReference; ULONG EClockMicrosecondFactor; struct timerequest TimerRequest; struct Library * TimerBase; BOOL init_time_elapsed(void) { struct EClockVal eclock_reference; BOOL successful = FALSE; memset(&TimeRequest, 0, sizeof(TimeRequest)); if (OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)&TimerRequest, 0) == OK) { TimerBase = TimerRequest.tr_node.io_Device; EClockFrequency = ReadEClock(&eclock_reference); EClockReference = (((unsigned long long)eclock_reference.ev_hi) << 32) | eclock_reference.ev_lo; EClockMicrosecondFactor = 65536ULL * 1000000ULL / EClockFrequency; successful = TRUE; } } void get_time_elapsed(struct timeval * time_elapsed_ptr) { struct EClockVal now; unsigned long long time_elapsed; unsigned long long eclock_elapsed; ULONG seconds_remainder; unsigned long long microseconds; ReadEClock(&now); eclock_now = (((unsigned long long)now.ev_hi) << 32) | now.ev_lo; /* How many EClock ticks occurred since the reference point? */ eclock_elapsed = eclock_now - EClockReference; /* Turn the number of EClock ticks into the number of seconds * and a remainder value which still needs to be normalized * in order to yield the proper number of microseconds. */ time_elapsed_ptr->tv_secs = eclock_elapsed / EClockFrequency; seconds_remainder = eclock_elapsed % EClockFrequency; /* The remainder of the EClock frequency division needs to be * normalized so that it comes out as the number of microseconds. * The conversion is performed by multiplying with a precalculated * factor which has been premultiplied by 65536. That scaling * needs to be taken out of the end result and does not require a division. */ microseconds = seconds_remainder * EClockMicrosecondFactor; time_elapsed_ptr->tv_micro = microseconds >> 16; /* Paranoia: make sure that the output is really "normal". */ while (time_elapsed.tv_micro > 1000000) { time_elapsed.tv_secs++; time_elapsed.tv_micro -= 1000000; } } |
![]() |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Setting up a debugging environment for Bebbo's Amiga GCC toolchain | Nightfox | Coders. C/C++ | 3 | 12 July 2024 19:48 |
GCC 6.2 toolchain for AmigaOS 3 | Samurai_Crow | Coders. C/C++ | 1555 | 01 May 2024 19:56 |
Can't make bebbo's amiga-gcc work | Bren McGuire | Coders. General | 18 | 12 June 2023 01:09 |
bebbo gcc+eclipse problem | Raislin77it | Coders. C/C++ | 1 | 15 February 2022 08:37 |
gcc-bebbo: argc is always 0 | sparhawk | Coders. C/C++ | 8 | 31 January 2021 18:42 |
|
|