When you have a long-running SAS/IML program, it is sometimes useful to be able to monitor the progress of the program. For example, suppose you need to computing statistics for 1,000 different data sets and each computation takes between 5 and 30 seconds. You might want to output a message after every 100th computation so that you know at a glance whether the program is close to finishing. (You might also want to check out some efficiency tips and ways to vectorize your program.)
Now some of you might be thinking, "What's the problem? Just put a PRINT statement inside the loop!" Right idea, but it doesn't work like you might expect. For efficiency, SAS/IML loops are compiled and executed in a very efficient manner. One of the consequences of this efficiency is that ODS output is not flushed until the entire DO loop has completed! Run the following program (which takes 10 seconds) and notice that you get NO output until the loop completes, at which point you will see all 10 messages displayed at once:
proc iml; do i = 1 to 1000; if mod(i,100)=0 then do; print "Iteration= " i; end; call sleep(1, 0.01); /* delay for 1/100th second */ end; print "Execution finished";
So how can you force SAS/IML to display information while the loop is executing? I know two ways. In the IMLPlus language (available in the SAS/IML Studio application), you can use the PRINTNOW statement to flush the ODS output. In PROC IML, you can use the SUBMIT and ENDSUBMIT statements to write messages to the SAS Log.
The IMLPlus solution: The PRINTNOW statement
In the SAS/IML Studio environment, the IMLPlus language supports the PRINTNOW statement. The PRINTNOW statement tells the IMLPlus program to retrieve and display any pending output from the SAS Workspace server. In the IMLPlus language, the following statement prints the iteration history while the DO loop is executing:
do i = 1 to 1000; if mod(i,100)=0 then do; print "Iteration= " i; printnow; /* IMLPlus statement: works only in SAS/IML Studio */ end; call sleep(1, 0.01); /* delay for 1/100th second */ end;
The PROC IML solution: The SUBMIT/ENDSUBMIT statements
If you are running PROC IML as part of a larger SAS program, you can use the SUBMIT/ENDSUBMIT statements to write messages to the SAS Log. Recall that you can pass values from SAS/IML matrices into SAS statements. If you include the name of a SAS/IML variable on the SUBMIT statement, the contents of that variable are substituted into the SAS code before the SUBMIT block is sent to SAS. In the following example, the value of the counter i is sent into a SUBMIT block, and the %PUT macro statement is used to print the iteration value to the SAS Log:
proc iml; do i = 1 to 1000; if mod(i,100)=0 then do; submit i; %put Iteration= &i; endsubmit; end; call sleep(1, 0.01); /* delay for 1/100th second */ end; print "Execution finished";
The previous program displays the iteration count in the SAS Log while the program is running.
Write NOTE: into the log
Some SAS programmers know that if you use the %PUT statement to write a message that begins with 'NOTE:', then SAS will color-code that message in the log so that it looks like a system-issued note. However, to get that feature to work in the SUBMIT block, you need to turn on the NOTES option, which is off by default. That is, use OPTIONS NOTES at the top of the SUBMIT block, as follows:
/* write NOTE: <message> */ submit i; options notes; /* turn on notes */ %put NOTE: Iteration = &i; /* displays NOTE: in color */ endsubmit;
Do you have long-running programs in SAS? Have you developed a clever way to monitor their progress while they run? Leave a comment about your technique.