BookmarkSubscribeRSS Feed

Use contexts to give users a choice of CPU and memory size: Part 2 - Compute contexts

Started 7 hours ago by
Modified 7 hours ago by
Views 70

In Part 1 of this two part article, I described what CPU and memory requests and limits are, and walked through how to create different-sized launcher contexts.

 

In this Part 2, I'll show you how to create a corresponding set of new compute contexts which you can use to test different values with an example SAS program, to illustrate the process you would follow to find out which values suit a particular task best. I'll also touch on how you would change the default values for CPU and memory requests and limits, which are used wherever the launcher context does not override the defaults.

 

To properly explain different-sized launcher contexts, I've structured this two-part article in five sections:

 

In part 1 - launcher contexts:

 

  1. What are CPU and memory requests and limits?
  2. How to configure launcher contexts with non-default values of CPU and memory request and limits

 

In this part 2 - compute contexts and changing global defaults:

 

  1. Create a new compute, connect or batch context to use the new launcher context
  2. A demonstration of the impact, using some example SAS code
  3. How to change the global default CPU and memory request and limit

 

 

Part 2, Section 1: Create a new compute, connect or batch context to use the new launcher context

 

A new 'large' compute context should reference the new large launcher context. It also needs to have a SAS options statement adjusting the value of the CPUCOUNT SAS system option from the default 4 to 8.

 

As an aside, if you changed the memory limit in the launcher context which your new compute context will use, you must also set the value of the MEMSIZE SAS system option to match it.

 

    • If MEMSIZE is larger than the memory limit and your pod runs some SAS code on some data so that it actually uses (allocates) more memory than its stated pod memory limit, it is likely to be OOM killed.
    • If MEMSIZE is smaller than the memory limit, your pod will confine itself to using only up to the MEMSIZE amount of memory as set by that SAS system option value, even though Kubernetes and cgroupsv2 in the underlying OS would have allowed it to use more memory without being OOM killed.

 

For my examples in this article I have chosen not to change the launcher memory limit, so I don't need to specify a matching value for the MEMSIZE SAS system option - the default of 2 Gi is still correct. But don't forget about setting a correct value for MEMSIZE in a compute, connect or batch context if you do change the memory limit in the launcher context it uses to something different.

 

We can create our new compute context in SAS Environment Manager, on the Contexts page, in the Compute context view. Right-click the SAS Studio compute context and choose Copy from the popup context menu. Give the new compute context a name, a description, and most importantly change the launcher context. Here's an example for a large compute context, using the large launcher context we created in Part 1 of this article:

 

01_DS_Large_compute_context-1.png

 

On the Advanced tab, adjust the CPUCOUNT for this compute context by putting -CPUCOUNT 8 in the SAS options textbox.  (Again, if you are adjusting memory, you should provide a matching value for MEMSIZE here in a similar way, e.g. something like -MEMSIZE 4Gi specifying the appropriate amount of memory SAS programs can use in this context). For later convenience, to provide a way to confirm which context is in use in the SAS log output, I also added a line to the autoexec content textbox to define a macro variable context_name. This is just handy for confirmation later, it is absolutely not required:

 

02_DS_Large_compute_context_advanced_tab.png

Defining a large compute context in SAS Environment Manager - Advanced tab 

 

 

Alternatively, you can create the new compute context from the command line. Unlike the sas-viya CLI command for creating a launcher context, we have to create a JSON file defining the compute context resource, then run the sas-viya compute context create command and pass that JSON file in as a parameter.

 

Start by creating the JSON file - in fact, let's create three JSON files, one each for the three new compute contexts. In the example below, I am signed in to a bash shell session on a server where the sas-viya CLI is installed, as a user called cloud-user, so I can create the JSON files in the cloud-user home directory. Edit the code below to suit your particular environment and requirements:

 

# Create a JSON file defining an extra small compute context
# It will create compute sessions with less CPU and memory available because it references the extra small launcher context.  It also sets a smaller value for CPUCOUNT.
tee /home/cloud-user/SAS_Studio_compute_context_extra_small.json > /dev/null << EOF
{
    "name": "SAS Studio compute context - extra small",
    "description": "Extra small compute context for SAS Studio",
    "environment": {
        "autoExecLines": [
            "%let context_name=SAS Studio compute context - extra small;"
        ],
        "options": [
            "-CPUCOUNT 1"
        ]
    },
    "launchContext": {
        "contextName": "SAS Studio launcher context - extra small"
    },
    "launchType": "service"
}
EOF

