Use graphviz visualized function call

Source: Internet
Author: User

Original article link

Applications can be viewed in graphicsProgramAs a learning experience. This helps you understand the internal behavior of an application and obtain information about program optimization. For example, by optimizing frequently called functions, you can achieve optimal performance with minimal effort. In addition, call tracking can also determine the maximum call depth of user functions, which can be used to effectively limit the memory used by the call stack (in an embedded system, this is a very important factor ).

To capture and display call graphs, you need four elements: GNU Compiler tool chain, addr2line tool, and custom intermediateCodeAnd a code named graphviz. The addr2line tool can recognize functions and addressSource codeNumber of lines and executable images. The custom intermediate code is a very simple tool that reduces the number of URL tracking for graphic specifications. The graphviz tool can generate a graphical image. The entire process 1 is shown.

Figure 1. process of collecting, simplifying, and visualizing tracing paths
 

Data collection: capture the function call path

To collect traces of a function call, you need to determine the time each function is called in the application. In the past, a unique symbol was inserted at the function entrance and exit to manually detect each function. This process is very cumbersome and error-prone, and usually requires a lot of modifications to the source code.

Fortunately, the GNU Compiler tool chain (also knownGcc) Provides a method to automatically detect various functions in an application. When you execute an application, you can collect relevant analysis data. You only need to provide two special analysis functions. One function is called every time you execute the function you want to trace. The other function is called every time you exit the function you want to trace (see Listing 1 ). These two functions are specially designated, so the compiler can recognize them.


Listing 1. GNU Entry and Exit configuration functions

Void _ cyg_profile_func_enter (void * func_address, void * call_site) _ attribute _ (no_instrument_function); void _ cyg_profile_func_exit (void * func_address, void * call_site) _ attribute _ (no_instrument_function ));

 

Avoid using special Detection Functions

You may wonder why GCC is not tested if it is the detection function we need._ Cyg _*What about analysis functions? GCC developers once thought about this issue and providedNo_instrument_functionFunction attribute, which can be applied to the function prototype and cannot be checked. Do not apply this function attribute to the analysis function, which will lead to infinite recursive analysis loops and a large amount of useless data.

When calling a detection function,_ Cyg_profile_func_enterIt will also be called andFunc_addressThe address of the called function andCall_siteFormat address. When a function exits_ Cyg_profile_func_exitFunction, and passFunc_addressFunction address and the real address from which the function exits.Call_site.

In these analysis functions, you can record the address pairs for later analysis. To request all GCC Detection Functions, each file must use-Finstrument-FunctionsAnd-GTo retain the debugging symbols.

Therefore, you can now provide some analysis functions for GCC. These functions can transparently insert function entry points and function exit points in the application. But how should we handle the provided address when calling the analysis function? You have many options, but for the sake of simplicity, you can simply write this address into a file. Note which address is the function entry address, which address is the exit address of the function (see list 2 ).

Note:In Listing 2, call callsite information is not used, because this information is unnecessary for the analysis program.


List 2. analysis functions

Void _ cyg_profile_func_enter (void * This, void * callsite) {/* function entry address */fprintf (FP, "E % P \ n", (int *) this);} void _ cyg_profile_func_exit (void * This, void * callsite) {/* function exit address */fprintf (FP, "x % P \ n ", (int *) This );}

 

Now you can collect and analyze data, But where should you open or close your tracking output file? Up to now, you do not need to make any modifications to the source program for analysis. Therefore, how do you detect the entire application (includingMainFunction) instead of initializing the output results of the analysis data? GCC developers have also considered this issue.MainThe constructor and destructor functions of the function provide some methods that happen to meet this requirement.ConstructorThe function is called.MainCalled before the function, andDestructorThe function is called when the application exits.

To create the constructor and destructor functions, you must declare two functions and apply them to them.ConstructorAndDestructorFunction attribute. InConstructorIn the function, a new tracking file is opened, and the address tracking of the analysis data is written to this file;DestructorFunction, the trace file is closed (see listing 3 ).


Listing 3. Analyze the constructor and destructor Functions

/* Constructor and destructor prototypes */void main_constructor (void) _ attribute _ (no_instrument_function, constructor); void evaluate (void) _ attribute _ (no_instrument_function, destructor);/* output trace file pointer */static file * FP; void main_constructor (void) {fp = fopen ("trace.txt", "W "); if (FP = NULL) Exit (-1);} void main_deconstructor (void) {fclose (FP );}

 

