in reply to Any ideas for using perl as a simple pulse generator?

The problem with using threads for this is that there will be a propagation delay between the controlling thread deciding it is time to issue a pulse and the writing thread receiving the command to write. And that delay will be non-determanistic.

Once the controller issues the write command--however it does that--it will then have to relinquish the rest of its time-slice. At that point you are in the hands of the system scheduler as to when the write thread will next be run. It might choose it immediately, but it is very unlikely on a system that has many other threads running--device drivers; system processes; and other application programs. There would simply be no way to know how long it would be before the other thread got the command.

You might set the write thread to a real-time priority setting, which would mean it would get a look in before most other threads. But some device drivers and system processes will also run at real-time priority and you would be competing with them. I don't think that threads are of much advantage here--not as you've described using them anyway.

For example, on my system, even when I am watching a video and playing an mp3, the following code hits the 500 millisecond target to within 1 or 2 milliseconds every time:

#! perl -slw use strict; use Time::HiRes qw[ time sleep ]; my $next = time() + 0.5; while( 1 ) { sleep .001 while time() < $next; printf "%10.3f\n", time(); $next += 0.5; } __END__ c:\test>849367 1279055103.020 1279055103.520 1279055104.020 1279055104.519 1279055105.020 1279055105.520 1279055106.019 1279055106.520 1279055107.020 1279055107.519 1279055108.020 1279055108.519 1279055109.020 1279055109.519 1279055110.020 1279055110.519 1279055111.020

I do have multiple cpus though. YMMV on a single cpu system.

In fact, with a small tweak, it hits it to the millisecond every time at the expense of a fraction more cpu (still < 1% though) even with two video streams playing:

#! perl -slw use strict; use Time::HiRes qw[ time sleep ]; my $next = time() + 0.5; while( 1 ) { sleep .001 while time() < ( $next - 0.01 ); 1 while time() < $next; printf "%10.4f\n", time(); $next += 0.5; } __END__ c:\test>849367 1279056441.7570 1279056442.2570 1279056442.7570 1279056443.2570 1279056443.7570 1279056444.2570

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP an inspiration; A true Folk's Guy

Replies are listed 'Best First'.
Re^2: Any ideas for using perl as a simple pulse generator?
by bfreemer (Novice) on Jul 13, 2010 at 22:02 UTC

    Excellent description. Just out of curiosity, I tried your second example on my idle system (linux, newer AMD quad). It used <2% cpu and showed 2-3 *microsecond* precision:

    1279058169.099145 1279058169.599145 1279058170.099145 1279058170.599144 1279058171.099144 1279058171.599144 1279058172.099146 1279058172.599144 1279058173.099145 1279058173.599144 1279058174.099145 1279058174.599146 1279058175.099144 1279058175.599145 1279058176.099146 1279058176.599145 1279058177.099145 1279058177.599144

    Then I started two fsck processes and 4 prime number searching threads which overtax all CPUs and FPUs. I got this:

    1279057824.4011 1279057824.9012 1279057825.4012 1279057825.9011 1279057826.4012 1279057826.9012 1279057827.4012 1279057827.9012 1279057828.4011 1279057828.9011 1279057829.4012 1279057829.9011 1279057830.4012 1279057830.9012 1279057831.4030 1279057831.9012

    Which still looks like 1-2 millisecond precision. This is of course much better than I need. I don't know how valid those tests are, though, so I'll have to read up on the linux kernel schedulers.

    Any tips for code to do the actual writing? I'll probably use the autoflush=1 example posted in the thread.

      Any tips for code to do the actual writing?

      I don't really understand how writing to a file creates pulses to a pump.

      Is this a real file that you're writing to? Or some kind of memory mapped IO?

      if the latter, I'd probably drop into Inline::C for this. On windows, I'd write the whole timing and writing loop in C and run it in a system thread. But I don't know enough about Linux to know if this makes sense there.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
      Any tips for code to do the actual writing?
      syswrite, and if you aren't checking whether your write actually succeeded, open the file in O_ASYNC mode (use sysopen for that).

      But since you don't mind a variation of a couple of hundred msecs (on a delay of five hundred msecs) running it with autoflush and without O_ASYNC should be ok. Just as an unconditional sleep - writing a byte shouldn't take hundreds of msecs anyway (I presume the file you're writing to isn't on some NFS drive while the OS doesn't have any memory for file buffers). And as you said, the write takes a few tens of msecs.

Re^2: Any ideas for using perl as a simple pulse generator?
by bfreemer (Novice) on Jul 13, 2010 at 22:16 UTC

    And another repeat trial on the overtaxed system, but this time executing with higher priority (nice = -15):

    1279058992.204795 1279058992.704795 1279058993.204795 1279058993.704794 1279058994.204794 1279058994.704794 1279058995.204794 1279058995.704794 1279058996.204794 1279058996.704794 1279058997.204794 1279058997.704795 1279058998.204795 1279058998.704795 1279058999.204795 1279058999.704795

    Which shows 2 microsecond accuracy again. Pretty damn impressive code indeed! Of course, I'd need some electronics to verify the accuracy (vs. precision) of the above, but it verifies software timing might be feasible even in the 100kHz realm, where I'm dealing with 2Hz. Thoughts?