Get Numer Of Timer Ticks

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
JoeTheProgrammer
Member
Member
Posts: 48
Joined: Mon Aug 13, 2007 2:30 pm

Get Numer Of Timer Ticks

Post by JoeTheProgrammer »

I need to get the number of timer ticks total since the system has booted. Is it possible to do this in assembly? If so, how?

Thanks,
Joseph
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

well i know there is an instruction in assembly that can tell you how many clocks cycles the cpu has gone through. other than that if you use a custom boot loader, you can pass the number of ticks your bootloader counted. other than that, i have no idea.
User avatar
Jef
Member
Member
Posts: 112
Joined: Tue Jan 08, 2008 7:25 am
Location: Greece
Contact:

Post by Jef »

if the boot loader is written by you, put the RDTSC instruction at the start, and once at the end of system loading. Do the maths and you will find it.
see also: http://en.wikipedia.org/wiki/RDTSC
Keep coding...
...the sky is the limit

AsteriOS project: http://www.mindfields.gr/main/index.php ... &Itemid=27
xyzzy
Member
Member
Posts: 391
Joined: Wed Jul 25, 2007 8:45 am
Libera.chat IRC: aejsmith
Location: London, UK
Contact:

Post by xyzzy »

Just have a variable that gets incremented in the timer IRQ handler, and to get the number of ticks read that variable.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

In order to really answer your question, we need to know precisely what you mean by "timer ticks". There are at least 4 different timers ticking away in any machine. The 1 microsecond PIT timer, the 18.2Hz PIT rollover, the CPU internal clock (mentioned above), and the Real Time Clock (seconds). I'm happy just measuring seconds, myself -- especially so long as the final number is either 0 or 1. :wink:
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post by 01000101 »

I have the PIT 18.2 Hz rollover installed on IRQ 0, but I've been thinking, would it not be more efficient to just use the 1second timersto free up some processor time? instaed of it responding to an IRQ every 1/18th of a second, wouldn't it be better to have it respond only once a second? Also, I don't even use the timer_wait functions or anything similar anywhere in my OS and the only thing I can think of to use the timer for would be too... display the time active in the OS.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

Many people use the IRQ0 interrupt for involuntary task pre-emption. So, for them, it depends on how often they want preemptive task switches.

If you are only singletasking, or using cooperative multitasking, then the general rule is "the fewer interrupts the better", so yes.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
01000101 wrote:I have the PIT 18.2 Hz rollover installed on IRQ 0, but I've been thinking, would it not be more efficient to just use the 1second timersto free up some processor time? instaed of it responding to an IRQ every 1/18th of a second, wouldn't it be better to have it respond only once a second? Also, I don't even use the timer_wait functions or anything similar anywhere in my OS and the only thing I can think of to use the timer for would be too... display the time active in the OS.
Using a 1 Hz timer frequency would be more efficient, however it lacks precision (for e.g. "1.999 seconds" would look the same as "1.000 seconds").

Consider something like the "floppy motor on" delay time - when turning a floppy motor on, the device driver needs to wait for at least 500 ms for the motor to reach operating speed before the device driver sends a command.

If the floppy device driver asks for "one timer tick" delay, then the timer IRQ could occur immediately after the device driver asks for the delay and in this case the delay could be (almost) zero seconds. Alternatively, the timer IRQ could occur immediately before the device driver asks for the delay and the device driver's delay would be (almost) 1 full second. Because your timer lacks precision, you'd need to wait between 1 second and 2 seconds just to guarantee that the delay is at least 500 ms. Worst case is a user sitting there waiting to read some data from the floppy for 1.5 seconds longer than necessary.

The timer tick is also (usually) used for measuring how much CPU time each thread has consumed (used for measuring system load and for simplistic profiling), and for generating file system time-stamps.

For example, if 2 processes use "1 second" of CPU time each, then which process used less CPU time - the one that actually used 1.12303 seconds, or the one that actually used 1.8932 seconds? Even though the second process used 68% more CPU time you won't be able to measure a difference.