If you compile an analysis function (in instrument. c) and link them with the target application, and then execute the target application. The result will generate an application call tracing, and the tracing record will be written.Trace.txtFile. The trace file is in the same directory as the called application. The final result is that you may get a file with a very large address. To make the data more meaningful, you can use a less famous GNU tool called addr2line.

Back to Top

Use addr2line to resolve the function address to the function name

The addr2line tool (which is part of the standard GNU binutils) is a tool that converts the instruction address and executable image into a file name, function name, and number of lines of source code. This feature is great for converting tracking addresses into more meaningful content.

To understand how this process works, we can test a simple interactive example. (I operate directly from shell, because this is the easiest way to demonstrate this process, as shown in Listing 4 .) In this example, the C file (test. c) usesCatImplemented by a simple application (that is, the standard output text is redirected to a file ). Then use GCC to compile the file. It will pass some special options. First, you must-WlOption) notifies the linker to generate an image file and-GOption) notifies the compiler to generate debugging symbols. Generate an executable fileTest. After obtaining a new executable application, you can useGrepFind the tool in the Image FileMainTo find its address. Use this address and the addr2line tool to determine the function name (Main), The source file (/home/mtj/test. C), and its row number in the source file (4 ).

Use the addr2line Tool-EOption to specify whether the executable image isTest. Use-FIndicates the name of the output function.


Listing 4. An interactive example of addr2line

$ Cat> test. C # include <stdio. h> int main () {printf ("Hello world \ n"); Return 0 ;}< ctld-D> $Gcc-wl,-map = test. Map-g-o Test test. c$ Grep main test. map0x08048258 _ libc_start_main @ glibc_2.00x08048258main $Addr2line 0x08048258-E test-FMain/home/mtj/test. C: 4 $

 

Addr2line and debugger

The addr2line tool provides basic symbolic debugging information, but GNU Debugger (GDB) uses other internal methods.

Back to Top

Streamlined function tracking data

Now you have a method to collect tracing data for the function address. You can also use the addr2line tool to convert the address to the function name. However, how can we streamline a large amount of tracing data from an application to make it more meaningful? This is where custom intermediate code is used to establish a connection between open-source tools. This article provides the complete annotated code of this tool (pvtrace), including instructions on how to compile and use this tool. (For more information, see the download section .)

Recall the content in step 1 and create an application namedTrace.txt. The files that people can read contain a series of address information-one address per line and one prefix character per line. If the prefix isE, Then this address is the entry address of a function (that is, you are calling this function ). If the prefix isXThen this address is an exit address (that is, you are exiting from this function ).

Therefore, if there is an entry address (A) in the tracking file followed by another entry address (B), you can infer that a calls B. If an entry address (a) is followed by an exit address (a), it indicates that this function (a) is directly returned after being called. When a large number of call chains are involved, it is difficult to analyze who calls them. Therefore, a simple solution is to maintain a stack of the entire address. Every time a tracking file encounters an entry address, it is pushed into the stack. The address at the top of the stack represents the last called function (that is, the current active function ). If another entry address is followed, the address in the stack calls the address that was just read from the tracking file. When the function exits, the current active function returns and releases the top element of the stack. This will return the context back to the previous function, so that a correct call chain process can be generated.

Figure 2 describes this concept and how to streamline data. When analyzing the call chain in the trace file, a connection matrix is built to indicate which function calls other functions. The rows in this matrix represent the address of the called function, and the columns represent the called address. For each call pair, the intersection of rows and columns is accumulated continuously (number of calls ). When processing a complete trace file, the result is a very simple representation of the entire call history of the application, including the number of calls.


Figure 2. Process and streamline the tracking data and generate a matrix format
 

Compile and install tools

After downloading and decompressing the pvtrace tool, you only need to enterMakeCommand to compile the pvtrace tool. You can also use the following code to install the tool to the/usr/local/bin directory:

$ Unzip pvtrace.zip-D pvtrace

$ CD pvtrace

$ Make

$ Make install

Now we have built a simplified function connectivity matrix. Next we should build a graphical representation. Let's take a deeper look at graphviz and understand how to generate a call chart from the connection matrix.

Back to Top

Use graphviz

