|
|||||||
VROOM - Window Processing IIThe last issue dealt with the way in which window flow can impair performance, specifically in relation to OCONVs and symbolics. Example code to deal with this problem by removing the OCONVs and symbolics at pre save and restoring them pre read is presented below. Note that the best performance improvements will be seen where the OCONVs and symbolics make reference to other files, eg code table lookups. To use the program, enter compile and catalog it and then put commuter calls to it on the PRE.INIT, PRE.READ and PRE.SAVE hooks. (EG Pre Save Code = S Pre Save Command = STRIPPER,PRE.SAVE. The code listing that follows is longer than our preferred length but this in view of the numerous comments contained therein it is felt to be acceptable. 0001 SUBROUTINE STRIPPER(BRANCH) 0002 * 0003 * Author AMcA with acknowledgements to Stefan Gilboy of ICS (Sales) for 0004 * the original idea 0005 * Date April 1990 0006 * 0007 BEGIN CASE 0008 CASE BRANCH = "PRE.INIT" ; GOSUB PRE.INIT 0009 CASE BRANCH = "PRE.READ" ; GOSUB PRE.READ 0010 CASE BRANCH = "PRE.SAVE" ; GOSUB PRE.SAVE 0011 END CASE 0012 RETURN 0013 0014 PRE.INIT: 0015 * 0016 * It is necessary to make a copy of all of the symbolics and OCONVs so 0017 * that they can be restored later when they have been removed. Anywhere 0018 * can be used, this example uses REGISTER(2). Note that as this logic 0019 * takes place at PRE.INIT the template structure is still in @RECORD so 0020 * this is manipulated 0021 * 0022 CTR = @RECORD<1> + 1 0023 NEW_REG = "" 0024 FOR X = 2 TO CTR 0025 * 0026 * Note that we store the field name and OCONV for EVERY prompt 0027 * regardless of the relevance of same. It is a moot point whether the 0028 * extra checks required to implement the extra logic might slow the 0029 * program down sufficiently to nullify the benefits accrued therefrom 0030 * 0031 NEW_REG<X-1> = @RECORD<X,2> : @VM : @RECORD<X,13> 0032 * 0033 * Don't null down key prompts as this seems to cause problems under 0034 * some circumstances. For all other fields though remove the field 0035 * name if symbolic to prevent recalculation and the OCONV 0036 * 0037 IF X > 2 THEN 0038 IF @RECORD<X,3> = "S" THEN @RECORD<X,2> = "" 0039 @RECORD<X,13> = "" 0040 END 0041 NEXT 0042 * 0043 * Now store NEW_REG in REGISTER(2) 0044 * 0045 @RECORD = FIELDSTORE(@RECORD,"÷",37,1,NEW_REG) 0046 RETURN 0047 0048 AREV.COMMON: 0049 * 0050 * Note - cannot be done at top of program as it is not loaded until 0051 * after PRE.INIT 0052 * 0053 $INSERT AREV.COMMON 0054 RETURN 0055 0056 PRE.READ: 0057 GOSUB AREV.COMMON 0058 * 0059 * If @ID is null then this is the "Dummy" pre read highlighted in the 0060 * last issue. Under these circumstances it makes no sense to reload the 0061 * missing information 0062 * 0063 IF @ID # "" THEN 0064 FOR X = 1 TO W.CNT 0065 W(X)<2> = REGISTER(2)<X,1> 0066 W(X)<13> = REGISTER(2)<X,2> 0067 NEXT 0068 END 0069 RETURN 0070 0071 PRE.SAVE: 0072 GOSUB AREV.COMMON 0073 * 0074 * Remove information 0075 * 0076 FOR X = 1 TO W.CNT 0077 IF W(X)<3> = "S" THEN W(X)<2> = "" 0078 W(X)<13> = "" 0079 NEXT 0080 RETURN Improving OCONV PerformanceAs evidenced in the last issue, OCONVs are called an inordinate amount of times in entry windows. If user-defined OCONVs which produce disk i/o are being used then performance will degrade dramatically. It is therefore only practical to examine ways of decreasing this overhead. One simple but effective improvement that can easily be made is to examine the value that the program is being asked to OCONV and then compare it with the value last OCONVed. If the two values are the same then there is no point in recalculating the value - simply use the result produced last time. The decision of where to store this information is a purely personal one but the higher fields in @RECORD are convenient if you remember to null them down on a Pre Save. The following logic serves to illustrate this. It assumes the basic structure of the user defined conversion has been defined and the data to convert is in PASSED_DATA whilst the data to return is in RETURNED_DATA. 0001 * Normal OCONV code precedes 0002 IF PASSED_DATA = @RECORD<100,1> THEN 0003 RETURNED_DATA = @RECORD<100,2> 0004 END ELSE 0005 @RECORD<100,1> = PASSED_DATA 0006 GOSUB CALCULATE_CONV 0007 @RECORD<100,2> = RETURNED_DATA 0008 END Note that in the example given above the passed data is stored in value one of the field and the OCONVed result is stored in field 2. This will obviously not work if the field being OCONVed is MVed. Improving SYMBOLIC performance - RLISTIt is frequently the case that symbolics make reference to other symbolics. As these need to be recalculated every time they are referenced this can reduce list performance. Extrapolating upon the technique used above we could modify our symbolics so that those symbolics that others used could place their result both in @ANS and @RECORD<x>. The other symbolics could reference this field and if null calculate the appropriate value and insert it. This means that in any list statement the same symbolic would only ever be calculated once regardless of how many times it was referenced. This sort of approach is simple to implement - the only problem is remembering to modify new symbolics in line with pre-existing ones. The performance improvements gained can be significant, in one disk intensive operation at a client recently, list speed was improved by an order of magnitude by applying this technique. The following code illustrates the technique - using two dictionary items, HOURS_TO_DATE and AMOUNT_TO_DATE (assume CALCULATE_HTD and CALCULATE_ATD exist and return the relevant information). 0001 * Hours to date, stored temporarily in @RECORD<100> 0002 IF @RECORD<100> THEN 0003 @ANS = @RECORD<100> 0004 END ELSE 0005 GOSUB CALCULATE_HTD 0006 @ANS = HTD 0007 @RECORD<100> = HTD 0008 END 0009 0010 * Amount to date, stored temporarily in @RECORD<101> 0011 IF @RECORD<101> THEN 0012 @ANS = @RECORD<101> 0013 END ELSE 0014 IF @RECORD<100> THEN 0015 HTD = @RECORD<100> 0016 END ELSE 0017 HTD = {HOURS_TO_DATE} 0018 @RECORD<100> = HTD 0019 END 0020 GOSUB 0021 CALCULATE_ATD 0022 @ANS = ATD 0023 @RECORD<101> = ATD 0024 END (Volume 2, Issue 3, Pages 4-6) |
|||||||
| |||||||