AnsweredAssumed Answered

vrf Sampling Reduced

Question asked by VRFuser on Jul 23, 2004
Mike & Amrik

> using the windows sleep function -
> this will pause just the thread you want.

Unfortunately I think that's incorrect. VEE uses one Win32 thread to execute
all VEE code, and implements VEE threads with that one thread (in Windows
parlance, it's the user interface thread). So if that one sleeps then all
VEE threads sleep.

The problem isn't that bad though. Amrik, I didn't read your program, but I
think you could probably use an OnCycle object to implement your checking
frequency. Or better yet, integrate it into data acquision. Something like:

Do
  if abort then break loop
  Acquire
  if < lower_limit or > upper_limit then
    throw away
  else
    store
  end if
Loop

> (I can't remember the syntax off the top of my head).

Just in case Sleep does come in handy, it's in kernel32:
void __stdcall Sleep(long dwMs);

A value of 0 causes the calling thread to relinquish it's remaining time
slice to any other thread of equal priority that's ready to run. Any other
value theoretically causes the calling thread to be suspended for the
specified number of milliseconds. I say theoretically because the timing is
not real exact. Whatever you do, don't call Sleep with a value of -1 (a.k.a.
0xffffffff, a.k.a. INFINITE). It really does cause the calling thread to
sleep forever

There is another kernel32 function called GetTickCount that can help
implement time delays. It's prototype is:

long __stdcall GetTickCount(void);

It returns the number of milliseconds since the system was started. It's
usually accurate to about 10ms. There is yet another kernel32 function to
find out what exactly the system timer interrupt period is. It is:

int __stdcall GetSystemTimeAdjustment(long *pdwTimeAdj, long *pdwTimeInc,
int *pbDisable);

If the function fails it returns 0. Otherwise, it returns something else.
The dwTimeAdj value is set to the number of 100 nanosecond increments added
to the time of day clock at each interrupt. The dwTimeInc value is the
interesting beast. This is the number of 100 nanosecond intervals between
clock interrupts. This is the value that tells you how accurate GetTickCount
is. The bDisable value is 0 if time adjustments are enabled, and some other
value if time adjustments are enabled. Fascinating, isn't it

There are also other timers. Multimedia timers can be accurate to 1ms, but
they are very difficult to use with VEE. There is a high performance counter
that can be used as a timer that's simple to use however. It's intervals are
frighteningly short on today's hardware. When you use this puppy you have to
start worrying about how long it takes to call the function and return from
it to accurately measure an interval. The function that tells you the
frequency of the high performance counter (also in kernel32) is:

int __stdcall QueryPerformanceFrequency(long *pliFreq);

The parameter is a pointer to a "large integer", a struct containing a DWORD
and a LONG. VEE can use an Int32 array of size 2. ary[0] is the low 32 bits
of the frequency and must be interpreted as an unsigned value. ary[1] is the
hi 32 bits of the frequency value. If bit 31 of ary[0] is set then you have
to do some mathematical aerobics to get the frequency. Specifically, reset
bit 31, set a Real64 value to the resulting Int32 value and add 2 ^ 31 to
the Real64 value. Don't try to set bit 31 of the Real64 value - it won't
work right. Add ary[1] * 2 ^ 32 to the real to get the actual frequency.
When you see the resulting number you'll see what I mean about
"frighteningly short intervals".

OTOH, if the hardware does not support a high res timer, the array
components can be 0, so if the function returns TRUE (the return value is
something other than 0) and you're array contains [0, 0] then the hardware
just isn't there. That's pretty unlikely though. Windows will try to use
whatever hardware is installed, and typically if you have audio capability
then you have what is necessary to implement this counter.

That's only half the story though. That gives you the frequency of the
counter itself, and that's accessed by calling:

int __stdcall QueryPerformanceCounter(long *pliCount);

The parameter is again a "large integer" - or more simply an Int32 array of
size 2. Interpret the numbers returned in the array in the same way as above
and you have the current count of the high performance counter at the time
of the call. Call it again with a different array and interpret it's array
values, and the difference between the two tells you how many counts elapsed
between the calls. The time base for these counts is of course specified by
QPF.

I did a quick n' dirty demo of these functions once upon a time. Search for
QueryPerformanceFrequency in the body text of messages in the archive. This
demo is QAD because it doesn't take into account bit 31 (I think, can't
remember now), nor does it detect rollover in the count. Still if you need
to use these functions (only for the *really* snobby perfectionist - VEE's
now() works just fine for me) then it can at least show you how to call
them.

I suppose it could come in handy now and again, but like I said the
frequency of the counter is so spectacularly high that one single machine
instruction is going to show several counts by itself (the interval was
usually much shorter than the "T state" interval of the CPU as of a few
years ago - that may have changed by now what with 2.8GHz processors &
whatnot). Consider that VEE probably executes at least a couple dozen
instructions to set up and make a call to a dll and suddenly your count
interval could show thousands of counts that measure the time it takes VEE
to make the call.

One thing you can do about that is to make two successive calls immediately
and find the count difference. This difference then becomes an offset that's
subtracted from all count differences. Then the extra time only comes from
VEE code between the calls and VEE object transitions. See? This counter is
really just a pain in the ****! If one needs to split Red C Hairs *that*
fine then it's usually a much better idea to take software out of the
equation entirely.
-SHAWN-


---
You are currently subscribed to vrf as: rsb@soco.agilent.com
To subscribe send a blank email to "join-vrf@it.lists.it.agilent.com".
To unsubscribe send a blank email to "leave-vrf@it.lists.it.agilent.com".
To send messages to this mailing list,  email "vrf@agilent.com". 
If you need help with the mailing list send a message to "owner-vrf@it.lists.it.agilent.com".

Outcomes