Graphviz or graph visualization is an open-source graphical visualization tool developed by at&t. It provides a variety of drawing capabilities, but our focus is on its ability to directly connect to images using the dot language. In this article, we will briefly introduce how to use dot to create a graph and demonstrate how to convert the analysis data to a specification that graphviz can use. (For more information about downloading this open-source software, see references .)

Dot graphics specifications

Using the dot language, you can specify three objects: graphs, nodes, and edges. To help you understand the meaning of these objects, we will build an example to demonstrate the usage of these elements.

Listing 5 shows a simple directed graph with three nodes. The first line declares this imageGAnd declare the graph type (digraph ). The following three lines of code are used to create nodes for the graph.Node1,Node2AndNode3. Nodes are created when their names appear in the graph specification. Edges are operated by edges on two nodes (->) Created when the connection is made, as shown in rows 6th to 8th. I also used an optional attribute on the edge.LabelTo indicate the name of an edge in the graph. Finally, define the graph specification in Row 3.


Listing 5. Example graph represented by the dot symbol (test. Dot)

1: digraph G {2: node1; 3: node2; 4: node3; 5: 6: node1-> node2 [label = "edge_1_2"]; 7: node1-> node3 [label = "edge_1_3"]; 8: node2-> node3 [label = "edge_2_3"]; 9 :}

 

To convert the. Dot file into a graphical image, you need to use the dot tool, which is provided in the graphviz package. Listing 6 describes the conversion.


Listing 6. Use dot to create a jpg image

$ Dot-tjpg test. Dot-O test.jpg $

 

In this Code, I told Dot to use the test. Dot graphic specification, generate a jpg image, and save it in the test.jpg file. The generated image 3 is shown. Here, I use JPG, but the dot tool also supports other formats, including GIF, PNG, And postscript.


Figure 3. Example of dot Creation
 

The dot language also supports other options, including shape, color, and many attributes. However, this option is sufficient for the functions we want to implement.

Back to Top

Comprehensive

Now we have seen all stages of the process. The following example shows how to merge these stages. Now you have expanded and installed the pvtrace tool, and copied the instrument. c file to the working source code directory.

In this example, a source file is used.Test. c. Listing 7 shows the entire process. In row 3, I used the detection source (instrument. c) to build (compile and connect) applications. Then executeTest, And then useLsCommand to verify that the trace.txt file has been generated. In row 8th, I called the pvtrace tool and provided this image file as its only parameter. The image name is required, so that addr2line (called in pvtrace) can access debugging information in this image. In row 9th, I executed anotherLsCommand to ensure that the pvtrace generates the graph. Dot file. Finally, in Row 3, use dot to convert the image specification into a jpg image.


Listing 7. The entire process of creating a call trace Graph

1: $ ls 2: instrument. C test. C 3: $$ Gcc-g-finstrument-Functions Test. c instrument. C-o Test4: $./Test 5: $ ls 6: instrument. C test. C 7: Test trace.txt 8: $Pvtrace Test9: $ ls10: Graph. Dot test trace.txt 11: instrument. C test. C12: $Dot-tjpg graph. Dot-O graph.jpg13: $ ls14: Graph. Dot instrument. C test. C15: graph.jpg test trace.txt 16: $

 

Sample output 4 of this process is shown in. This example is obtained from a simple enhanced learning application using Q.


Figure 4. tracing results of the sample application
 

You can also use this method to analyze larger applications. The last example I want to show is the gzip tool. I simply add instrument. C to the makefile of gzip as a source file on which it depends, compile gzip, and use it to generate a trace file. This image is too big to perform more detailed analysis, but it indicates the processing process when gzip compresses a small file.


Figure 5. gzip tracking result
 

Back to Top

Conclusion

With open-source software and a small amount of intermediate code, it takes very little time to develop very useful projects. By using several GNU Compiler extensions that analyze applications, you can use the addr2line tool to perform address translation and visualize graphviz applications. Then you can get a program, this program can analyze the application and display a directed graph indicating the call chain. It is very important to understand the internal behavior of an application to view the call chain of an application through graphs. After correctly understanding the call chain and its frequency, this knowledge may be useful for debugging and optimizing applications.

 

Back to Top

Download

Description Name Size Download Method
Instrumentation source and pvtrace Source Pvtrace.zip 4 kb HTTP

Information about the Download Method

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.