Controlling Process Scheduling

A process is considered scheduled when it has been submitted for initiation, but the system is delaying initiation of the process. Scheduling can occur for any of a number of reasons, most of which are not preventable by the programmer. For an explanation of these reasons, refer to the discussion of process scheduling in the System Administration Guide.

One type of process scheduling that you can prevent, to some extent, is scheduling due to a lack of available memory. The system performs this type of scheduling if it estimates that a particular process requires more memory for efficient execution than is currently available. The system places the process in a scheduled state until more memory becomes available.

The initial memory estimate for a process is created by the compiler and stored in the object code file. The memory estimate is an estimate of the average amount of memory that must be available for the process to run efficiently (that is, without excessive overlays). This ideal amount of memory is referred to as the working set of the process.

Each time the object code file is executed, the system writes an updated memory estimate into the object code file. The updated estimate is based on the average of the existing estimate and the memory usage during the current run. The effect is gradually refined and improved the accuracy of the memory estimate each time the object code file is run.

The memory estimate for a process consists of two separate statistics: the estimated process stack size, and the estimated memory usage for data and code segments. You can override the process stack size estimate through an assignment to the STACKSIZE task attribute. You can override the data and code estimate through an assignment to the CORE task attribute. By assigning large or small values to the STACKSIZE and CORE attributes, you can make it more or less likely that the system will schedule a process when it is submitted for initiation.

It is rarely necessary or desirable for you to make assignments to the STACKSIZE and CORE task attributes. It is true, for example, that you can help ensure that a process will not be scheduled by setting STACKSIZE and CORE to artificially low values. However, doing so could cause a system to begin thrashing, with the result that system performance could dramatically worsen.

The following are situations in which it might make sense to assign STACKSIZE and CORE values:

  • When initiating a program that is newly compiled. The memory estimate in such an object code file has not been refined through repeated use.

  • When initiating a program that is stored on a read-only disk. Many types of disk drives have a switch that enables an operator to put the disk drive in read-only mode. If an object code file is stored on a read-only disk, the system is not able to update the memory estimate in the object code file after each run.

  • When initiating a program whose memory usage varies widely from one run to the next. This can be the case if the memory usage depends on the type and quantity of the data passed to the program for processing.

Even in these situations, there is no point in your assigning a CORE or STACKSIZE value unless you have some information about what the working set of the program really is. You can get some general idea of the memory usage of a program by running it and examining statistics with the LOGANALYZER utility. You can use the LOGANALYZER MIX option to return log entries for a particular process. In the Major Type 1, Minor Types 2 and 4 (EOJ and EOT) log entries, you can find figures for the average memory usage of a process.

The average memory usage is not necessarily the ideal memory usage for a process; if memory is very crowded, the process might be constrained to use a less-than-optimum amount. Still, these statistics might be helpful in some cases.

For example, suppose you run the same reporting program twice a day: once to report on the payroll for your whole department, and once to summarize the time charged to certain accounts. Using LOGANALYZER, you might discover that the program consistently uses less memory for the time-accounting run than it does for the payroll run. In this example, the memory estimate in the object code file tends to reflect an average of the two types of runs. You can improve on this memory estimate for individual runs by assigning one set of CORE and STACKSIZE values for the time accounting run and another set of CORE and STACKSIZE values for the payroll run.