For time-stamps, most old file systems used 1 second timestamp precision until OS developers realised it's not adequate, and all newer file systems use much more precise time-stamps (e.g. millionths of a second). There's only 3 exceptions to this that I know of.

The first is FAT32, which shares much of it's design with FAT12 - the less said about it the better. :)

The second is the file system used by Minix 3, which still uses 1 second time stamp precision (but I assume Minix 3 is intended for educational purposes only, and teaching people how to do things poorly is what universities are for :twisted:).

The other exception is BeFS, which uses a different approach. Instead of using a "pure" time stamp it combines a 1 second time stamp with a 16-bit counter that guarantees that the final time stamps are (locally) unique. This avoids problems caused by poor time-stamp precision (e.g. trying to find out if one file is newer or older than another file that was created at almost the same time).

In any case, IMHO the OS (and it's file system/s) should be designed to handle at least nanosecond precision. The actual timer itself may not be as precise as the design allows (providing room for future growth is never a bad idea), but a 1 Hz timer is still too imprecise for anything invented after 1985... ;)


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

IMHO, trying to use filesystem timestamps for measuring relative "recentness" is completely unreasonable. Unless you go to completely unreasonable extremes (storing nanoseconds), eventually the machine will always become faster than can be measured by your timestamp -- which means that is not the right way to fix the problem. A reasonable filesystem will use seconds for filesystem timestamps (because that is all a human cares about), and will have a dedicated "version number" field. Having a dword to store seconds, and another dword to store version number takes the same amount of space as trying to store some ungodly tiny time increment, and is still more robust.

Brendan is right about precision -- however, you do not have to use interrupts to achieve what he is saying. In a singletasking system, you can always use the "microsecond" PIT countdown timer. If you are willing to use interrupts, you can use one-shots to measure short periods of time, also.
rv6502
Posts: 19
Joined: Fri Nov 02, 2007 8:28 pm

Post by rv6502 »

bewing wrote: Brendan is right about precision -- however, you do not have to use interrupts to achieve what he is saying. In a singletasking system, you can always use the "microsecond" PIT countdown timer. If you are willing to use interrupts, you can use one-shots to measure short periods of time, also.
NOOOOO :shock:
please do not use the PIT countdown timer: its buggy on about half the systems out there.

1) some chipsets cannot latch the MSB/LSB counters properly and you will get erroneous readings.
2) one-shot works fine as long as you dont hit the case where the PIT fired an interrupt just as you were about to reprogram it (interrupts disabled at this point).
you will get the previous interrupt just as you re-enable interrupts after reprogramming the PIT effectively nullifying any delays.

in any case, using the PIT for timing does NOT work reliably 100% of the time if you dont program it for a regular interval and leave it alone (the way it was designed) ](*,)

#2 will happen to the APIC timer as well.
you need to verify/validate the delay using a reliable timer counter such as the one that should be provided by RDTSC so you can ignore spurious timer interrupts.

I say *should* because RDTSC isnt reliable either, on previous and currently in use mobile CPUs the counter changes speed along with CPU when the power saving system kicks in, and on normal CPU the bus speed varies by as much as 10% as the clock circuits heat up / cool down.
also, in multi-processor systems each cpus have their own independant TSC so you must make sure you stick with the same CPU to check for short-delay timing.

your design need to take all this into account and expect and tolerate imprecise timers.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

rv6502 wrote: 1) some chipsets cannot latch the MSB/LSB counters properly and you will get erroneous readings.
I'd really like some more info on this, please.

Is your objection specifically that some CPUs get out of sync when reading the PIT MSB/LSB *pair*?

Brendan pointed out a trick to me. Please note that this can be done without changing the IRQ0 behavior, if your IRQ0 interval (the countdown reset value) is long enough.

Assume I were to send some OUTs to try to put the PIT into "MSB only" mode, and then read the PIT's state repeatedly -- would I see the MSB counting down properly on a "buggy" system? If not, what buggy operation could I see, and why? (This assumes, of course, that I am interested in timing something a bit longer than perhaps five hundred microseconds, to an accuracy of about 120us.)

