[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP Pascal for OpenVMS
User Manual


Previous Contents Index

9.7.4 Optimal Data Size

Data items that are smaller than 32 bits might impose a performance penalty, due to the additional instructions required to access them. The compiler will attempt to reorder loads and stores that manipulate adjacent items smaller than 32 bits to minimize the number of memory references required.

For performance reasons, HP Pascal on OpenVMS I64 and OpenVMS Alpha systems will allocate Boolean and enumerated types as longwords in unpacked records or arrays. On OpenVMS VAX systems, you have to explicitly request this with a DCL qualifier or the corresponding attribute.

You should avoid any explicit size attributes on subrange types. While it is true that [BYTE] 0..255 is smaller than 0..255 (which would allocate 4 bytes, since it is a subrange of INTEGER), the additional overhead of accessing the byte-sized subrange might be than the extra 3 bytes of storage. Using the BIT attribute on subranges is even less effective in terms of the extra instructions required to manipulate a 13-bit integer subrange inside a record. Use these attributes only where needed.

9.7.5 Converting Existing Records

When moving code from an OpenVMS VAX system to an OpenVMS I64 or OpenVMS Alpha system, you probably want to make sure that you are getting the best performance on the new system. To do that, you must use natural alignment on your record types.

9.7.6 Applications with No External Data Dependencies

If your application has no external data dependencies (such as no stored binary data files, no binary data transmitted to some external device), then the conversion is as simple as:

  • Using the default natural alignment.
  • Using the default enumeration size.
  • Removing any uses of PACKED that are not needed.
  • Removing any explicit positioning or size attributes that are not needed.
  • Optionally reordering fields to place larger fields before smaller fields. This does not make the record faster, but does make it smaller.

Depending on your data types, the removal of any PACKED keywords or attributes may make little improvement in performance. For example, a PACKED ARRAY OF REAL is identical in size and performance to an unpacked ARRAY OF REAL.

HP Pascal has two features to help you identify poorly aligned records and how often they are used:

  • The /USAGE=PERFORMANCE command-line option
    This option causes the compiler to generate messages for declarations and uses of record fields that are poorly aligned or poorly sized. For example:


    program a;
    
    type r = packed record
             f1 : boolean;
             f2 : integer;
             end;
    
    begin
    end.
    

    In this program the compiler can highlight the following:


    $ pascal/usage=performance test.pas
    
             f1 : boolean;
    .........^
    %PASCAL-I-COMNOTSIZ, Component is not optimally sized
    at line number 4 in file DISK$:[DIR]TEST.PAS;32
             f2 : integer;
    .........^
    %PASCAL-I-COMNOTALN, Component is not optimally aligned
    at line number 5 in file DISK$:[DIR]TEST.PAS;32
    %PASCAL-S-ENDDIAGS, PASCAL completed with 2 diagnostics
    

    In this example, the size of the Boolean field in the PACKED ARRAY is only 1 bit. Single bit fields require additional instructions to process. The integer field is not aligned on a well-aligned boundary for the target system. The /USAGE=PERFORMANCE qualifier gives performance information customized to the target system. For example, on an OpenVMS I64 or OpenVMS Alpha system, INTEGERs should be on a longword boundary; on an OpenVMS VAX system, INTEGERs need only be aligned on a byte boundary for "good" performance.
  • The /SHOW=STRUCTURE_LAYOUT command-line option.
    This option causes the compiler to generate a structure layout summary in the listing file.
    This summary gives size and offset information about variables, types, and fields. It also flags the same information as the /USAGE=PERFORMANCE command-line option.
    For example, compiling the above program with the following command produces the following in the listing file:


    $ pascal/list/show=structure_layout test.pas
    


    Comments      Offset         Size
    -----------  -----------  -----------
                                  5 Bytes     R {In PROGRAM A} = PACKED RECORD
    Size             0 Bytes      1 Bit           F1 : BOOLEAN
    Align            1 Bit        4 Bytes         F2 : INTEGER
                                                  END
    

    This output shows the size of the record R as well as the sizes and offsets of the records fields. It also highlights any components that were poorly sized or poorly aligned.

9.7.7 Applications with External Data Dependencies

If your application has external data dependencies, the process is more involved, since you have to isolate and understand the dependencies.

Possible steps when porting the code include:

  • Using the /ALIGN=VAX qualifier
  • Using the /ENUMERATION_SIZE=BYTE qualifier
  • Using the /FLOAT=D_FLOAT qualifier (if you have any DOUBLE binary data)
  • Leaving the code exactly as is

This should produce the same behavior on the OpenVMS I64 or OpenVMS Alpha system as you had on your OpenVMS VAX system with the following exception: Using D_Floating data on Alpha systems only provides 53 bits of mantissa instead of 56 bits as on VAX systems; using D_floating data on OpenVMS I64 systems causes the compiler to convert to/from D_Floating data and IEEE T_Floating data to actually perform any needed operations.

You then have to identify which records in your program have external data dependencies. These include binary files (for example, FILE OF xxx), shared memory sections with other programs, and binary information passed to a library routine (such as an OpenVMS item list).

You can immediately begin to convert records without external data dependencies into optimal format (for example, remove any unneeded PACKED keywords and attributes as described earlier).

You need to classify records with external dependencies further into:

  • Records that cannot be naturally aligned due to a hard dependency that cannot be changed (like a record that maps onto an external piece of hardware, or a record that is passed to some software you cannot change).
  • Records that can be changed after conversion of binary data or cooperating software.

Isolate records that you cannot change into their own environment file by using /ALIGN=VAX, /ENUM=BYTE, and /FLOAT=D_FLOAT. You can also attach the ALIGN and ENUMERATION_SIZE attributes to the TYPE or VAR sections that define these records. In this case, you need to also change any uses of the DOUBLE datatype to the D_FLOAT datatype, to ensure that the proper floating format is used.

You do not need to isolate the record if it uses the PACKED keyword, since PACKED records are identical regardless of the /ALIGN or /ENUM qualifiers. Nevertheless, isolating the records with dependencies might be useful in the future if you eventually intend to change the format.

For records that you might change, you need to decide whether it is worthwhile to convert the record and any external binary data. If the record is of low use and you have a large quantity of external data, the cost of conversion is probably too high. If a record is of high use but is mostly aligned, then the conversion also may not be worthwhile. However, a high-use record that is poorly aligned suggests conversion of external data regardless of the amount of effort required.

There are two types of poorly aligned records:

  • Records that use the PACKED keyword
    PACKED records lay out the same with either setting of the /ALIGN or /ENUMERATION_SIZE qualifiers. To get natural alignment, you must remove the PACKED keyword. However, the keyword PACKED by itself does not guarantee poor alignment. For example:


    type t = packed record
             f1,f2 : integer;
             end;
    

    This record is well aligned with or without the PACKED keyword. It is also well aligned with /ALIGN=NATURAL and /ALIGN=VAX. You can remove the PACKED keyword for completeness, but nothing else needs to be done.
  • Unpacked records that lay out differently with /ALIGN=NATURAL and /ALIGN=VAX
    These records automatically are well-aligned by the compiler when recompiled with /ALIGN=NATURAL. However, there are some unpacked records are already well-aligned with both alignment formats. For example:


    type t = record
             f1,f2 : integer;
             end;
    

    This unpacked record is well aligned with /ALIGN=NATURAL and /ALIGN=VAX. Nothing else needs to be done to this record.

The /USAGE=PERFORMANCE and /SHOW=STRUCTURE_LAYOUT DCL qualifiers can be helpful for identifying poorly aligned records.

For PACKED keywords, you can compile with and without the PACKED keyword to see if the fields are positioned at the same offsets or not.

You have classified the records with external data dependencies into:

  • Records that are well-aligned with both alignment/enumeration formats
  • Records that are poorly aligned, where conversion is not worthwhile
  • Records that are poorly aligned, where conversion is worthwhile

For the well-aligned records, no additional work is needed now, but be aware that you still have an external data dependency that might cause problems if you add fields to the record in the future.

Isolate records that are not being converted into the same environment file or into the TYPE or VAR sections where you placed the records that you could not convert.

For records that are worth converting, you need to plan how to convert the external binary data or cooperating software. For cooperating software, you need to ensure that it gets modified so it views the record with the "natural" layout. You can determine the layout by using the /SHOW=STRUCTURE_LAYOUT command-line option described above. For binary data, you need to write a conversion program.

Converting existing binary data involves writing a program that reads the existing data into a poorly aligned record, copies the data into a well aligned record, and then writes out the new record.

A simple conversion program would look like:


program convert_it(oldfile,newfile);

[align(vax),enumeration_size(byte)]
type oldtype = packed record
               { Existing record fields }
               end;

type newtype = record
               { Record fields reorganized for optimal alignment }
               end;

var oldfile = file of oldtype;
    newfile = file of newtype;
    oldvar : oldtype;
newvar : newtype;

begin
reset(oldfile);
rewrite(newfile);
while not eof(oldfile) do
   begin
   read(oldfile,oldvar);

   { For each field, sub-field, etc. move the data }
   newvar.field1 := oldvar.field1;
   newvar.field2 := oldvar.field2;

   write(newfile,newtype);
   end;
close(oldfile);
close(newfile);
end.

Notice the "type" keyword before the definition of the "newtype" type. Without this keyword, "newtype" would be in the same type definition part as "oldtype" and would be processed with the same ALIGN and ENUMERATION_SIZE settings.

If you have embedded DOUBLE data, you must use the D_FLOAT predefined type in the "oldtype" definition, since the default on OpenVMS I64 systems is for T_floating format and the default on OpenVMS Alpha systems is for G_Floating format. The compiler does not allow a simple assignment of a D_FLOAT value to a T_FLOAT or G_FLOAT variable. You need to use the CNV$CONVERT_FLOAT routine provided with OpenVMS to convert the floating data.


Appendix A
Errors Returned by STATUS and STATUSV Functions

This appendix lists the error conditions detected by the STATUS and STATUSV functions, their symbolic names, and the corresponding values. The symbolic names and their values are defined in the file SYS$LIBRARY:PASSTATUS.PAS, which you can include with a %INCLUDE directive in a CONST section of your program. To test for a specific condition, you compare the STATUS or STATUSV return values against the value of a symbolic name.

The symbolic names correspond to some of the run-time errors listed in Appendix C; however, not all run-time errors can be detected by STATUS.

There is a one-to-one correspondence between the symbolic constants returned by STATUS or STATUSV documented in PASSTATUS.PAS and the OpenVMS condition code values in SYS$LIBRARY:PASDEF.PAS. The following routine shows how to map the return value of STATUS to its corresponding condition code located in PASDEF.PAS:


FUNCTION CONVERT_STATUS_TO_CONDITION(STAT:INTEGER):INTEGER;
   BEGIN
      CONVERT_STATUS_TO_CONDITION := 16#218644 + STAT * 8;
   END;

Table A-1 lists the symbolic names and the values returned by the STATUS and STATUSV functions and explains the error condition that corresponds to each value.

Table A-1 STATUS and STATUSV Return Values
Name Value Meaning
PAS$K_ACCMETINC 5 Specified access method is not compatible with this file.
PAS$K_AMBVALENU 30 "String" is an ambiguous value for the enumerated type "type".
PAS$K_CURCOMUND 73 DELETE or UPDATE was attempted while the current component was undefined.
PAS$K_DELNOTALL 100 DELETE is not allowed for a file with sequential organization.
PAS$K_EOF --1 File is at end-of-file.
PAS$K_ERRDURCLO 16 Error occurred while the file was being closed.
PAS$K_ERRDURDEL 101 Error occurred during execution of DELETE.
PAS$K_ERRDUREXT 127 Error occurred during execution of EXTEND.
PAS$K_ERRDURFIN 102 Error occurred during execution of FIND or FINDK.
PAS$K_ERRDURGET 103 Error occurred during execution of GET.
PAS$K_ERRDUROPE 2 Error occurred during execution of OPEN.
PAS$K_ERRDURPRO 36 Error occurred during prompting.
PAS$K_ERRDURPUT 104 Error occurred during execution of PUT.
PAS$K_ERRDURRES 105 Error occurred during execution of RESET or RESETK.
PAS$K_ERRDURREW 106 Error occurred during execution of REWRITE.
PAS$K_ERRDURTRU 107 Error occurred during execution of TRUNCATE.
PAS$K_ERRDURUNL 108 Error occurred during execution of UNLOCK.
PAS$K_ERRDURUPD 109 Error occurred during execution of UPDATE.
PAS$K_ERRDURWRI 50 Error occurred during execution of WRITELN.
PAS$K_EXTNOTALL 128 EXTEND is not allowed for a shared file.
PAS$K_FAIGETLOC 74 GET failed to retrieve a locked component.
PAS$K_FILALRCLO 15 File is already closed.
PAS$K_FILALROPE 1 File is already open.
PAS$K_FILNAMREQ 14 File name must be specified in order to save, print, or submit an internal file.
PAS$K_FILNOTDIR 110 File is not open for direct access.
PAS$K_FILNOTFOU 3 File was not found.
PAS$K_FILNOTGEN 111 File is not in generation mode.
PAS$K_FILNOTINS 112 File is not in inspection mode.
PAS$K_FILNOTKEY 113 File is not open for keyed access.
PAS$K_FILNOTOPE 114 File is not open.
PAS$K_FILNOTSEQ 115 File does not have sequential organization.
PAS$K_FILNOTTEX 116 File is not a text file.
PAS$K_GENNOTALL 117 Generation mode is not allowed for a read-only file.
PAS$K_GETAFTEOF 118 GET attempted after end-of-file has been reached.
PAS$K_INSNOTALL 119 Inspection mode is not allowed for a write-only file.
PAS$K_INSVIRMEM 120 Insufficient virtual memory.
PAS$K_INVARGPAS 121 Invalid argument passed to an HP Pascal Run-Time Library procedure.
PAS$K_INVFILSYN 4 Invalid syntax for file name.
PAS$K_INVKEYDEF 9 Key definition is invalid.
PAS$K_INVRECLEN 12 Record length nnn is invalid.
PAS$K_INVSYNBIN 37 "String" is invalid syntax for a binary value.
PAS$K_INVSYNENU 31 "String" is invalid syntax for a value of an enumerated type.
PAS$K_INVSYNHEX 38 "String" is invalid syntax for a hexadecimal value.
PAS$K_INVSYNINT 32 "String" is invalid syntax for an integer.
PAS$K_INVSYNOCT 39 "String" is invalid syntax for an octal value.
PAS$K_INVSYNREA 33 "String" is invalid syntax for a real number.
PAS$K_INVSYNUNS 34 "String" is invalid syntax for an unsigned integer.
PAS$K_KEYCHANOT 72 Changing the key field is not allowed.
PAS$K_KEYDEFINC 10 KEY(nnn) definition is inconsistent with this file.
PAS$K_KEYDUPNOT 71 Duplication of key field is not allowed.
PAS$K_KEYNOTDEF 11 KEY(nnn) is not defined in this file.
PAS$K_KEYVALINC 70 Key value is incompatible with file's key nnn.
PAS$K_LINTOOLON 52 Line is too long; exceeds record length by nnn characters.
PAS$K_LINVALEXC 122 LINELIMIT value exceeded.
PAS$K_NEGWIDDIG 53 Negative value in width or digits (of a field width specification) is invalid.
PAS$K_NOTVALTYP 35 "String" is not a value of type "type".
PAS$K_ORGSPEINC 8 Specified organization is inconsistent with this file.
PAS$K_RECLENINC 6 Specified record length is inconsistent with this file.
PAS$K_RECTYPINC 7 Specified record type is inconsistent with this file.
PAS$K_RESNOTALL 124 RESET is not allowed for an internal file that has not been opened.
PAS$K_REWNOTALL 123 REWRITE is not allowed for a file opened for sharing.
PAS$K_SUCCESS 0 Last file operation completed successfully.
PAS$K_TEXREQSEQ 13 Text files must have sequential organization and sequential access.
PAS$K_TRUNOTALL 125 TRUNCATE is not allowed for a file opened for sharing.
PAS$K_UPDNOTALL 126 UPDATE is not allowed for a file that has sequential organization.
PAS$K_WRIINVENU 54 WRITE operation attempted on an invalid enumerated value


Previous Next Contents Index