Managing server space for objects

From m204wiki
Jump to navigation Jump to search

Overview

The Model 204 VTBL table is particularly impacted by SOUL objects. VTBL space is required to accommodate two generic datastructures: object references and object instances.

  • Object references, each of which in a program is allocated a fixed amount of VTBL space at compile time, are primarily object variable declarations (explicit and implicit, in parameters and in user method definitions), though they also may include some internal "work" object variables. Object references are more complicated than SOUL %variables, and they take a few times more space in VTBL.
  • Object instances, which are completely run-time products, are created by a class's constructor methods (called explicitly or implicitly). The compiler reserves VTBL space to store the object instances in anticipation of their creation. For any object of any class ever referenced within a request, there must be space for at least one instance of the object in VTBL (and STBL, for parts of some objects, such as string variables). For certain methods, two, and rarely, three, instances must be available in VTBL at once.

SOUL uses object swapping to handle cases where a request has more objects than the compiler has reserved VTBL/STBL space for. Object swapping involves the managing of server-resident slots — object-instance "containers" — and the swapping of object instances between those slots in the server and pages of CCATEMP. This scheme combines extremely efficient access to object data with a modest memory requirement, and it may even produce smaller server sizes than comparable non-object applications once the code that uses those object classes is considered.

The subsections that follow discuss SOUL object swapping, the compiler directives that let you exchange object swaps for server table space, and statistics that report both swapping and server space allocation:

Swapping objects

SOUL objects effectively live in VTBL (and STBL) and in CCATEMP. The compiler reserves VTBL/STBL space for only a few object instances for each class that is referenced in a request. At run time, these object-instance slots are used for the objects instantiated in the request. If the number of objects instantiated exceeds the compiler-allocated slots, the swapping of objects out to CCATEMP begins.

The least-recently-used objects get swapped out. If such an object is referenced again, it gets swapped back in, probably pushing another object out. No server or CCATEMP space is kept for objects discarded explicitly or implicitly.

The SOUL swapping scheme trades performance (CPU) for server size economy. In general, as swapping increases, performance slips. Decreasing the server size (number of object spaces allocated) means more swapping is necessary. Increasing the number of object slots means less swapping but a larger server size.

Unfortunately, although object references are easily tracked during compilation, it is impossible to determine the right number of object instance slots to reserve in all but the simplest programs. Guessing the size of the "normal" working set of object instances of a particular class requires knowledge of what the program is doing and what its inputs are expected to be. Using the count of object references is not sufficient: In one program, all object references may point to a single collection object, for example, whereas in another program, each object variable may reference a different object.

Because there is no right number of objects to allocate at compile time, the SOUL compiler directives, discussed below, are provided to allow a programmer who is more aware of the likely performance requirements of a class to set the correct number of objects programmatically. In most cases these directives will not be necessary: most simple object-oriented applications have few objects, so swapping will be minimal. And even in complex applications where swapping is greater, the directives should be a recourse only if performance degrades intolerably.

Using compiler directives to modify object allocation

The MaxObjects, MinObjects, and AddObjects options of the Sirius compiler directive adjust the number of SOUL objects for which VTBL/STBL space is allocated at request compile time.

By default, that is, with no object compiler directives specified, SOUL allocates space for at most three (usually two) objects per class per request. This ensures that only a small amount of server table space is used for objects, and no object swapping occurs until more than two or three objects in a class are instantiated at the same time. This approach also prevents an exceptional, object-heavy request from forcing server tables to be huge for all requests.

For details about the calculation of the space allocated for an object, see the description of the components of the object statistics in Message format.

Contrast the default allocation behavior with a scheme designed to maximize performance, in which one object is allocated for every object reference in the request. This high-allocation approach eliminates most object swapping, but it is likely to allocate considerably more server space than is necessary for most programs. An extreme example of this is an application that has dozens of object variables, especially object variable parameters, that all reference the same object. In this case, VTBL/STBL space would be allocated for dozens of objects, yet most of the space would be unused.

You can adjust the allocation behavior by specifying one or more Sirius compiler directives in your program. You locate the directive after the Begin statement; directives referencing a user-defined class must follow the class definition. The directives have the following format:

Sirius option class number

Where:

