Search

ParaSoft

HOME
PRODUCTS
SUPPORT
ABOUT
WHAT'S NEW
EVENTS


Insure++

Quick facts

Add-on Modules:
   -INUSE
   -TCA

Comparisons

Technical Papers

Support & Manuals

FAQs

Recent Reviews

User Testimonials

Press Releases


Insure tool to debug c++





Running Inuse


Table of Contents


Running Inuse

The basic steps involved in using Inuse are:

  • Running the GUI.
  • Linking your program to Inuse.
  • Adding the inuse on option to your .psrc file and running the application program. During runtime, you can view and manipulate the displays shown by the GUI. You can even watch the memory allocation as you single step through your program from a standard code-oriented debugger.

This section will cover each of these steps detail.

The basics

You must start the Inuse program before you attempt to display results from any user application. (If you try to run an application before starting Inuse it will run normally, without displaying any memory activity.)

In normal use, you should enter the inuse command once and simply leave it running as a background process.

	inuse

You should compile your code with your regular compiler and then link with Insure++ as shown below.

	insure -o foo foo.c

To enable runtime display of memory activity, you need to set the following option in your .psrc file.

	insure++.inuse.on

Inuse can be linked simultaneously with any number of application programs. By turning this option on or off, you can control when your programs connect to Inuse. If you exit Inuse, you must restart it before running any applications for which you wish to display memory activity.

The Inuse GUI

Executing the inuse command opens the Inuse GUI. (See Figure 2).

Inuse

Figure 2. The Inuse GUI

Bend The "look and feel" of a windowing application will vary quite significantly from system to system. As a result, the version of Figure 2 that you see may differ from that shown here. Furthermore, the ways in which you control the menu selections, etc. may also vary.

The display contains two basic elements as indicated:

Menus
File
Select Exit to close Inuse.
Processes
Select Next or Prev to choose among
linked programs.

Select Del to remove a program from the list.

Select Stop to stop receiving memory display
information from a linked program.

Select Step to display one allocation or free
request from the program at a time.
Reports
Select a report for Inuse to display. Reports
are described in detail in the next section.
Help
Get help for using Inuse, including the
Inuse FAQ and version information.
Toolbar The toolbar has buttons for most menu options.
Clicking on a button selects that option.

Inuse Reports

Inuse can generate the following reports:

Heap History This graph displays the amount of memory allocated to the heap and the user process as a function of real (i.e., wallclock) time. This display updates periodically to show the current status of the application, and can be used to keep track of the application over the course of its execution.
Block Frequency This graph displays a histogram showing the number of blocks of each size that have been allocated. It is useful for selecting potential optimizations in memory allocation strategies.
Heap Layout This graph shows the layout in memory of the dynamically allocated blocks, including the free spaces between them. You can use this report to "see" fragmentation and memory leaks.

You can scan through different areas of the layout by pressing the Fast Left (Fleft), Fast Right (Fright), and left and right buttons on the Heap Layout toolbar. You can also zoom in (+) and out (-) of the layout by pressing the zoom buttons. (These options are also available in the Controls menu.)

Clicking the mouse on any block of the heap layout will tell you the block's address, size, and status (free, allocated, overhead, or leaked). Clicking on an allocated or leaked block will also open a window telling you the block id, block address, stack size, and stack trace for the selected block.

Time Layout This graph shows the sequence of allocated blocks. As each block is allocated it is added to the end of the display. As blocks are freed, they are marked green. From this display, you can see the relative size of blocks allocated over time. This will allow you to determine if you are allocating a huge block at the beginning of the program or many small blocks throughout the run, for example.
Usage Summary This bar graph shows how many times each of the memory manipulation calls has been made. It also shows the current size of heap and the amount of memory actively in use. (The heap fragmentation can be computed simply from these numbers as (total-in_use)/total).
Query The query function enables you to "view" blocks of memory allocated by your program according to their id numbers, their size, and /or their stack traces. You can edit the range of the query according to block id, block size and stack trace.

By "grouping" blocks of memory in this way, you can better understand how memory is being used in your program. The range options let you narrow or broaden your query to your specifications. For example, you can see how much memory is being allocated from a single stack trace or by the entire program combined. For each, query you can choose whether you receive a detailed (i.e. containing block id, block size, and stack trace information) or summarized report.

Which report to use?

