09-30-2014 03:12 PM
In general when I press the Break button to interrupt a CPU intensive IML program, I find that it is extremely unresponsive. If I am patient it will run for many minutes before it releases control back to me, so instead I resort to killing SAS in the Windows Task Manager, but only provided I have remembered to save what I was doing!
I have fudged a way around this. In my main program loop, I am considering using syntax like:
do i = 1 to 1E10;
if mod(i, 1E5) = 0 then do;
< do stuff here >
In my tests, this does make IML much more responsive to pressing the break button. But you either have to put up with the flood of notes to the log window, or kill notes for the whole program. Is there a better way? A system option perhaps? A different way of structuring my IML program? I am using 9.4 in Windows 7.
09-30-2014 03:40 PM
That's an interesting problem (and solution). When your program is deep inside a compuational routine (say, an eigenvector computation), it can't check for an interrupt. So the more efficient your code is, the worse this problem will be.
I think you can use the EXECUTE statement to implement the flavor or your solution without experiencing the NOTES/Log problem. I don't think the statement that you execute is important, but try this:
if mod(i, 1E5) = 0 then do;
10-01-2014 03:29 AM
Thanks Rick, the call execute trick does work for me.
I suspect IML on my machine is checking for interrupts less frequently than you imagine. If I run :
do i = 1 to 2E8;
j = i;
then it takes a little less than 30 secs CPU to complete without interruption. However if I press the break button 2 seconds into the run, it appears to ignore it until the loop has completed, since the log always reports about the same CPU time after "user asked for termination".
10-01-2014 08:38 AM
Oh, I realize that IML doesn't check for interrupts very frequently. By design, IML is optimized to execute quickly. It compiles the entire DO loop and then executes it as a unit. That is why a DO loop in IML is not as expensive as in some other matrix-vector languages.
You might also try CALL EXECUTE(";"), which would have no side effects. [Untested idea.]
Another thought: You could write a macro that would replace the single loop with multiple loops. For example,
%SplitLoops(i=1 to 1E8, 10, <code>);
could resolve to 10 DO loops that each execute <code>. The first loop is i=1 to 1e7, the next is i=1e7+1 to 2e7, and so forth.
You might find it interesting that SAS/IML Studio, which has a client-server architecture, handles interrupts differently. Programs that are submitted through SAS/IML Studio check for interrupts more frequently, and therefore are more responsive to user interruptions. This suggests that you might want to use SAS/IML Studio to test and debug your IML program.
10-01-2014 09:26 AM
Thanks, I think have a much better understanding now. Is it the case that nested loops get compiled as a single unit and therefore can not be interrupted? So the loop slicing trick will only work on the outer most loop?
Now I know the issues, I think I am comfortable managing it myself with call execute. The empty command does work by the way, so if I use:
and then at various points later on:
it should make the purpose clear to others.