option One of the following:
MaxObjects Sets an upper limit on the number of class objects for which space is allocated in VTBL/STBL. Sirius MaxObjects is useful for restraining server table size, although in some circumstances it can allow a larger allocation than if it were not specified. (For a demonstration of this paradoxical behavior, see the request example in How the compiler options interact.)

The Sirius MaxObjects default number setting is not a constant: when no MaxObjects directive is specified, the upper limit for the object allocation is set to the effective MinObjects value.

A MaxObjects setting of 1 is currently ignored, and a setting of 0 is a compilation error.

If there is more than one Sirius MaxObjects specification for a class, the minimum of these is the effective MaxObjects value. If there is both a Sirius MaxObjects and a Sirius MinObjects specification for aclass, the compiler allocation is bounded by their values and depends on the request complexity (see How the compiler options interact).

MinObjects Sets a lower limit on the number of class objects for which space is allocated in VTBL/STBL.

This should be the minimum number of objects you require for the program to perform well — if fewer are allocated, too much swapping occurs.

Its default number setting is 2 for non-system objects and for most system objects. For some system object and method combinations, the default is 3. A setting of 1 is currently ignored, and a setting of 0 is a compilation error.

If there is more than one Sirius MinObjects specification for a class, the maximum of these is the effective MinObjects value. If there is both a Sirius MinObjects and a Sirius MaxObjects specification for aclass, the compiler allocation is bounded by their values and depends on the request complexity (see How the compiler options interact).

AddObjects Adds to the effective Sirius MinObjects value. If there is more than one AddObjects specification for a class, the compiler adds their sum to the effective MinObjects value.

An AddObjects directive may be useful in an individual code fragment to reflect the increase in requirements caused by that fragment. If the procedure containing the fragment is included in the program, its AddObjects value is added to the effective MinObjects value for the program.

class The name of the system or user class for which you are specifying a directive.

For a collection, instead of a name, you specify the type of collection (for example, arraylist of object Invoice).

number The number of object instances of class class for which to allocate space.

Usage notes:

  • Typically, you use these directive options to trade server space for performance gain, depending on the constraints in effect at your site and the type of requests you are running. Your most likely options are:
    • To emphasize performance, increase the Sirius MinObjects setting for one or more classes.

      This increases the number of object instances for which space is allocated in VTBL/STBL. The result is less swapping between the server table and CCATEMP, so better CPU performance. The expense is VTBL/STBL resources, so you may need to increase your VTBL or STBL size.

    • To restrain server size, specify a Sirius MaxObjects setting for one or more classes.

      This sets an upper limit on the number of objects for which space is allocated in VTBL/STBL. However, the space-conservative behavior of the default SOUL object space allocation makes Sirius MaxObjects of limited utility. It may be most useful in a large program that liberally employs MinObjects and AddObjects directives. A single Sirius MaxObjects directive at the top of the program can act as an overall safeguard on the required server table space.

      For some programs that make extensive use of user classes, selectively including object methods is an approach that may provide a significant reduction in server requirements. This is described in "Selectively compiling user methods".

  • Sirius MaxObjects only raises the ceiling for the number of object instance slots that the compiler may allocate — it allows but does not force a greater allocation (as Sirius MinObjects does).
  • As shown in the next section, the OBJSTAT statistics report lets you compare object allocation and swapping to help you determine whether and how much to adjust the object allocation of any of the classes in your program. You can also use Model 204 TIME REQUEST command output to indicate the effect on CPU performance of your adjustments.

A MinObjects example

To see the effects of the compiler directives, consider the object allocation report shown in "Sample object statistics". Those statistics (invoked by the OBJSTAT parameter) show object handling when no compiler directives are specified. Note the relatively high swapping counts of the LONG, PT, and CELL objects:

OBJECT LONG: objects/VTBL/STBL - 2/7/0, count/pages swapped 571/571 OBJECT PT: objects/VTBL/STBL - 2/18/0, count/pages swapped 310/310 OBJECT CELL: objects/VTBL/STBL - 2/20/0, count/pages swapped 528/528 ... *TOTAL*: objects/VTBL/STBL - 14/163/144, count/pages swapped 1409/1409

The output from a T REQUEST command issued in that situation includes the following statistics:

STBL=8453 VTBL=1002 CPU=1064 OBJSWAP=1409

In an effort to maximize performance in this case, the following compiler directives are set to allocate space for more of these object instances in VTBL (they are not using STBL), thereby reducing swapping:

Sirius Minobjects Long 20 Sirius Minobjects Pt 15 Sirius Minobjects Cell 310

After rerunning the program, the resulting OBJSTAT statistics show the swapping eliminated (at the expense of additional VTBL space):

OBJECT LONG: objects/VTBL/STBL - 20/63/0, count/pages swapped 0/0 OBJECT PT: objects/VTBL/STBL - 15/132/0, count/pages swapped 0/0 OBJECT CELL: objects/VTBL/STBL - 310/3023/0, count/pages swapped 0/0 ... *TOTAL*: objects/VTBL/STBL - 353/3336/144, count/pages swapped 0/0

The T REQUEST output shows reduced CPU, increased VTBL consumption, and no OBJSWAP value (indicating that there was no swapping):

STBL=8453 VTBL=4174 CPU=1053

Comments:

  • Without a suitably large VTBL, increasing the number of object instances allocated as in this example would have broken the program because of insufficient VTBL space.
  • The CPU savings were not dramatic: SOUL object swapping is quite efficient. The savings are likely to be proportional to the size of the objects that no longer are being swapped.
  • The settings of the compiler directives were determined after a few trials. Such testing is necessary because the effect of the setting of a directive is program and object dependent. In this case, the directives for two of the objects did not have to be set very large to prevent swapping, whereas the third object required a relatively large value. In the program, this third object was often instantiated as a collection item, so it was relatively under-counted by the object allocation algorithm, which relies heavily on a count of explicit object declarations.

How the compiler options interact

If multiple directives are specified in a program for a class, this section describes rules for calculating the actual number of object instance slots for which the compiler allocates VTBL/STBL space.

Note: Remember that the number of object instance slots for which the compiler allocates space may not be optimal in terms of swapping reduction. It may not be an amount that eliminates swapping. Or it may be an amount that eliminates swapping, but is not the lowest number of slots at which swapping is eliminated.

These are identifiers for the critical values taken into consideration in the rules that follow:

AbMin Per class, the required minimum number of object instances for which space must be allocated in any request. This value overrides any and all explicit directives: the compiler will in all circumstances allocate at least AbMin object slots.
Max The effective MaxObjects value. Per class, the lowest Sirius MaxObjects setting.
Add The effective AddObjects value. Per class, the sum of the Sirius AddObjects settings.
Min The effective MinObjects value. Per class, the larger of these:
  • AbMin
  • The highest Sirius MinObjects setting, plus Add.
Native The object instance allocation count determined by the compiler before consideration of any explicit or implied directives. This count is typically very close to the number of object variable declarations in the program.

In the program in A MinObjects example, the compiler would allocate space for 32 LONG class object instances if it were not for the default limit (MinObjects=2)or for any explicit directives. However, with MinObjects set to 20, swapping was reduced to 0. Thus, the Native value represented more object slots than the program actually made use of atany one time. In other programs, the Native value may be less than the number actually required to reduce swapping to 0.

To determine the Native value for a class, you can specify a single MaxObjects directive that is set to an unusually high value, say, three times the number of objects the program probably instantiates. In the example being discussed, MaxObjects for LONG was set to 100.

The OBJSTAT statistics that resulted showed space for 32 object instances allocated (and swapping, as expected, was 0).

For another example, consider the following request, which declares multiple objects that are never instantiated:

Begin %sla Collection Arraylist Of Object Stringlist Auto New %sl Object Stringlist %slnew Object Stringlist %slnew2 Object Stringlist %slnew3 Object Stringlist %slnew4 Object Stringlist %i Float %j Float %limit Float %limit = 8 For %i From 1 To %limit %sl = New For %j From 1 To %i %sl:Add('Strlist ' With %i With ' item ' With %j) End For %sla:Add(%sl) End For For %i From 1 To %limit Print '--- Item ' %i ' has ' %sla(%i):Count ' items' %sla(%i):Print End For End

The request produces the default allocation for Stringlists:

OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 3/18/0,
count/pages swapped 21/21 COLLECTION SYSTEM:ARRAYLIST OF OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 2/17/0,
count/pages swapped 0/0

