Program size and structure. IBM iSeries
Реклама
Реклама
Chapter 5. Designing efficient applications
In this chapter, design changes are suggested that can improve performance and efficiency without much change to the application program itself.
Program size and structure
The most efficient structure for a program is to have all the code in one program, with no subprograms. This structure can mean that programs are difficult to maintain. To overcome these potential problems, you might like to consider the following guidelines on program structure.
For modestly sized blocks of code that are processed sequentially, inline code is most efficient. The exceptions to this rule are blocks of code that are: v
Fairly long and used independently at several different points in the application v
Subject to frequent change (in which case, you balance the overhead of EXEC
CICS LINK or EXEC CICS XCTL commands with ease of maintenance) v
Infrequently used, such as error recovery logic and code to handle uncommon data combinations
If you have a block of code that, for one of these reasons, has to be written as a subroutine, the best way of dealing with this from a performance viewpoint is to use a closed subroutine within the invoking program (for example, code that is dealt with by a PERFORM command in COBOL). If it is needed by other programs, it should be a separate program. A separate program can be invoked using either an EXEC CICS LINK or XCTL command, or by a host language call.
Host language calls are more efficient than the EXEC CICS commands, but are functionally different in areas such as working storage initialization. See either
Choosing between pseudoconversational and conversational design
In a
conversational
transaction, the length of time spent in processing each of a user’s responses is extremely short when compared to the amount of time waiting for the input. A conversational transaction is one that involves more than one input from the terminal, so that the transaction and the user enter into a conversation. A
nonconversational
transaction has only one input (the one that causes the transaction to be invoked). It processes that input, responds to the terminal, and terminates.
Processor speeds are considerably faster than terminal transmission times, which, in turn, are considerably faster than user response times. This is especially true if users have to think about the entry or have to enter many characters of input.
Consequently, conversational transactions tie up storage and other resources for much longer than nonconversational transactions.
A
pseudoconversational
transaction sequence contains a series of nonconversational transactions that look to the user like a single conversational transaction involving several screens of input. Each transaction in the sequence handles one input, sends back the response, and terminates.
© Copyright IBM Corp. 1998, 2004
61
Before a pseudoconversational transaction terminates, it can pass data forward to be used by the next transaction initiated from the same terminal, whenever that transaction arrives. A pseudoconversational transaction can specify what the next transaction is to be, and it does this by setting the transaction identifier of the transaction that handles the next input. However, you should be aware that if another transaction is started for that device, it may interrupt the pseudoconversational chain you have designed.
No transaction exists for the terminal from the time a response is written until the user sends the next input and CICS starts the next transaction to respond to it.
Information that would normally be stored in the program between inputs is passed from one transaction in the sequence to the next using the COMMAREA or
There are two major issues to consider in choosing between conversational and pseudoconversational programming. The effect of the transaction on
contention
resources, such as storage and processor usage. Storage is required for control blocks, data areas, and programs that make up a transaction, and the processor is required to start, process, and terminate tasks. Conversational programs have a
very
high impact on storage, because they last so long, relative to the sum of the transactions that would make up an equivalent pseudoconversational sequence.
However, there is less processor overhead, because only one transaction is initiated instead of one for every input.
The second issue is the effect on
exclusive-use
resources, such as records in recoverable files, recoverable transient data queues, enqueue items, and so on.
Again, a conversational transaction holds on to these resources for much longer than the corresponding sequence of nonconversational transactions.
CICS ensures that changes to recoverable resources (such as files, transient data, and temporary storage) made by a logical unit of work (LUW) are made completely or not at all. An LUW is equivalent to a transaction, unless that transaction issues EXEC CICS SYNCPOINT commands, in which case an LUW lasts between syncpoints.
When a transaction makes a change to a recoverable resource, CICS makes that resource unavailable to any other transaction that wants to change it until the original transaction has completed. In the case of a conversational transaction, the resources in question may be unavailable to other terminals for relatively long periods.
For example, if one user tries to update a particular record in a recoverable data set, and another user tries to do so before the first one finishes, the second user’s transaction is suspended. This has advantages and disadvantages. You would not want the second user to begin updating the record while the first user is changing it, because one of them would be working from what is about to become an obsolete version of the record, and these changes would erase the other user’s changes. On the other hand, you also do not want the second user to experience the long, unexplained wait that occurs when that transaction attempts to read for update the record that is being changed.
If you use pseudoconversational transactions, however, the resources are only briefly unavailable (that is, during the short component transactions). However, unless all recoverable resources can be updated in just one of these transactions,
62
CICS for iSeries Application Programming Guide V5
recovery is impossible because LUWs cannot extend across transactions. So, if you cannot isolate updates to recoverable resources in this way, you must use conversational transactions.
The previous example poses a further problem for pseudoconversational transactions. Although you could confine all updating to the final transaction of the sequence, there is nothing to prevent a second user from beginning an update transaction against the same record while the first user is still entering changes.
This means that you need additional application logic to ensure integrity. You can use some form of enqueuing, or you can have the transaction compare the original version of the record with the current version before actually applying the update.
There are factors other than performance overhead to consider when choosing between pseudoconversational and conversational design for CICS applications.
The method you choose can affect how you write the application programs. You may need extra CICS requests for pseudoconversations, particularly if you are updating recoverable files. After you have done this, however, operational control
(performance monitoring, capacity planning, recovery, system shutdown, and distributing system messages) may be much easier.
General programming techniques
Programming techniques can affect the performance and efficiency of the CICS system.
Storage usage
A truly conversational CICS task is one that converses with the terminal user for several or many interactions, by issuing a terminal read request after each write
(for example, using either an EXEC CICS SEND command followed by an EXEC
CICS RECEIVE command, or an EXEC CICS CONVERSE command). This means that the task spends most of its extended life waiting for the next input from the terminal user.
Any CICS task requires some storage throughout its life and, in a conversational task, some of this storage is carried over the periods when the task is waiting for terminal I/O. The storage areas involved include the TCA and associated task control blocks and the storage required for all programs that are in use when any terminal read request is issued. Also included are the work areas (such as copies of
COBOL/400 working storage) associated with this task’s use of those programs.
With careful design, you can sometimes arrange for only one very small program to be retained during the period of the conversation. The storage needed could be shared by other users. You must multiply the rest of the virtual storage requirement by the number of concurrent conversational sessions using that code.
By contrast, a pseudoconversational sequence of tasks requires almost all of its storage only for the period actually spent processing message pairs. Typically, this takes a period of 1–3 seconds in each minute (the rest being time waiting for operator input). The overall requirement for multiple concurrent users is thus perhaps five percent of that needed for conversational tasks. However, you should allow for data areas that are passed from each task to the next. This may be a
COMMAREA of a few bytes or a large area of temporary storage.
Minimizing memory requirements
To improve performance, you should try to minimize the size of memory required.
You can do this by:
Chapter 5. Designing efficient applications
63
v
Writing modular programs and structuring the modules according to frequency and anticipated time of reference. Do not modularize merely for the sake of size; consider duplicate code inline as opposed to subroutines or separate modules. v
Using separate subprograms whenever the flow of the program suggests that execution will not be sequential. v
Not tying up memory awaiting a reply from a terminal user. v
Using command-level file control locate-mode input/output rather than move-mode. Use of multiple temporary storage queues is restricted. programs, using static storage for constant data. v Avoiding the use of EXEC CICS LINK commands where possible, because they generate requests for memory and require additional processor time. v
Specifying constants as literals in the procedure division, rather than as data variables in the WORKING STORAGE SECTION. The reason for this is that there is a separate copy of working storage for every task executing the program, whereas literals are considered part of the program itself, of which only one copy is used in CICS. v
Using static storage in ILE C for data that is genuinely constant, for the same reason as in the point above. Static storage is the same between different invocations of the same transaction and is shared between them. v Reusing data areas in the program as much as possible. You can do this with the REDEFINES clause in COBOL and the union clause in ILE C. In particular, if you have a map set that uses only one map at a time, code the DFHMSD map set definition without specifying either the STORAGE=AUTO or the
BASE operand. This allows the maps in the map set to redefine one another.
Refer to “DFHMSD” on page 555 for more information.
Refer to data directly by: v
Avoiding long searches for data in tables v
Using data structures that can be addressed directly, such as arrays, rather than structures that must be searched, such as chain v Avoiding methods that simulate indirect addressing v
Using binary or hash search algorithms
Processor usage
Pseudoconversational tasks require a new task to be created to process each message-pair, and to be deleted when that task has finished. These may include the cost of initializing a new work area for the program that is first entered. (In a conversational task, this area is retained permanently, as already mentioned.)
There may also be extra processor overhead because of extra requests needed to retrieve data passed from the previous task of the pseudoconversation, and possibly to pass data to the next task.
Recovery design implications
The fundamental and powerful recovery facilities that CICS provides have performance implications. CICS serializes updates to recoverable resources so that, if a transaction fails, its changes to those resources can be backed out independently of those made by any other transaction. Therefore, a transaction updating a recoverable resource gets control of that resource until it terminates or indicates with an EXEC CICS SYNCPOINT command that it wants to commit those changes. Other transactions requiring the same resource for update must wait until the first transaction finishes with it.
64
CICS for iSeries Application Programming Guide V5
The primary resources that produce these enqueue delays are files, databases, temporary storage, and transient data queues. For transient data, the “read” end of the queue is considered a separate resource from the “write” end (that is, one transaction can read from a queue while another is writing to it, provided that the records are committed).
To reduce transaction delays from contention for resource ownership, the length of time between the claiming of the resource and its release (the end of the LUW) should be minimized. In particular, conversational transactions should not own a critical resource across a terminal read.
Note:
Even for nonrecoverable files, CICS prevents two transactions from reading the same record for update at the same time. This enqueue ends as soon as the update is complete, rather than at the end of the LUW.
This protection scheme can also produce deadlocks as well as delays, unless specific conventions are observed. If two transactions update more than one recoverable resource, they must update the resources in the same order. If they each update two files, for example, file “A” should be updated before file “B” in all transactions. Similarly, if transactions update several records in a single file, they should always do so in some predictable order (low key to high, or conversely). Transient data and temporary storage must be included among such resources.
Many applications require a succession of interactions with the user to get all the data needed to create a file record. A conversational application might create a partial order record and then update it in stages, as the terminal operator enters items. If all the updates are to be committed and backed out together, this means retaining the protective enqueues on records throughout the conversation until the order is complete. You may need to protect both the current order being entered and the stock records that have been decreased by the number of items ordered.
Thus, a whole series of enqueues could be carried forward through the conversation for several minutes, and any other user making a conflicting request might wait without warning until the end of the order. Lastly, if the conversation went on to another order, presumably a CICS syncpoint would be taken to commit the previous one.
In a pseudoconversational implementation, the above approach is not possible because updates on one task are committed independently of any other. Therefore, an order that must be complete “in one piece” must be created by just one task.
However many interactions it takes to get all the necessary input, the final task has to be the one that creates the order. Data supplied earlier in the conversation must be saved somewhere between transactions—usually in temporary storage on disk.
That is, you must incur extra overhead in I/O to TS while the order is built up.
If the operator is taking orders over the telephone, with no written backup material on paper, then maybe the TS data itself should be made recoverable to avoid the remote client having to dictate the order again later on.
To summarize the issue: recovery places separate design constraints on
both
conversational and pseudoconversational implementations, but the performance cost of the pseudoconversational approach is usually more acceptable.
Chapter 5. Designing efficient applications
65
Изтегляне
Реклама