# Create a JSON file defining a small compute context
# It will create compute sessions with less CPU and memory available because it references the small launcher context.  It also sets a smaller value for CPUCOUNT.
tee /home/cloud-user/SAS_Studio_compute_context_small.json > /dev/null << EOF
{
    "name": "SAS Studio compute context - small",
    "description": "Small compute context for SAS Studio",
    "environment": {
        "autoExecLines": [
            "%let context_name=SAS Studio compute context - small;"
        ],
        "options": [
            "-CPUCOUNT 2"
        ]
    },
    "launchContext": {
        "contextName": "SAS Studio launcher context - small"
    },
    "launchType": "service"
}
EOF

# Create a JSON file defining a large compute context
# It will create compute sessions with more CPU and memory available because it references the large launcher context. It also sets a larger value for CPUCOUNT
tee /home/cloud-user/SAS_Studio_compute_context_large.json > /dev/null << EOF
{
    "name": "SAS Studio compute context - large",
    "description": "Large compute context for SAS Studio",
    "environment": {
        "autoExecLines": [
            "%let context_name=SAS Studio compute context - large;"
        ],
        "options": [
            "-CPUCOUNT 8"
        ]
    },
    "launchContext": {
        "contextName": "SAS Studio launcher context - large"
    },
    "launchType": "service"
}
EOF

 

Again, the environment.autoExecLines element of the file is not required in this case. You could omit it, but I included it to provide another way for us to confirm later that we are using the compute context we think we are using. The important things are:

 

  • The compute context name (so we can identify it when we select it in SAS Studio etc.)
  • The options statement setting CPUCOUNT to a value matching the launcher context - also set MEMSIZE on a separate line, if you need to
  • The launchContext.contextName value must match the name of the corresponding launcher context exactly

 

Then you can pass those files in as parameters to three separate sas-viya compute contexts create commands:

 

# Create the new compute contexts from those JSON files
sas-viya compute contexts create -r -d @/home/cloud-user/SAS_Studio_compute_context_extra_small.json
sas-viya compute contexts create -r -d @/home/cloud-user/SAS_Studio_compute_context_small.json

# If you already created the large compute context in SAS Environment Manager, this will produce an error
sas-viya compute contexts create -r -d @/home/cloud-user/SAS_Studio_compute_context_large.json

 

If you accidentally run one of these twice, or try to create the SAS Studio compute context large when you already created it interactively in SAS Environment Manager, you may see an error messages saying something like "Failed to create a compute context. Reason: A context with the name "SAS Studio compute context - large" already exists."

 

If everything works as intended you should be able to refresh the view of compute contexts in the Compute contexts view on the Contexts page in SAS Environment Manager.  

 

03_DS_SAS-Environment-Manager-Contexts-page-showing-new-compute-contexts-1024x522.png

 SAS Environment Manager Contexts page showing new compute contexts 

 

 

That's basically it. The examples above are all focused on compute contexts that use the new different-sized launcher contexts with varying amounts of CPU, but you can do similar with connect and batch contexts too. And you can modify the memory limits for the launcher and compute (and connect and batch) contexts in a similar way - I chose not to for simplicity and because when performance testing comparing different contexts, I prefer to only change one variable at a time, rather than two, to better understand the effect of the change.

 

If you want to limit compute contexts to be only useable by a specific groups of users (or individuals), you can absolutely do that too. There's a basic way, and a much neater, but more difficult way.

 

You can limit compute contexts to be only useable by a specific groups of users in a basic way, by using the Identity type/authorized groups section of the Compute Context definition, like this for example:

 

04_DS_Edit-compute-context-limit-to-custom-group.png

 

You can do this in the JSON which creates a compute context too, with an authorizedGroups element like this (here granting access to only members of a custom group with name="Power Users", groupID=power_users):

 

"authorizedGroups": [
		"power_users"
]

 

In the complete JSON for our "SAS Studio compute context - large" it looks like this:

 

{
	"name": "SAS Studio compute context - large",
	"description": "Large compute context for SAS Studio",
	"environment": {
		"autoExecLines": [
			"%let context_name=SAS Studio compute context - large;"
		],
		"options": [
			"-CPUCOUNT 8"
		]
	},
	"launchContext": {
		"contextName": "SAS Studio launcher context - large"
	},
	"launchType": "service",
	"authorizedGroups": [
		"power_users"
	]
}

 