And if I am timing something less than, say, four hundred microseconds, couldn't I do the same thing by setting the PIT to "LSB only" mode?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
bewing wrote:
rv6502 wrote: 1) some chipsets cannot latch the MSB/LSB counters properly and you will get erroneous readings.
I'd really like some more info on this, please.
There's 2 different problems that I'm aware of.

When you send the "latch counter" command to the the PIT, the PIT is meant to (atomically) copy the remaining count into a latch register so you can read it reliably.

On some chipsets this doesn't work quite right and you can lose a clock tick each time you latch the count, which can cause clock drift. One clock tick is roughly 838 ns, which means each time you read the timer count on a buggy chipset you could lose 838 ns; and if you read the timer count 1000 times per second (on average) you'd lose about 72.4 seconds per day.

Also, there's a "Neptune" Pentium chipset where the latch doesn't work properly at all. From Ralph Brown's Interrupt List (the file that lists I/O port details):

Code: Select all

 5-4	counter access
	00  counter latch command
		BUG:	Intel Neptune/Mercury Chipset 8237IB (SIO) needs a
			  short delay after issueing this command, else the
			  MSB may be outdated concerning the LSB, resulting
			  in large measuring errors.
			Workaround: Check for this condition by comparing
			  results with last results and don't use errornous
			  results.
Basically, the MSB of the latched value may be one more than it should be if the LSB wraps while the latch command is being handled by the PIT (e.g. you might read 0x12FF instead of 0x11FF because the LSB wrapped from 0x00 to 0xFF after the MSB was latched).

The simplest solution would be to repeatedly read the timer count until the most recent count is less than the previous count, like this:

Code: Select all

    disable_IRQs();
    second_count = get_PIT_count();
    do {
        first_count = second_count;
        second_count = get_PIT_count();
    } while (first_count < second_count);
    restore_IRQs();
Note: the timer count may have legitimately wrapped (e.g. from 0x0000 to 0xFFFF), so the simplest solution isn't necessarily a good solution (it can result in reading the count more than twice, when it should be possible to write better code that only ever reads the PIT count twice).

The other problem is that I/O port accesses to "ISA stuff" are slow (around 1 microsecond each, or about 1000 cycles on a 1 GHz CPU), and you need to do 3 of them to read the count (about 3000 cycles on a 1 GHz CPU).

This means that to read the count twice (to avoid the Neptune chipset problem) you'd get twice as much drift due to problem #1 (lost clock ticks) and it'd take twice as much CPU time (about 6000 cycles on a 1 GHz CPU).

Also note that for some CPUs there's a similar problem with RDTSC, where the high 32-bits may be "stale" (e.g. you could read the values 0x01234567FFFFFFFE then 0x0123456700000002 then 0x0123456800000004).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

But if you are only reading the MSB *or* LSB (not both), then you don't need to latch the value of the PIT register, right?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Post by Brendan »

Hi,
bewing wrote:But if you are only reading the MSB *or* LSB (not both), then you don't need to latch the value of the PIT register, right?
No...
pctim003.txt wrote:{JAM} Some CTC hardware implementations do not buffer the counter properly, so
if the Counting register is read at the instant it is changing value, you may
read the counter part-way through the 'ripple-through', i.e. some low-order bits
may have decremented but high-order bits may not have decremented yet.
Therefore, even in lobyte-only or hibyte-only mode, the Counting register cannot
be read reliably in this way.
You'd need to set the channel to "lobyte only" or "hibyte only" and then issue the latch command to get a reliable 8-bit count (e.g. without needing to worry about the "ripple through" or the stale MSB problem on the Neptune chipset, but still needing to worry about lost ticks).

That would reduce the overhead down to two I/O port accesses to read the counter.

For "lobyte only" it'd give you an 8-bit counter that decreases at the rate of one tick per 838 ns and wraps around every 214.5 us. For "hibyte only" it'd give you an 8-bit counter that decreases at the rate of one tick per 214.5 us and wraps around every 55 ms.