Which report is most useful depends on what you are trying to learn about your application.

  • If you simply wish to see how much memory is being used, the "usage summary" and "heap history" reports.
  • If you wish to optimize your memory allocation strategy, perhaps by building your own allocator for blocks of certain sizes, the "block frequency" graph is appropriate.
  • To study the heap fragmentation caused by your algorithm, and understand the way that memory blocks are laid out, you should use the "heap layout" graph.
  • To see correlations between block id, block size, and stack traces in your program, use the query option.

Block Color in Inuse

An important visual aid in Inuse is its use of colors to represent the various properties of the heap. These colors are as follows

Black Indicates the total memory allocated to the heap. This is usually the amount of memory that gets swapped to disk whenever your application is swapped from memory, regardless of whether or not you are actually using it.
Blue Denotes leaked blocks as reported by Insure++. (Only available if running Inuse and Insure++ together).
Green Free space that is available to be allocated.
Red Denotes allocated blocks.
Yellow "Overhead" associated with each block. Normally the system keeps a small amount of memory with each allocated (and maybe free) block for its bookkeeping information. This memory cannot be used by the application, although its impact can be reduced by allocating fewer large blocks rather than many small ones.

Inuse Reports

This section will describe each Inuse report option in detail.

The "Heap History" report

Clicking on the Hist button or selecting Heap History from the Reports menu brings up the Heap History window. If your program is running when you open this reports, you will be able to monitor the amount of memory allocated by the program as it executes. If the program has ended its run, you can see how much memory was allocated across the history of the run.

Inuse

Figure 3. The Heap History window

The black area indicates the total size of the heap. The red, yellow, and blue areas constitute the make-up of the heap. The red area represents the amount of memory allocated by the program. The yellow area represents the amount of "overhead" associated with the memory (but which cannot be used by the application). The blue area represents the amount of leaked memory.

To change the sampling rate, that is, how much time passes before the graph is updated, press the Sampl button or select Sampling from the Options menu.

The "Block Frequency" report

The "block frequency" report will show you what sizes of blocks are typically being allocated by your program. If you are allocating many small blocks, you may want to switch to a different memory allocation scheme which groups many small allocations into several larger ones. A "block frequency" graph might look like the one in Figure 4.

Inuse

Figure 4. A "Block Frequency" graph

The Block Frequency graph groups together blocks that are similarly sized. Each bin (column) in the graph represents the number of blocks in a particular size range. Clicking on a bin will show you the number and size range of blocks contained in that bin.

The right-most bin includes all blocks above a certain size. If this bin is very high, click to see the size range covered by that bin. If the range is fairly wide, you can rescale the graph to include more bins by pressing the Bins button or selecting Bins from the Options menu. Entering a number higher than the number currently shown should narrow the size range for each bin. Likewise, entering a number that is lower than the number currently shown should increase the size range included in each bin. If all block sizes are currently represented on the graph, increasing the bin number will have no effect.

You can alternate between a linear or logarithmic scale by pressing the Yscale buttons. Pressing the Xscale button will toggle the x-axis between linear and logarithmic scales. Pressing the Yscale button will toggle the y-axis between linear and logarithmic scales. Selecting Horiz.log/lin or Vert.log/lin from the Options menu will also toggle the x- or y-axis.

The "Heap Layout" report

The Heap Layout report shows the status of blocks in the program's heap. Blocks are either free, allocated, overhead, or leaked.

Inuse

Figure 5. The "heap layout" report

Click on a block to see its address, size and status. This information is shown in the lower right corner of the display screen.

If the block is allocated or leaked, a Memory Information window will also appear. The memory information window contains the block's id, address, stack size, and stack trace.

Inuse

Figure 6. Memory Information window

You can scan through different areas of the heap layout by pressing the Fast left (Fleft), Fast Right (Fright) and left and right buttons on the Heap Layout toolbar. You can also zoom in (+) and out (-) of the layout by pressing the zoom buttons. (These options are also available in the Controls menu).

The "Time Layout" graph

The Time Layout report shows how memory blocks are allocated across the run of the program. As each block is allocated, it is added to the end of the display. As blocks are freed, they are marked green. (See Figure 7.)

Inuse

Figure 7. The "Time Layout" screen

From this display, you can watch how memory is allocated over the run of your program. As you see the patterns, in which memory blocks are allocated and freed over time, you can better optimize your program's use of memory. Memory leaks are also shown on this display.