The downside of limiting a compute context as shown above is that, in the current release of SAS Viya at the time of writing (SAS Viya LTS 2025.09 or SAS Viya Stable 2025.11), everyone will see the compute context from the contexts dropdown list in e.g. SAS Studio, whether they are allowed to use it or not. Users who are not allowed to use it get an error message if they select it. I am not aware of plans for this to change.

 

However, with a little more effort, you can limit the visibility of compute contexts so that they are only visible to one or more specific groups of users, or individual users. This results in a better end-user experience for users who are not allowed to use the context - they don't have their list of contexts cluttered up with contexts they can't use, and they don't have the opportunity to select contexts they can't use which results in a slightly frustrating error message. I described how to set it up in these two articles: Create group-specific and user-specific compute contexts – Part 1 – manual method and Create group-specific and user-specific compute contexts – Part 2 – scripted method.  

 

 

Part 2, Section 2: A demonstration of the impact different-sized launcher & compute contexts can have on SAS code

 

Let's see if it works. Honestly the code here isn't terribly important to the point, beyond that it demonstrates how the performance of a SAS statement that changes when the CPU or memory changes.

 

 

Example SAS Code: Create the gel.primes test dataset

 

For my example, I chose to create some test data in a 'gel' library using the code below, to give our proc means test something large to work with later. Open SAS Studio, paste the code below into a new SAS program window, edit the 'gel' library name throughout and path on line 1 to something that will work in your environment, and run this in the normal SAS Studio compute context (though it should run in any of the SAS Studio compute contexts).

 

libname gel "/gelcontent";

