[SCA]
1 – Advanced Query Examples
The examples in this section use the SCA$EXAMPLE library. You are
encouraged to try these queries using the example library.
1. FIND CALLED_BY( END=translit, DEPTH=ALL)
This query gives the full call tree for TRANSLIT.
2. FIND CALLED_BY( END=translit, BEGIN=signal_duplicate, DEPTH=ALL)
This query returns all the call paths emanating from translit that
end up calling SIGNAL_DUPLICATE.
3. FIND CALLED_BY( translit, DEPTH=ALL, TRACE=(NOT OPEN*))
This query gives the full call tree for TRANSLIT, but does not
show any calls from items named OPEN*. Calls to items named OPEN*
appear in the call tree; however, items which are called by OPEN*
do not appear. Try the query without the trace expression and
compare the results when the TRACE is given.
4. FIND CALLED_BY( END=translit,
BEGIN=(NOT DOMAIN=PREDEFINED and NOT lib$*),
DEPTH=ALL )
This example leaves predefined functions and functions named
LIB$* out of the call graph. Functions such as CHR and WRITELN
in Pascal, MAX in FORTRAN, a builtin like _ADAWI in C, and so
forth are predefined. These functions are defined by the language,
not the programmer.
5. FIND IN( build_table and occ=comp, max_code )
This example finds all occurrences of MAX_CODE in the module
BUILD_TABLE. In this case, module has the same meaning as it
does in SHOW MODULE. This is the fastest way to limit a query to
occurrences in a particular module. The first parameter to the IN
function tells SCA in what container to look. The "and occ=comp"
part of the query ensures that the BUILD_TABLE you are looking
in is one of the modules displayed by SHOW MODULE, rather than
something else.
The second parameter to the IN function tells SCA what to look
for. This is faster than specifying the following:
FIND IN( build_table and occ=comp ) and max_code
Both queries in this example produce the same result.
Routines Used in a Module But Declared Elsewhere
In this example, you find functions that are used in a given
module but have their primary declaration in some other module.
This example is a multistep process that makes use of previous
queries. Each query in this section is numbered so that you can
refer to a specific query. If you refer to a query, adjust the
query name (for example, where @1 is used) to refer to the query
name you have created.
1. FIND IN( translit and occurrence=compilation_unit, -
symbol=function and domain=(global,inheritable) )
This query finds all occurrences of functions, either declarations
or references, in the module TRANSLIT.
You use "domain=(global,inheritable)" to limit the query only
to occurrence in which you are interested. Only global and
inheritable symbols can be imported because module-specific
symbols are from the same module, and predefined symbols come
from the language. Next, you have to remove any functions that
have their primary declaration in the module.
2. FIND @1 AND NOT EXPAND( @1 and occurrence=primary )
This query removes any functions that have a primary declaration
in the module TRANSLIT. What remains are those global or
inheritable functions that do not have a primary declaration in
TRANSLIT.
The EXPAND function in this query can be evaluated efficiently
by SCA. The parameter to EXPAND, @1 and occurrence=primary, can
be evaluated by looking at the result of query 1, so SCA does not
have to use the SCA library. Because the overall query does @1 AND
..., everything in the result is present in the result of query 1.
All we are doing is removing occurrences. In this case, SCA can
evaluate the whole query expression by looking at the result of
query 1 and does not have to use the SCA library.
Items Declared In a Module But Not Used Anywhere In the Module
In this example, you find occurrences of functions or variables
that are declared in a module but are not used in the module. This
example is a multistep process that makes use of previous queries.
The numbers by each query are used to refer to it later. If you
refer to a query, adjust the query name (for example, where @1 is
used) to refer to the query names you have created.
1. FIND IN( translit and occurrence=compilation_unit, -
symbol=(function, variable) )
This query finds all occurrences of functions or variables, either
declarations or references, in the module TRANSLIT.
2. FIND @1 AND NOT EXPAND( @1 and occurrence=reference )
This query removes from our first query any functions or variables
that have a reference in the module TRANSLIT. What remains are
those functions or variables that are not used anywhere in the
module.
The EXPAND function in this query can be evaluated efficiently
by SCA. The parameter to EXPAND, @1 and occ=reference, can be
evaluated just by looking at the result of query 1, so SCA does
not have to use the SCA library. Because the overall query does
@1 AND ..., everything in the result is present in the result of
query 1. All we are doing is removing items. In this case, SCA can
evaluate the whole query expression by looking at the result of
query 1, and does not have to use the SCA library.
Finding Unused Functions
This example finds functions or subroutines that are never used.
It provides several ways of solving the problem. Some of these are
easy to understand, but can be very slow on larger SCA libraries.
The more complex ones are intended to improve performance on
larger SCA libraries. They do not have a significant impact on
smaller libraries.
The first example finds unused functions only. Note that instead
of saying "occurrence=call" to find functions that are called, you
specify "occurrence=reference" to find functions that are used at
all. The query is as follows:
FIND symbol=function AND occurrence=primary -
AND NOT EXPAND( symbol=function and occurrence=reference )
On the SCA$EXAMPLE library, this query works well because it is
a small library. On a larger library, it may be too slow. To
evaluate this query, SCA must first evaluate "symbol=function
and occurrence=primary." It must then evaluate "symbol=function
and occurrence=reference" before doing any additional processing.
In this case, SCA has to do twice what is essentially the same
work. Also, SCA does not discard information about functions that
are referenced until the end, so it uses a lot of memory.
Using Previous Query Results to Find Unused Functions Faster
The next example also finds unused functions. However, it uses
previous query results, so the work is done only once. For this
reason, it is faster than the previous example. It also uses
somewhat less memory, but still not enough to make a difference on
a large library.
FIND symbol=function and occurrence=(primary,reference)
In the previous query, we find all the occurrences that we want to
use. We ignore the associated declarations at this point because
they are not essential to the query.
Next, we must select those functions that are not used as in the
following query:
FIND @1 AND occurrence=primary -
AND NOT EXPAND( @1 AND occurrence=reference )
This query removes from the list of functions in our system any
that are referenced, leaving only unreferenced functions. Because
you are using a previous query with all the information in it,
SCA does not have to access the SCA library, and performance is
generally faster.
However, on a large library, this may still be slow. The reason
for this is that it ends up keeping a list of all the functions
and all their references in memory.
Using Iteration to Find Unused Functions Faster
This is the most complex example. It includes some repetitive
parts that the query language does not provide directly. You
can do these using the callable interface, or by writing a .COM
procedure, or you can do the repetitive parts manually. This is
also the fastest form of the example and uses less memory.
Basically, you are going to split up the work into smaller pieces
to avoid having to keep everything in memory at the same time. In
this example, you process one module at a time, so you need to get
a list of modules first. You can do this by entering the following
query:
1. FIND occurrence=compilation_unit
In the next step, you have to loop through each of the
occurrences found in step 1. This part cannot be done directly
using the query language. You can do this using one of the
following methods:
o Do this manually, stepping through the occurrences in the
query one by one, and using INDICATED() in the following
queries where module_name is specified.
o Use the /DISPLAY options to specify only the name of each
occurrence found, capture the result in a file, and write
a command procedure to loop over the names. In this case,
you use "module_name and occurrence=compilation_unit" in the
following queries where module_name is specified.
o Use the callable interface. By writing a small program
using the callable interface, you can do the loop relatively
easily, using SCA$GET_OCCURRENCE and SCA$SELECT_OCCURRENCE.
In any case, you repeat the following steps for each of the
modules found in step 1.
2. FIND IN( module_name, symbol=function and occurrence=primary )
This step finds primary declarations of functions in the
current module. You want only primary declarations at this
stage because there may be some calls in other modules. In the
next step, you find any references to those functions:
3. FIND EXPAND( @2 )
This finds everything you need. At this point, what you do is
very similar to what you did for the examples in the previous
section.
4. FIND @3 and occurrence=primary -
AND NOT EXPAND( @3 and occurrence=reference )
This finds those functions in a particular module that are not
referenced anywhere. Steps 2 through 4 must be repeated for
each module.
2 – Basic Query Concepts
This section covers some of the basic concepts underlying SCA
queries.
You may want to have a hardcopy of this section. The directions
for producing a hardcopy are as follows:
1. Place the contents of Basic_Query_Concepts in a printable file
by typing the following command at the DCL command line:
$
Declarations
o PRIMARY - most significant declaration
o ASSOCIATED - associated declaration
o DECLARATION - primary or associated
References
o READ, FETCH - fetch of a symbol value
o WRITE, STORE - assignment of a symbol value
o ADDRESS, POINTER - reference to the location of a symbol
o CALL - call to a routine or macro
o COMMAND_LINE - command line file reference
o INCLUDE - source file include referenece
o PRECOMPILED - precompiled file include referenece
o OTHER - any other kind of reference (such as a macro expansion
or use of a constant)
o REFERENCE - any of the preceding values
o BASE - Any base class of a C++ class
o FRIEND - Any friend of a C++ class
o MEMBER - Any member of a C++ class
o SPEPARATE - Any Ada package or sub-program unit defined
as SEPARATE
o WITH - Any WITH of an Ada package or sub-program unit
Other Occurrence Classes
o EXPLICIT - explicitly declared
o IMPLICIT - implicitly declared
o VISIBLE - occurrence appears in the source
o HIDDEN - occurrence does not appear in the source
o COMPILATION_UNIT - the declaration that contains all
occurrences in a particular compilation unit
o LIMITED - Any Ada limited private type
o PRIVATE - Any private C++ objects, or Ada private type
o PROTECTED - Any protected c++ object
o PUBLIC - Any public C++ object
o VIRTUAL - Any virtual C++ object
The previous keywords are SCA terms. For information on
corresponding language-specific terms, request help for the
appropriate language table (for example, FORTRAN_ATTRIBUTES_TABLE)
under the Getting_Started help topic.
An example using the occurrence class attribute follows:
FIND OCCURRENCE=PRIMARY
This query finds all PRIMARY occurrences of declarations.
23 – Reducing LOAD Time
There are different means you can use to try to decrease LOAD
time. Listed below are a few guidelines that may help you reduce
LOAD time:
o Loading an SCA library for a software system is a time
consuming operation and should be done in batch. Loading
more than one module at a time is more efficient than loading
modules separately. Using LOAD *.ANA is a common method for
loading multiple modules. You use LOAD/DELETE to clean up .ANA
files after they are loaded successfully and to use a little
less disk space during the load.
o With large software systems, it is a good idea to use more
than one SCA library and load them all simultaneously. This
can lessen the elapsed LOAD time considerably. You should be
able to load several libraries simultaneously on a single
disk. Additionally, using more than one CPU to do your loads
also helps, but SCA loading is mainly I/O intensive. For more
information about how to use multiple libraries, see the help
subtopics under Libraries.
o Once your SCA library starts getting above 20K blocks, you
should consider preallocating the library when you create it.
SCA currently extends the library file by 1000 blocks at a
time, so for large libraries it frequently extends the library.
You can preallocate an SCA library by specifying CREATE LIBRARY
/SIZE=xxx, where xxx is the size of the library in disk blocks.
Use the size of the SCA$EVENT.DAT file in your current SCA
library directory as the value to the /SIZE qualifier.
o SCA uses a large number of I/Os during LOAD. Loading an SCA
library on a heavily used or badly fragmented disk causes the
load to be less efficient.
You can tell how badly your SCA libraries are fragmented by
using the following command:
$ DUMP/HEADER/BLOCK=COUNT=0 -
_$ DISK:[sca_library_directory]SCA$EVENT.DAT
The interesting portion of the output is the Map area. Each
retrieval pointer represents a contiguous section on the disk.
Because SCA extends SCA libraries 1000 blocks at a time, having
a lot of retrieval pointers smaller than this is a strong
indication that some defragmentation is needed.
24 – Quick Reference Card
The following page contains a reference of the SCA query language. It
is intended to be printed out and used as a Quick Reference Card.
ATTRIBUTE SELECTIONS: |RELATIONSHIP FUNCTIONS:
|
Name Class: |Short form:
---------- |-----------
<name-expression> |CALLED_BY(<caller>,<callee>,<depth>)
NAME=<name-expression> |CALLING(<callee>,<caller>,<depth>)
NAME=(<name-expression>,...) |
|CONTAINED_BY(<container>,<containee>,
Symbol Class: | <depth>)
------------- |CONTAINING(<containee>,<container>,
SYMBOL=<symbol-class-keyword> | <depth>)
SYMBOL=(<symbol-class-keyword>,...) |
|TYPED_BY(<type>,<typee>,<depth>)
Symbol Class keywords: |TYPING(<typee>,<type>,<depth>)
|
Argument, Component, Constant, |Long form:
Exception, File, Field, Function, |----------
Generic, Keyword, Label, Literal, |<rel-func>(END=<query-expression>,
Macro, Module, Package, Placeholder, | BEGIN=<query-expression>,
Procedure, Program, Psect, Routine, | DEPTH={<number> | ALL },
Subroutine, Tag ,Task, Type, Unbound, | RESULT=<result-keyword>,
Variable, Other, All, None | TRACE=<query-expression>)
|
Occurrence Class: |Result keywords:
----------------- |
OCCURRENCE=<occ-class-keyword> |Begin, End, [No]Structure, Any_path
OCCURRENCE=(<occ-class-keyword>,...) |
|OTHER FUNCTIONS:
Occurrence Class keywords: |----------
|
Declaration, Primary, Associated, |IN (END=<query-expression>,
Reference, Address, Call, | BEGIN=<query-expression>)
Command_line, Fetch, Include, |
Pointer, Precompiled, Read, Store, |EXPAND (<query-expression>)
Write, Other, All, None |
|@(<query-name>)
Domain Class: |
------------- |INDICATED() (NOTE: LSE required)
DOMAIN=<domain-class-keyword> |
DOMAIN=(<domain-class-keyword>,...) |NOT(<query-expression>)
|
Domain Class keywords: |
|
Global, Inheritable, Module_specific, |
Multi_module, Predefined, All, None |
|
File Class: |
---------- |
FILE=<filename-expression> |
FILE=(<filename-expression>,...) |
|
OPERATORS: |
---------- |
AND, OR, XOR, Pathname (\ or \\) |
|
ATTRIBUTE SELECTION EXPRESSIONS: |
<attri-select> [<op> <attri-select>]...|
25 – SCA Tutorial
This tutorial is for character cell LSE and SCA on
the OpenVMS platform. For a tutorial on the
DECwindows interface, please see the DECset Guide to
Source Code Analyzer.
If you do not have DECwindows, you may want to have a hardcopy
of this tutorial to follow it along interactively. The directions
for producing a hardcopy are as follows:
1. Place the contents of SCA_Tutorial in a printable file
by typing the following command on the DCL command line:
$ Close
Help