You can scan through the run by pressing the Fast Left (Fleft), Fast Right (Fright) and left and right buttons on the Time Layout toolbar. You can also zoom in (+) and out (-) of the layout by pressing the zoom buttons. (These options are also available in the Controls menu.)

The "Usage Summary" report

The "usage summary" report will show you how much memory you are using and how often calls have been made to each category of memory allocation functions malloc, realloc, and free. Note that the malloc category includes all functions which allocate dynamic memory, for example calloc, memalign, and XtMalloc. Similarly, the realloc category includes all functions which relocate or resize dynamic memory blocks. The free category includes all functions which free dynamic memory. You can calculate the number of blocks currently allocated by subtracting the number of frees from the number of malloc's. A typical "usage summary" graph might look like the following one in Figure 8.

Heap

Figure 8. A "usage summary" graph

The number given by "Alloc" is the total number of bytes allocated dynamically by your program. The number given by "Heap" is the total number of bytes currently allocated by the system to your program's heap.

The number given with "Number of calls" and "Memory in bytes" is simply the extreme value on the x-axis for each graph. The limit of each graph will change as Inuse updates the display with more memory allocation function calls.

Query Reports

Query is a powerful tool that makes it easier for you to understand how memory is being used by your program. With Query, you can find out exactly how much memory is being allocated to blocks of a particular size or location; how much memory is being allocated from a particular path; find out the stack traces of blocks of a particular size or location; and much, much more.

By creating queries, you will be creating a "model" of your program's memory use. You will be able to "look" at it from different angles and approaches, learning more and more with each successive report. As you come to understand how and where your program uses memory, you will be able to better optimize you program's memory use.

For example, if the Block Frequency report shows that your program is using many small allocations (creating a lot of memory overhead), you may to know exactly how much memory is being allocated to these small blocks. You will also want to know which part of the code is responsible for creating them.

To find out how your program is distributing memory across block sizes, you can run a query that shows how much memory is being allocated to each size block.

If you find that your program is distributing memory across block sizes, you can then run a query that gives you the block ids and stack traces responsible for creating these small blocks.

Armed with this information, you will be able to make simple adjustments to your code that will result in a more effective use of memory.

You can run queries on any combination of block id, block size, and stack trace. These queries can be flexible or as restrictive as you choose, as you set the parameters (see "Editing a Query").

Running queries does not affect your program or its operation. By running different queries and trying different approaches, you will soon see how valuable and informative these reports can be.

Heap

Figure 9. The Query Manager screen

Pressing Query opens the Query Manager screen. From here you can:

  • Press New to start a new query.

  • Press Load to open a saved query.

  • Press Delete to delete the current query.

  • Press Save to save the current query for later use.

  • Press Eval to evaluate the current query.

When you open a query, its name will appear in the Query Manager window. If you pressed New, the query will be named NoName.

Editing a Query

Pressing the Edit button on the Query Manager screen will let you edit the currently selected query.

Heap

Figure 10. The Query Editor

The Query Editor window lets you:

  • Change the name of a query.

  • Set the lower and upper ranges for the block ids you want to isolate.

  • Set the lower and upper ranges for the block sizes you want to isolate.

  • Enter an expression to isolate certain stack traces.

  • Choose whether to receive a complete report (including block id, block size, and stack trace data) or just a summary of block size and/or stack trace information.

The default values for a query are 0 for the lower and upper block id and block size ranges and no expressions in the stack trace area. This will produce the widest query, listing all memory blocks allocated by your program.

You can filter a query to isolate particular block ids, block sizes, and/or stack traces. Just enter the values you want to filter for and "check" the Filter by box.

The Sum by option provides a useful summary of block size and stack trace data. Use it in combination with the Filter by option or on its own to get a breakdown of blocks by size and/or stack trace.

For example, let's say you want to learn more about blocks that are between 60 and 70 bytes in size. In the Block Size Filter by box and press OK. Running this query will return block ids and stack traces for all blocks allocated by your program that are sized between 60 and 70 bytes.

Checking the Block Size Sum by box for this query will return a list showing how much memory (in bytes) is being allocated to each block size in that range.

You can enter filters for any or all three areas in a single query. This can help you find out the exact stack trace(s) responsible for the largest block allocations by your program, for example, or conversely, to find our the size and location of memory allocated from a particular stack trace path.

Once you have edited your query, pressing OK returns you to the Query Manager.

To run the query, press the Eval button or select Evaluate Query from the Commands menu. Query results will appear in a Memory Information window.

Heap

Figure 11. Query Results

Additional Features