In both of these cases you'd probably need to use the timer IRQ to detect counter wrap. For example, setup PIT channel 0 to generate an IRQ at a rate of 4662 times per second (reload value = 0xFF) and use "lobyte only" to get the count (and use IRQ0 to increase a "number of times LSB has wrapped" variable). This would have it's own problems though: extra overhead from IRQ0 (interrupt, EOI, etc), race conditions between counter wrap and IRQ handling, and (potentially) power management implications (IRQ0 frequently taking the CPU out of it's HLT state, causing worse power consumption and heat).

If you're looking for "as perfect as possible" then I'd recommend using the best possible method that the hardware supports (RDTSC, localAPIC, HPFET, PIT) and consider seperating your requirements. For example, (if necessary) seperate the method used to keep track of real time from the method used for short time delays, so that (for e.g. if short time delays are measured using the PIT counter) your real time clock isn't effected by drift caused by short time delays.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
rv6502
Posts: 19
Joined: Fri Nov 02, 2007 8:28 pm

Post by rv6502 »

Brendan wrote:
Also note that for some CPUs there's a similar problem with RDTSC, where the high 32-bits may be "stale" (e.g. you could read the values 0x01234567FFFFFFFE then 0x0123456700000002 then 0x0123456800000004).
:shock: are you serious ?
](*,)

but at least its not on the ISA bus so reading it multiple times until you get twice the same high word and an incrementing total wont take an eternity, and there's relatively no chance that the 32bit counter will wrap multiple times between reads

(hey, if two consecutive RDTSC takes 4giga cycles with interrupts disabled you got a real hardware problem ;)

where reading the PIT twice can easily be delayed enough to warp the low 8bits around more than once if some bus master device fires (big AGP transfer or floppy DMA for example), where RDTSC is cpu-internal and wont block as long as the code is cached.


bewing:
if you want to see for yourself, make a win32 program that calls QueryPerformanceCounter() in an infinite loop and check for roll backs (a new value that is less than the old value) and run this program on many DIFFERENT machines (try especially HP and Dell systems, they use very cheap clone parts likely to have marginal bugs)

and run that on windows 2003 or older NTs and Windows 95,98,ME. that function uses the PIT counters and PIT interrupt.
I dont know if winXP or Vista was updated to use RDTSC or other less buggy counters, but 2003 and ME (and olders) do hit the PIT bugs on some machines.

if you are stuck using the PIT as a high precision time counter, to read it reliably you need to:

do{
disable_int()
old_tick_count = pit_interrupt_count;
old_count = latch_and_read_pit();
enable_int()
} while(old_tick_count != pit_interrupt_count);

do {

max_loops = 10;

do {
disable_int()
new_tick_count = pit_interrupt_count;
new_count = latch_and_read_pit();
enable_int()
} while(new_tick_count != pit_interrupt_count);

suspicious = (old_tick_count != new_tick_count)
|| (new_count < old_count);

old_count = new_count;
old_tick_count = new_tick_count;
} while(suspicious && max_loops--);

return (old_tick_count << 16) + old_count;

YES it is horrible! and it might even loop infinitely without max_loops.
but the PIT itself is an horrible piece of unwashed bellybutton crust from 1981.

unless you need to run your timing code on an early pentium / 486 or older machine you shouldnt use it.

a calibrated busy-delay-loop should be used for short delays for accessing bad hardware with interrupts disabled.

the RTC timer could be used for up to 8192 hz tick counters with interrupts enabled.
this gives a 0.122 ms granularity delay +/- 0.061ms precision as long as you dont disable interrupts (then you will start to miss ticks).

but otherwise without RDTSC you're pretty much screwed, sorry.
PCs are really that bad for realtime stuff, they were designed as word processor machines.

btw, another interresting time-related issue to keep in mind, on KDE/Linux: set your screen saver to lock the machine and adjust your clock to a hour later. as soon as click OK the screen saver launches and lock (provided its set to less than a hour).

in this case its just amusing/anoying but think of the problem this kind of programming glitch could causes on 24h production lines during daylight saving changes, say, get the bread out of the oven in 1h 45 minutes, becomes either 45minutes or 2h45 minutes.. whoops. :D

its like that other thread here about file timestamps and build systems flipping out.

making computer understand time reliably seem to be the hardest thing to do... :roll:

:)
Post Reply