With a Sirius MaxObjects setting that is sufficiently high (say, 25), the compiler allocates object instance slots (6) according to its "Native" algorithm:

OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 6/35/0, count/pages swapped 18/18 COLLECTION SYSTEM:ARRAYLIST OF OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 2/17/0,
count/pages swapped 0/0

This example shows how the Native count tallies object declarations, even if the objects declared are not instantiated. The example also shows how the Native count may not account for objects within collections.

The following rules describe the compiler allocation outcomes when combinations of directives are specified for a class:

  1. The number of object slots allocated for a class is never allowed to fall below AbMin for that class.
  2. The number of object slots allocated for a class is not allowed to exceed Max for that class. The only exception is if Max is less than AbMin.
  3. In the absence of any MaxObjects settings, Min becomes the effective Max.
  4. If there is a combination of Sirius MaxObjects and Sirius MinObjects specification for a class, the compiler allocates as follows:
    Situation Object slots allocated
    Min < Max Min or greater

    There are three cases, which are also depicted in the figure below:

    1. If Min >= Native, Min are allocated (not to exceed Max).
    2. If Min < Native < Max, Native are allocated.
    3. If Native > Min, and Native >= Max, Max are allocated.
    Max <= Min Max

    The compiler will try to allocate Min object slots, but it will "stop" when it reaches Max (by rule 2, Max is not exceeded).

Object allocation (multiple directives, Min < Max)

Cfiggg3a.png

Cases a, b, and c in the figure above are those described in rule 4, above. The figure shows that, if a combination of MaxObjects, MinObjects, and AddObjects compiler directives are specified, the actual object space allocation in VTBL you get depends on how the compiler's Native count (N) of the needed object instance slots compares to Max and Min, the effective MaxObjects and MinObjects values.

Selectively compiling user methods

Sites that feature user-created classes can economize on server space consumption by modularizing their application code and by including user method definitions only if the methods are actually called.

SOUL classes incorporate a "header file" type of design: the declaration of classes is distinct from the code that implements the classes. This separation will let you package user classes in multiple procedures, one or more of which contain the declaration of the class definitions, while others contain the code for the various methods. Although the compiler needs the complete declaration to compile references to members of each class, the code that implements functions and properties need only be included if it is actually used in a particular procedure in the current compilation.

With this approach, you can avoid the extra server space accumulated by multiple includes of the same definition or method code within a single compilation of a complex program. You can even programmatically prevent such duplicate includes by using the !DUPEXIT SOUL macro.

Displaying object statistics

The OBJSTAT User 0 parameter controls the display of journal messages that contain user statistics about SOUL object usage per request. The messages specify server table usage (VTBL and STBL) and object-swapping counts per object class and summed for all classes.

Message format

You can set OBJSTAT to display object statistics after program compilation, evaluation, or both (as described below in Setting OBJSTAT). The layout for post-compilation messages is the same as that for post-evaluation messages, as described below and as shown in Sample object statistics:

  • One message for each class of objects instantiated in the program, with this format:

    MSIR.0884: [OBJECT | COLLECTION] classname: objects/VTBL/STBL - obj/vtb/stb, count/pages swapped osw/psw

  • A single message that reports the sum of the counts of the preceding individual classes, with this format:

    MSIR.0884: *TOTAL*: objects/VTBL/STBL - obj/vtb/stb, count/pages swapped osw/psw

Where:

classname Identifies the name of the class for which space for object instances is allocated. System classes are prefixed with SYSTEM:. System enumerations are excluded because they are not stored in VTBL or STBL.
objects Object instances for which server space is allocated for the indicated class (or for all classes) for the request. This space is allocated at compile time, thus separate from the actual number of run-time objects used.

The number of objects allocated is obj

VTBL VTBL units (32 bytes per unit) occupied by the objects. Each instance of an object in a given class requires the same amount of space: a fixed amount for an object header, and a non-fixed amount for each member variable (that is, every variable in the Public or Private — but not Public Shared or Private Shared — blocks).

The number of VTBL units allocated is vtb.