proc iml;
    start sieve(n);
        a = J(n,1);
        a[1] = 0;
        do i = 1 to n;
            if a[i] then do;
                if i*i>n then return(a);
                a[i*(i:int(n/i))] = 0;
            end;
        end;
    finish;

    a = loc(sieve(100000000))`;
    create work.primes from a;
    append from a;
    close work.primes;
quit;

/* Create a primes dataset in the gel library,
   containing two copies of the work.primes dataset, with some
   added columns - the prime number expressed in words, and
   a random number. The idea is simply to create some fairly large
   data which we can pass to other procedures later. */
data gel.primes;
  set work.primes
      work.primes;
  number_in_words=put(col1,words100.);
  random_number=ranuni(0);
run;

 

The resulting primes dataset looks like this:  

 

05_DS_Primes_dataset_sample-1024x522.png

 The first few rows of the gel.primes dataset 

 

The gel.primes dataset is about 1GB in size, which you can see using the following code, if you want to:

 

* See how big the dataset is.;
%let libraryname=gel;
%let datasetname=primes;
PROC SQL ;
TITLE ‘Filesize for &libraryname..&datasetname. Data Set’ ;
SELECT libname,
        memname,
        memtype,
        FILESIZE FORMAT=SIZEKMG.,
        FILESIZE FORMAT=SIZEK.
    FROM DICTIONARY.TABLES
    WHERE libname = upper("&libraryname")
        AND memname CONTAINS upper("&datasetname")
        AND memtype = "DATA" ;
QUIT;

 

Result:

 

06_DS_Primes_dataset_stats.png

 

 

Example SAS Code: Run our PROC MEANS with the gel.primes test dataset in different-sized compute/launcher contexts

 

Let's run the same test SAS program below in each of our four different-sized compute contexts:

 

  • SAS Studio compute context - extra small' with cpu.limit=1 and CPUCOUNT=1
  • SAS Studio compute context - small' with cpu.limit=2 and CPUCOUNT=2
  • the standard out-of-the-box 'SAS Studio compute context', which has cpu.limit=2 (yes, 2) and CPUCOUNT=4
  • SAS Studio compute context - large' with cpu.limit=8 and CPUCOUNT=8

 

We will run the following test SAS program in each context, and record the proc means CPU time and real time from the log output:

 

proc options option=(cpucount);
run;

%put &context_name;

libname gel "/gelcontent";

* Load primes dataset into memory;
sasfile gel.primes load;

* proc means is able to work as a multi-theaded SAS procedure;
proc means data=gel.primes fw=6 n min max median nonobs;
  var random_number;
run;

 

Switching between compute contexts is easy - you can just select a context from the dropdown list top right:  

 

07_DS_SAS_Studio_showing_compute_contexts-1024x522.png

SAS Studio showing the existing SAS Studio compute context, and the

three new compute contexts in the context dropdown list 

 

 

Here is an example of the log output, from a run in a compute session under the 'SAS Studio compute context - extra small':

 

1    /* region: Generated preamble */
79   
80   proc options option=(cpucount);
81   run;
    SAS (r) Proprietary Software Release V.04.00  TS1M0
 CPUCOUNT=1        Specifies the number of processors that thread-enabled applications should assume are available for concurrent 
                   processing.
NOTE: PROCEDURE OPTIONS used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds
      
82   
83   %put &context_name;
SAS Studio compute context - extra small
84   
85   libname gel "/gelcontent";
NOTE: Libref GEL was successfully assigned as follows: 
      Engine:        V9 
      Physical Name: /gelcontent
86   
87   * Load primes dataset into memory;
88   sasfile gel.primes load;
NOTE: The file GEL.PRIMES.DATA has been loaded into memory by the SASFILE statement.
89   
90   * proc means is able to work as a multi-theaded SAS procedure;
91   proc means data=gel.primes fw=6 n min max median nonobs;
92     var random_number;
93   run;
NOTE: There were 11522910 observations read from the data set GEL.PRIMES.
NOTE: The PROCEDURE MEANS printed page 1.
NOTE: PROCEDURE MEANS used (Total process time):
      real time           19.43 seconds
      cpu time            19.44 seconds
      
94   
95   
96   
97   /* region: Generated postamble */

 

In the example above, the proc means CPU time and real time are basically the same, which is consistent with the idea that the proc means is doing its work in a single thread.  

 

 

Example Results

 

Here are the consolidated results from four test runs, one in each compute context:

 

Compute context name CPUCOUNT real time (seconds) cpu time (seconds)
SAS Studio compute context - extra small 1 19.43 19.44
SAS Studio launcher context - small 2 8.32 15.68
SAS Studio launcher context 4 6.04 19.62
SAS Studio launcher context - large 8 5.23 29.72

 

In the example results above, we see that as the CPUCOUNT increases, the real time is reduced, which is what we might expect. But it appears to be a diminishing return. The total CPU time even tends upwards to complete the same task with more threads.

 

If you run the test more times, you may see some variability in the PROC MEANS timing results for each compute context - plus or minus a second or a few seconds perhaps. We can get a more representative impression of the trend with multiple runs for each size compute context:

 

08_DS_PROC_MEANS_vs_threads_results-1024x729.png

 

We could absolutely analyze these results in better way than this, but we are at risk of forgetting the point, which is that we can switch between compute contexts to run the same code with the same data under different-sized compute sessions, and generate performance test results which we can interpret to determine which of those contexts is the best, and thus which is the best size of the launched compute pod. The actual example used above is largely nonsense, but it illustrates that point well enough.  

 

 

Example Conclusions

 

For this article, the main conclusion is that you can quite easily configure launcher contexts with non-default Kubernetes CPU and memory requests and limits, and make compute contexts to pair with them which are easy to select. Performance testing to optimize resources for your code is no more difficult than this.

 

The specific results above, on our somewhat nonsense test data are not really important; the point is that we can produce results like this and use them to inform sizing decisions that are easy to implement.

 

Whether it is worth your time to do this depends on several factors. It isn't always worthwhile - the defaults are fine in many cases because they are simple and work out-of-the-box. But where performance optimization for a single job, or for a mass set of jobs which run simultaneously, is important, the time you invest in tuning the CPU and memory for compute, connect and batch pods can absolutely be worthwhile.

 

In preparing this post, I experimented with several other SAS procedures that are multi-threaded. In the environment I have to hand, the cpu time and real time taken to complete a PROC SORT with varying values of CPUCOUNT did not vary much once the compute context had 2 CPUs or more. I think that this is because a PROC SORT by default involves at least writing sorted data to disk, if not also reading unsorted data from disk. The test results indicate that with my test dataset in my environment, a proc sort on at least CPUCOUNT=2 was probably I/O bound, not CPU or memory bound. When you observe that adding more CPUs doesn't make a multi-threaded procedure run faster, that suggests CPU is not the bottleneck and something else, perhaps I/O throughput is.

 

You now know how to set up a set of both SAS Viya launcher contexts and compute contexts that you can use to find out what resource limits for CPU and memory will perform best, with your data, code and execution environment.  

 

 

Part 2, Section 3: How to change the global default CPU and memory request and limit

 

If you want all launched compute servers, connect servers and batch jobs in your SAS Viya deployment to run in pods that request a different default amount of CPU or memory as they are being scheduled to run, unless these values are overridden in the relevant launcher context, there are two places you can change the global defaults:

 

  • The sas.launcher.default configuration instance, for the Launcher service
  • Kustomize overlays referenced from your deployment's kustomization.yaml file and based on the examples launcher-memory-requests-limits.yaml and launcher-cpu-requests-limits.yaml in your SAS Viya deployment's sas-bases/examples/sas-launcher/configure directory.

 

You can modify the values for CPU and memory requests and limits specified in the sas.launcher.default configuration instance for the Launcher service, and this would be my recommended way to change the default CPU and memory requests and limits if you are a SAS administrator:  

 

09_DS_sas.launcher.default_config_instance.png

The sas.launcher.default configuration instance sets the default values that are used for CPU and memory requests and limits

if there is no other value specified through a kustomization overlay in the deployed SAS Viya podTemplates

for launched compute, connect and batch pods. 

 

 

But there is another way, and it takes precedence over the first one if you use it. I mentioned the example launcher-memory-requests-limits.yaml and launcher-cpu-requests-limits.yaml in your SAS Viya deployment's sas-bases/examples/sas-launcher/configure directory earlier, in section 2 of this article. The same example overlays that can be used to set the global maximum CPU and memory requests and limits, can also be used to change the global default CPU and memory requests and limits. Both sets of options are in the same example files.

 

So, if you copy these example yaml files to your site-config directory and reference the copies, or reference some other overlay based on them in your kustomization.yaml file and then use your usual deployment method to build the overall SAS Viya manifest and apply it to Kubernetes, then whatever defaults (and limits) you set in those files will apply to all launched compute, connect and batch pods from then on. Doing this takes precedence over using the sas.launcher.default configuration instance for the Launcher service.

 

There's a lot to get your head around here, so let's review the order of precedence between all these places you can set values for the same four properties:

 

  • CPU request: CPU capacity needed by a container, contributing to CPU capacity needed by its pod, that needs to be available on a node for the pod to start on that node
  • Memory request: memory needed by a container, contributing to memory needed by its pod, that needs to be available on a node for the pod to start on that node
  • CPU limit: nominal peak amount of CPU the container might use, contributing to peak amount of CPU its pod declares it might use, but the pod might be allowed to have more CPU if there is spare CPU capacity at a given moment without anything adverse happening
  • Memory limit: nominal peak amount of memory the container declares it might need, contributing to peak amount of memory the pod declares it might need, and crucially if the pod uses more than this amount of memory can be terminated by Kubernetes' OOM killer

 

First, find the maximum possible value for each of the above. Maximums can be set in this order of highest to lowest precedence:

 

  1. In the kustomization overlays - maximums set here take precedence if specified, but are NOT specified out of the box
  2. In the sas.launcher.max configuration instance - maximums are always specified here

 

With a maximum value for each of the four resource properties established, the SAS Launcher will then determine their actual values for the sas-programming-environment container in a launched sas-compute, sas-connect or sas-batch pod, from one of the following places, in this order from highest precedence (always wins) to lowest:

 

  1. A context-specific value specified in the launcher context wins, so long as it is equal to or smaller than the maximum for that value. If it is larger than the maximum, a compute session, connect session or batch job that uses this launcher context will fail to start.
  2. A global default value set in a sas-launcher kustomization YAML overlays in the deployment files mentioned above - defaults specified here are used, but these defaults are NOT specified out of the box. If a default value is larger than its respective maximum value (which would be a configuration error), ALL compute sessions, connect sessions or batch jobs will fail to start!
  3. A global default value set in the sas.launcher.default configuration instance - defaults are always specified here for the Launcher service. If one of these default values is larger than its respective maximum value (which would be a configuration error), ALL compute sessions, connect sessions or batch jobs will fail to start!

 

Hopefully you now know everything you need to know to be able to make different-sized compute, connect or batch contexts for different purposes, manage who has access to them, and carry out well-considered experiments that allow you to determine some reasonably optimal values for your particular workload, with your data, in your environment.  

 

See you next time! 

 

 

Find more articles from SAS Global Enablement and Learning here.

Contributors
Version history
Last update:
7 hours ago
Updated by:

sas-innovate-2026-white.png



April 27 – 30 | Gaylord Texan | Grapevine, Texas

Registration is open

Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!

Register now

SAS AI and Machine Learning Courses

The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.

Get started

Article Tags