<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926405#M364557</link>
    <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/350894"&gt;@sjb1&lt;/a&gt;&amp;nbsp;I believe the difference in runtime you observe is solely due to the SAS datastep code your macro generates.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To easily see the macro generated code the SAS compiler will get:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;filename mprint temp;
options fullstimer mprint mfile;
%macro_vs_datastep();
data _null_;
  infile mprint;
  input;
  put _infile_;
run;
filename mprint clear;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With 5 loops (%let months_to_process = 5;)&amp;nbsp;the code the macro generates is as below:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data input_dta;
  length Date t 8;
  do i = 1 to 100;
    Date = intnx("MONTH", "01JAN1980"d, i, "E");
    do t = 1 to 10000;
      output;
    end;
  end;
run;
data data_step;
  set input_dta;
  if Date = intnx("MONTH", "01JAN1980"d, 1, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 2, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 3, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 4, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 5, "E") then output;
run;
data macro;
  set input_dta;
  if Date = 7364 then output;
  if Date = 7395 then output;
  if Date = 7425 then output;
  if Date = 7456 then output;
  if Date = 7486 then output;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The step "data_step" needs to execute the intnx() function once per loop while step "macro" only needs to do a simple comparison per loop. I believe that's the reason for the performance difference you observe.&lt;/P&gt;
&lt;P&gt;As you mentioned already it does look like the intnx() function needs to execute for every single iteration of the data step and doesn't already resolve to a SAS date value during compilation time.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I guess if you would generate below data step code then the intnx() function would also only execute once.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;if Date = %sysfunc(intnx(MONTH, "01JAN1980"d, 1, E)) then output;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;...and of course both code versions would profit from change for a real implementation.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Tue, 30 Apr 2024 03:48:41 GMT</pubDate>
    <dc:creator>Patrick</dc:creator>
    <dc:date>2024-04-30T03:48:41Z</dc:date>
    <item>
      <title>Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926389#M364547</link>
      <description>&lt;P&gt;I am wondering if there are any rules about how SAS handles constants and if having the macro language resolve macro variables before they reach the data-step can improve processing time.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Take the following toy example. (I know there are more efficient ways to achieve the same outcome in the code below, this is purely for illustrative purposes.)&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;%macro macro_vs_datastep();

	%let macro_date = 01JAN1980;
	%let quarters_to_process = 10;

	data data_step;
		set sashelp.gnp;
		%do h = 1 %to &amp;amp;quarters_to_process;
			if intnx("QUARTER", Date, 0, "E") = intnx("QUARTER", "&amp;amp;macro_date"d, &amp;amp;h, "E") then output;
		%end;
	run;

	data macro;
		set sashelp.gnp;

		%do h = 1 %to &amp;amp;quarters_to_process;
			if intnx("QUARTER", Date, 0, "E") = %sysfunc(intnx(QUARTER, "&amp;amp;macro_date"d, &amp;amp;h, E)) then output;
		%end;
	run;

%mend;

%macro_vs_datastep();&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;My intuition is that that resolving the macro variables 'macro_date' and 'h' inside of %sysfunc() should reduce I/O time as in the 2nd data-step, as SAS only has to resolve intnx() with each loop of 'h'. Compare that to the first data-step where intnx() must be resolved with each loop of 'h' along with each record in the dataset.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Are there any rules-of-thumb around best practices in these sorts of situations?&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 29 Apr 2024 20:21:44 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926389#M364547</guid>
      <dc:creator>sjb1</dc:creator>
      <dc:date>2024-04-29T20:21:44Z</dc:date>
    </item>
    <item>
      <title>Re: Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926391#M364549</link>
      <description>&lt;P&gt;I don't think there is a good general rule.&amp;nbsp; Personally I would go with option 2:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%sysfunc(intnx(QUARTER, "&amp;amp;macro_date"d, &amp;amp;h, E))&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;I would do that for logical coherence, rather than run-time efficiency.&amp;nbsp; The expression doesn't have&amp;nbsp; any DATA step variables, so it makes sense to me to use the macro language.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The first option:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt; intnx("QUARTER", "&amp;amp;macro_date"d, &amp;amp;h, "E")&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;looks weird to me, because you're using the DATA step INTNX function on constants.&amp;nbsp; Which isn't a bad thing or a thing I've never done, but feels odd.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Efficiency-wise, I think it's going to come down to how many macro loops you have, and how many data step loops you have.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In option 1 you have two DATA step invocations of INTNX.&amp;nbsp; I'm assuming the DATA step compiler is not smart enough to recognize that the second one is a constant (but I could be wrong, which would destroy my argument here).&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In option 2 you have one DATA step invocation of INTNX, and one macro language invocation of INTNX.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So if the number of records in your data is N, I think the difference in time between the two is&amp;nbsp; N*10*(speed of DATA step to execute INTNX one time) - 10*speed of %sysfunc to execute INTNX once.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The macro language is generally slow, for for small N it could lose, but I guess for big N the macro language might win.&amp;nbsp; Essentially in the macro language the expression:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=""&gt;%sysfunc(intnx(QUARTER, "&amp;amp;macro_date"d, &amp;amp;h, E))&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Executes in constant time, independent of N.&amp;nbsp; &amp;nbsp;I think that is O(1) in big O notation.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;You should try testing it out.&amp;nbsp; Fun question.&lt;/P&gt;</description>
      <pubDate>Mon, 29 Apr 2024 20:46:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926391#M364549</guid>
      <dc:creator>Quentin</dc:creator>
      <dc:date>2024-04-29T20:46:19Z</dc:date>
    </item>
    <item>
      <title>Re: Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926395#M364552</link>
      <description>&lt;P&gt;You were right! It seems that the Data-Step Compiler does not recognize:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;intnx("QUARTER", "&amp;amp;macro_date", &amp;amp;h, "E")&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;as a constant.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;%macro macro_vs_datastep();

	options fullstimer;

	
	data input_dta;
		length Date t 8;

		do i = 1 to 100;
			Date = intnx("MONTH", "01JAN1980"d, i, "E");
			do t = 1 to 10000;
				output;
			end;
		end;
	run;	

	%let macro_date = 01JAN1980;
	%let months_to_process = 100;

	data data_step;
		set input_dta;
		%do h = 1 %to &amp;amp;months_to_process;
			if Date = intnx("MONTH", "&amp;amp;macro_date"d, &amp;amp;h, "E") then output;
		%end;
	run;

	data macro;
		set input_dta;
		%do h = 1 %to &amp;amp;months_to_process;
			if Date = %sysfunc(intnx(MONTH, "&amp;amp;macro_date"d, &amp;amp;h, E)) then output;
		%end;
	run;