The vtb units do not include the VTBL space that is occupied by each local object reference in the main program routine. These references include object variables in declarations (including method parameter declarations and explicit and implicit method objects) and "work" object variables. These work variables are used to hold intermediate results in the evaluation of statements containing method concatenations. They may be reused within the class, and they typically do not add significantly to the VTBL space used. Object references use 2 VTBL units each, excepting XmlNodes, which use approximately 8.

STBL STBL bytes occupied by the objects. Parts of some objects, such as string and longstring variable values, use STBL.

The number of STBL units allocated is stb.

obj, vtb, stb The number, respectively, of objects, VTBL units, and STBL bytes.

Note: These amounts encompass all the space used for object instances, which includes some internal overhead. It does not include the space used for object references, that is, object variables.

count The count of object swaps: the number of times object instances of this class were swapped into or out of the server during the request.

The value of count is osw.

Note: A swap out counts as one, and a swap in as one, so a swap in and out counts as two. Accessing a global/session object counts as a swap in, since objects do not sit in the server between requests, so they need to be swapped into/out of CCATEMP. Swaps happen only during evaluation, so this number should always be zero in the post-compilation statistics.

pages swapped The number of 6144-byte pages swapped into or out of the server. This number should always be an integral multiple of count, and the multiplier should be one, except for very large objects (greater than 6144 bytes).

The value of pages swapped is psw.

osw, psw Values, respectively, of count and pages swapped.

Setting OBJSTAT

OBJSTAT is a typical Model 204 bitmask parameter that is also per-user and resettable. It contains the following bit options, two or more of which you can select by specifying the sum of their bit values:

X'00' Display no OBJSTAT statistics; this is the default.
X'01' Display post-compilation object statistics to the journal.
X'02' Display post-evaluation object statistics to the journal.
X'10' Display post-compilation object statistics to both the terminal and the journal.
X'20' Display post-evaluation object statistics to both the terminal and the journal.

Note: X'22' is the same as X'20'; X'10' is the same as X'11'; and X'30' is the same as X'31', X'32', or X'33'.

You can set OBJSTAT in the User 0 stream, and you can reset it with the Model 204 RESET command (for example, R OBJSTAT X'33') or with the $Resetn function (for example, $RESETN('OBJSTAT', $X2D('33'))).

Sample object statistics

With OBJSTAT set to X'33', the following SirScan AD-line output displays after including a procedure that manipulates some objects. The post-compilation individual-class statistics and all-class totals are followed by the post-evaluation statistics and totals.

MSIR.0884: OBJECT LONG: objects/VTBL/STBL - 2/7/0, count/pages swapped 0/0 MSIR.0884: OBJECT PT: objects/VTBL/STBL - 2/18/0, count/pages swapped 0/0 MSIR.0884: OBJECT CELL: objects/VTBL/STBL - 2/20/0, count/pages swapped 0/0 MSIR.0884: OBJECT BOX: objects/VTBL/STBL - 2/75/144, count/pages swapped 0/0 MSIR.0884: COLLECTION SYSTEM:ARRAYLIST OF OBJECT PT: objects/VTBL/STBL - 3/25/0, count/pages swapped 0/0 MSIR.0884: OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 3/18/0, count/pages swapped 0/0 MSIR.0884: *TOTAL*: objects/VTBL/STBL - 14/163/144, count/pages swapped 0/0
MSIR.0884: OBJECT LONG: objects/VTBL/STBL - 2/7/0, count/pages swapped 571/571 MSIR.0884: OBJECT PT: objects/VTBL/STBL - 2/18/0, count/pages swapped 310/310 MSIR.0884: OBJECT CELL: objects/VTBL/STBL - 2/20/0, count/pages swapped 528/528 MSIR.0884: OBJECT BOX: objects/VTBL/STBL - 2/75/144, count/pages swapped 0/0 MSIR.0884: COLLECTION SYSTEM:ARRAYLIST OF OBJECT PT: objects/VTBL/STBL - 3/25/0, count/pages swapped 0/0 MSIR.0884: OBJECT SYSTEM:STRINGLIST: objects/VTBL/STBL - 3/18/0, count/pages swapped 0/0 MSIR.0884: *TOTAL*: objects/VTBL/STBL - 14/163/144, count/pages swapped 1409/1409

For a case where these statistics guide the tuning of the object allocation algorithm, see A MinObjects example.

See also