Selective animation

By default, Inuse will animate every dynamic memory action that is made by your program. This has the advantage that the data displayed reflects the true situation inside your program's memory, but the disadvantage of hiding low level detail.

If you are only interested in a portion of your application, you can make some simple, unobtrusive changes to the original source code so that the animation shows only those data blocks which are active within a particular memory range.

When you compile programs with the insure command, the pre-processor symbol __INSURE__ is automatically defined. This allows you to conditionally insert calls to the function which controls the animation process:

    void _Inuse_display_values(int status);

Suppose, for example, that you are only interested in events occurring during the execution of a hypothetical function malloc_a_lot. To restrict data collection to this function, you need to add the following lines to the beginning of your program (i.e. at the top of main):

	#ifdef __INSURE__
		_Inuse_display_values(0);
	#endif

When your program begins, the animation is normally turned on - this call will turn it off. We next modify malloc_a_lot to turn the animation back on for the duration of the function. To do this, we modify the function malloc_a_lot from

    malloc_a_lot() {
          ... code ...
    }

to

    malloc_a_lot() {
    #ifdef __INSURE__
          _Inuse_display_values(1);
    #endif
          ... code ...
    #ifdef __INSURE__
          _Inuse_display_values(0);
    #endif
    }

Now when you compile and run your program, it will only display data between the calls to _Inuse_display_values.

It's worth noting that you can call this routine from a debugger to control the profiling without recompiling your code at all.

An additional option is turning just the Inuse GUI on and off at will during the execution of your program, which allows more flexibility in exploiting Inuse's power without sacrificing speed.

You can now turn the GUI on and off using the command:

    _Inuse_enable(boolean)

Calling _Inuse_enable with true (1) turns the GUI on, while calling with false (0) turns the GUI off.

This feature allows you to avoid waiting for many thousands of mallocs during the initialization of your code, and then still be able to turn Inuse on without halting the program's execution or losing information.

To make use of this feature, you cannot have the inuse on option set in your .psrc file. With that option set, Inuse will automatically start working when you execute your program.

Bend This option is only available if you are using the Insure++ version of malloc. If you are using Insure++ to monitor your own malloc (as explained in the Insure++ Users Guide and in the next section), this command will not be available.

Working with your own memory allocator

Internally, there are two important components to the way that Inuse operates

  • The graphical user interface.
  • A version of the memory allocation functions which transmits data to the user interface.

Communication between the two pieces is achieved with standard UNIX sockets using a protocol defined by Inuse. If you have your own memory allocation scheme, you can still use Inuse by adding calls to your code which send their results to the user interface.

For example, if you have a routine which performs a similar function to the regular malloc system call, you can add to it a call to the following function:

    _Inuse_malloc(void *ptr, size_t length);

which causes the display system to indicate an allocated block of the indicated size, at the address given.

A full list of the available functions and their usage is given in the manual page which can be found on-line as well as in this manual (Manual Pages).

Bend If you are instrumenting your own memory allocation scheme, be sure to disable the default by having the option "malloc_replace off" in your .psrc file when you link your program.

Working with the "native" memory allocator

By default, programs which use Inuse make calls to a special library which contains implementations of various memory allocation functions, such as malloc, realloc, calloc, and free. As a result, the data that you see displayed in the user interface does not match exactly the behavior of the native runtime system on the target machine, but it is representative of the true behavior.

An alternative approach is to have your own application call different functions which

  • call the genuine memory allocation routines on your system, and
  • send the results to the user interface for display.

To achieve this, use the following steps:

  • Include the lines

    	#define malloc _Insure_wrap_malloc
    	#define realloc _Insure_wrap_realloc
    	#define free _Insure_wrap_free
    	#define calloc _Insure_wrap_calloc
    	#define cfree _Insure_wrap_free
    
    at the top of every source file that calls one of the memory allocation functions. You may want to add these five lines to a header file that can be included in your sources file.
  • Recompile your source code.
  • Place the command "malloc_replace off" in your .psrc file.
  • Link the executable with the insure command.

This process will create an executable which uses the normal memory allocation package, but which also includes calls to display the results in Inuse's graphical user interface.

Bend Note that this process will only track calls to memory allocation routines that occur in user code which contains the five #define lines given above. It will not track calls made in system or 3rd party libraries which have not been recompiled.


Tools to debug c++ and java
(888) 305-0041 info@parasoft.com Copyright © 1996-2001 ParaSoft