%mend;

%macro_vs_datastep();&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Here's the log:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;BLOCKQUOTE&gt;&lt;P&gt;NOTE: There were 1000000 observations read from the data set WORK.INPUT_DTA.&lt;BR /&gt;NOTE: The data set WORK.DATA_STEP has 1000000 observations and 3 variables.&lt;BR /&gt;NOTE: DATA statement used (Total process time):&lt;BR /&gt;real time 18.73 seconds&lt;BR /&gt;user cpu time 18.70 seconds&lt;BR /&gt;system cpu time 0.03 seconds&lt;BR /&gt;memory 1497.43k&lt;BR /&gt;OS Memory 21272.00k&lt;BR /&gt;Timestamp 04/29/2024 05:05:39 PM&lt;BR /&gt;Step Count 59 Switch Count 9&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;NOTE: There were 1000000 observations read from the data set WORK.INPUT_DTA.&lt;BR /&gt;NOTE: The data set WORK.MACRO has 1000000 observations and 3 variables.&lt;BR /&gt;NOTE: DATA statement used (Total process time):&lt;BR /&gt;real time 0.23 seconds&lt;BR /&gt;user cpu time 0.21 seconds&lt;BR /&gt;system cpu time 0.01 seconds&lt;BR /&gt;memory 1195.31k&lt;BR /&gt;OS Memory 21088.00k&lt;BR /&gt;Timestamp 04/29/2024 05:05:40 PM&lt;BR /&gt;Step Count 60 Switch Count 5&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;This could be specific to intnx(), other functions might be optimized to recognize this behavior, but good to know!&lt;/P&gt;</description>
      <pubDate>Mon, 29 Apr 2024 21:12:52 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926395#M364552</guid>
      <dc:creator>sjb1</dc:creator>
      <dc:date>2024-04-29T21:12:52Z</dc:date>
    </item>
    <item>
      <title>Re: Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926396#M364553</link>
      <description>&lt;P&gt;Seems like you don't need to ask 100 questions but just one with end date of 100 months from start.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;48         %let macro_date = 01JAN1980;
49         %let months_to_process = 100;
50         
51         %let x = %sysfunc(intnx(MONTH,"&amp;amp;macro_date"d,100,E),date9);
52         %put &amp;amp;=x;
X=31MAY1988&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Mon, 29 Apr 2024 22:56:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926396#M364553</guid>
      <dc:creator>data_null__</dc:creator>
      <dc:date>2024-04-29T22:56:37Z</dc:date>
    </item>
    <item>
      <title>Re: Processing Time on Macro Variables Resolved within a Macro Function vs a Data-Step Function</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926405#M364557</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/350894"&gt;@sjb1&lt;/a&gt;&amp;nbsp;I believe the difference in runtime you observe is solely due to the SAS datastep code your macro generates.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;To easily see the macro generated code the SAS compiler will get:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;filename mprint temp;
options fullstimer mprint mfile;
%macro_vs_datastep();
data _null_;
  infile mprint;
  input;
  put _infile_;
run;
filename mprint clear;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;With 5 loops (%let months_to_process = 5;)&amp;nbsp;the code the macro generates is as below:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data input_dta;
  length Date t 8;
  do i = 1 to 100;
    Date = intnx("MONTH", "01JAN1980"d, i, "E");
    do t = 1 to 10000;
      output;
    end;
  end;
run;
data data_step;
  set input_dta;
  if Date = intnx("MONTH", "01JAN1980"d, 1, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 2, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 3, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 4, "E") then output;
  if Date = intnx("MONTH", "01JAN1980"d, 5, "E") then output;
run;
data macro;
  set input_dta;
  if Date = 7364 then output;
  if Date = 7395 then output;
  if Date = 7425 then output;
  if Date = 7456 then output;
  if Date = 7486 then output;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The step "data_step" needs to execute the intnx() function once per loop while step "macro" only needs to do a simple comparison per loop. I believe that's the reason for the performance difference you observe.&lt;/P&gt;
&lt;P&gt;As you mentioned already it does look like the intnx() function needs to execute for every single iteration of the data step and doesn't already resolve to a SAS date value during compilation time.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I guess if you would generate below data step code then the intnx() function would also only execute once.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;if Date = %sysfunc(intnx(MONTH, "01JAN1980"d, 1, E)) then output;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;...and of course both code versions would profit from change for a real implementation.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 30 Apr 2024 03:48:41 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Processing-Time-on-Macro-Variables-Resolved-within-a-Macro/m-p/926405#M364557</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2024-04-30T03:48:41Z</dc:date>
    </item>
  </channel>
</rss>

