====== Caching in on the Frames Array - Mike Pope=====
^Published By^Date^Version^Knowledge Level^Keywords^
|Sprezzatura Ltd|01 MAY 1992|2.12+|EXPERT|CACHE, FRAMES, ARRAY, XLATE, MEMORY, MENU.BUFFER, TEMPLATE.READ, PURGE.CACHE, FLUSH, TEMPLATE.FLUSH|
Quiz time: what do the ROS filing system, window and menu templates, and
XLATE all have in common? The answer -- not an obvious one -- is that all
three take advantage of a little-known system cache known as the frames
array.
The frames array is a 49-element dimensioned array in the system common
block. It is initialised when you log in, and then loaded by the three
processes just named, each of which reserves for itself a different block
out of the 49 elements. Though you probably don't know it, you get the
indirect benefit of this cache every day. And as with any cache, you also
pay certain penalties. Below I'll explain who uses the cache and why and
when, the pros and cons of the cache, and what influence you can have on it.
==== The ROS Filing System ====
If your memory and history with Revelation stretches that far, you may
remember that Revelation C was released in the days of dual-floppy systems.
Disk I/O was painfully slow, so each access had to be worthwhile. The ROS
filing system was designed, therefore, to read frames of up to 64K at a
time. To further minimize hitting the disk, it was efficient to cache the
frames, and thus was born the frames array.
Both RTP51 and RTP59 in Advanced Revelation still use 10 elements of the
frames array. For each record I/O operation, the filing system first looks
to see if the necessary frame is in the array. If not, it is fetched from
disk, loaded into the array, and then used for subsequent I/O. The frame's
"name" -- its DOS file name -- is kept in a separate system common variable.
At strategic times the cached frames are written out to disk and the cache
cleared.
==== Window and Menu Templates ====
When Advanced Revelation came on the scene with its new interface, efforts
were made to optimise window and menu loading. One way was to expand the
number of elements in the frames array and stash templates there. The
process that reads templates maintains up to 26 templates in memory, and
uses another element to store the template names for a total of 27 elements
in the frames array. Any templates accessed after the 26th aren't cached.
==== XLATE ====
The frames array is also used by RTP16, the XLATE processor. XLATE is a
particularly good candidate for a cache, because it is, obviously, a
read-only operation. Moreover, often one XLATE request for a field is
followed shortly by another to fetch a second field from the same record.
RTP16 therefore caches up to 9 records in the frames array. If this limit
is exceeded (not often, as I'll explain), RTP16 throws records away on a
least-recently-used (LRU) basis. (The system uses XLATE a lot, so you may
not get all 9 elements to yourself.) In addition to using the frames array,
RTP16 uses a couple of other system variables as arrays of names and to
manage the LRU flags.
==== Pros and Cons ====
In all cases, the goal of caching records in the frames array is speed; the
idea is to avoid having to go to disk. For ROS files and XLATEs, because
these are often used for repeated accesses, the savings can be substantial.
The benefit for templates is nowhere near as great, but noticeable when
traversing a menu, for instance -- just pull down a menu from the action bar
and press the right arrow key, then try to imagine life without caching.
Caching has its drawbacks, however. The first is that it uses memory. With
up to 10 frames of up to 64K each, ROS files can potentially use lots of
memory. This is one filing system, therefore, that implements the BFS FLUSH
code seriously: whenever an R/BASIC FLUSH is executed, ROS writes all
"dirty" frames out to disk, and clears its portion of the frames array.
Likewise, while window and menu templates are not usually huge, 26 of them
hanging around in memory can be a problem, as can the 9 records being stored
by XLATE.
A second problem is that of currency. If RTP16 is able to fulfil its
request for a record from the cache, great; but what if the record has
changed on disk since the last time RTP16 read it? You may also have
experienced a currency problem if you've ever attempted to use a program
that dynamically updates window or menu templates after they've displayed.
You'll find that changes may not take immediate effect. What happens,
obviously, is that the system is reading the cached (old) version from the
frames array, not your new version on disk.
Fortunately, the system is sensitive to both of these issues. Any
low-memory condition causes a BFS flush, and this clears ROS frames out
immediately. But even normal processing keeps things under control.
Whenever you return to TCL from any command, the system executes a BFS flush
automatically. In addition, certain TCL verbs -- ATTACH, DETACH, LOGTO,
and sometimes compilation, including of dictionary items -- go so far as to
clear out the entire frames array. As you'd imagine, panic-button commands
like FLUSH and RESET also do some flushing, too.
Currency is handled to some extent as well. In ROS files it's not a
problem, as the filing system writes to the cache in addition to reading
from it (ROS files should never be used for shared data on a net!). Cached
window and menu templates can be out of synch with disk versions, but in
practice this doesn't come up very often, and you can control this yourself
anyway (see below).
XLATE is more interesting. It turns out that it is difficult to go behind
RTP16's back. Whenever you execute a WRITE or WRITEV statement, these
operations set a flag that causes the next call to RTP16 to throw away the
entire current XLATE cache and start again. This virtually guarantees that
your XLATEs will get a current version after you update a record (and is
why, as I mentioned above, you rarely overrun the 9-record limit). On a
network, no; your WRITE isn't detected by my XLATE, so I might still cache
old data.
==== Using the Frames Array ====
What can you do with the frames array directly? Well, you can clear it in
a couple of ways to regain memory. Call the system subroutine PURGE.CACHE
(no arguments) to clear the whole lot. Execute a FLUSH first if you use ROS
files. Call TEMPLATE.FLUSH (again no arguments) to clear only the templates
portion of the frames array, useful not just to clear memory, but to force
the system to re-read changed templates from disk. (Actually a wee bug in
current versions can cause the system to be confused about how many
templates are buffered, leaving undetected templates in memory.
TEMPLATE.FLUSH will clear all buffers, though, avoiding any resulting
problems with memory loss). (As noted, any WRITE operation clears the XLATE
cache.) The TCL verb FLUSH does a FLUSH plus PURGE.CACHE; TCL RESET (level
2+) calls TEMPLATE.FLUSH.
More interestingly, you can also update or read the cache directly using
TEMPLATE.READ:
TEMPLATE = TEMPLATE.READ( FILENAME, TEMPLATE_NAME )
This fetches not just a template, but any record from the cache, or from
disk if necessary (updating the cache). FILENAME can be an @FM-array of
files to search until the template/record is found. For menus specifically,
use the function MENU.BUFFER:
MENU = MENU.BUFFER( MENU_NAME, MENU_PTR )
This searches MENUS then SYS.MENUS for the menu (using TEMPLATE.READ, so it
gets cached). MENU_PTR returns the position of the menu within the labelled
common list of menu names.
==== Curiosities ====
Ponder these. It's easy to clear the frames array itself. But both ROS and
XLATE maintain separate variables for control information (names, LRU info);
no routines in the system clear these. These variables are not big, but
they do represent memory loss. Also, count up the number of elements used
by the processes discussed. There are 49 elements in the frames arrays, but
only 46 appear to be used. What happened here? Looks like one of those
mysteries, at least for now.
(Volume 4, Issue 1, Pages 8,9)