.\" Copyright (C) 2014 Michael Kerrisk .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .TH sprof 1 2023-03-30 "Linux man-pages 6.04" .SH NAME sprof \- read and display shared object profiling data .SH SYNOPSIS .nf .BR sprof " [\fIoption\fP]... \fIshared-object-path\fP \ [\fIprofile-data-path\fP]" .fi .SH DESCRIPTION The .B sprof command displays a profiling summary for the shared object (shared library) specified as its first command-line argument. The profiling summary is created using previously generated profiling data in the (optional) second command-line argument. If the profiling data pathname is omitted, then .B sprof will attempt to deduce it using the soname of the shared object, looking for a file with the name .I .profile in the current directory. .SH OPTIONS The following command-line options specify the profile output to be produced: .TP .BR \-c ", " \-\-call\-pairs Print a list of pairs of call paths for the interfaces exported by the shared object, along with the number of times each path is used. .TP .BR \-p ", " \-\-flat\-profile Generate a flat profile of all of the functions in the monitored object, with counts and ticks. .TP .BR \-q ", " \-\-graph Generate a call graph. .PP If none of the above options is specified, then the default behavior is to display a flat profile and a call graph. .PP The following additional command-line options are available: .TP .BR \-? ", " \-\-help Display a summary of command-line options and arguments and exit. .TP .B \-\-usage Display a short usage message and exit. .TP .BR \-V ", " \-\-version Display the program version and exit. .SH STANDARDS GNU. .SH EXAMPLES The following example demonstrates the use of .BR sprof . The example consists of a main program that calls two functions in a shared object. First, the code of the main program: .PP .in +4n .EX $ \fBcat prog.c\fP #include void x1(void); void x2(void); int main(int argc, char *argv[]) { x1(); x2(); exit(EXIT_SUCCESS); } .EE .in .PP The functions .IR x1 () and .IR x2 () are defined in the following source file that is used to construct the shared object: .PP .in +4n .EX $ \fBcat libdemo.c\fP #include void consumeCpu1(int lim) { for (unsigned int j = 0; j < lim; j++) getppid(); } void x1(void) { for (unsigned int j = 0; j < 100; j++) consumeCpu1(200000); } void consumeCpu2(int lim) { for (unsigned int j = 0; j < lim; j++) getppid(); } void x2(void) { for (unsigned int j = 0; j < 1000; j++) consumeCpu2(10000); } .EE .in .PP Now we construct the shared object with the real name .IR libdemo.so.1.0.1 , and the soname .IR libdemo.so.1 : .PP .in +4n .EX $ \fBcc \-g \-fPIC \-shared \-Wl,\-soname,libdemo.so.1 \e\fP \fB\-o libdemo.so.1.0.1 libdemo.c\fP .EE .in .PP Then we construct symbolic links for the library soname and the library linker name: .PP .in +4n .EX $ \fBln \-sf libdemo.so.1.0.1 libdemo.so.1\fP $ \fBln \-sf libdemo.so.1 libdemo.so\fP .EE .in .PP Next, we compile the main program, linking it against the shared object, and then list the dynamic dependencies of the program: .PP .in +4n .EX $ \fBcc \-g \-o prog prog.c \-L. \-ldemo\fP $ \fBldd prog\fP linux\-vdso.so.1 => (0x00007fff86d66000) libdemo.so.1 => not found libc.so.6 => /lib64/libc.so.6 (0x00007fd4dc138000) /lib64/ld\-linux\-x86\-64.so.2 (0x00007fd4dc51f000) .EE .in .PP In order to get profiling information for the shared object, we define the environment variable .B LD_PROFILE with the soname of the library: .PP .in +4n .EX $ \fBexport LD_PROFILE=libdemo.so.1\fP .EE .in .PP We then define the environment variable .B LD_PROFILE_OUTPUT with the pathname of the directory where profile output should be written, and create that directory if it does not exist already: .PP .in +4n .EX $ \fBexport LD_PROFILE_OUTPUT=$(pwd)/prof_data\fP $ \fBmkdir \-p $LD_PROFILE_OUTPUT\fP .EE .in .PP .B LD_PROFILE causes profiling output to be .I appended to the output file if it already exists, so we ensure that there is no preexisting profiling data: .PP .in +4n .EX $ \fBrm \-f $LD_PROFILE_OUTPUT/$LD_PROFILE.profile\fP .EE .in .PP We then run the program to produce the profiling output, which is written to a file in the directory specified in .BR LD_PROFILE_OUTPUT : .PP .in +4n .EX $ \fBLD_LIBRARY_PATH=. ./prog\fP $ \fBls prof_data\fP libdemo.so.1.profile .EE .in .PP We then use the .B sprof \-p option to generate a flat profile with counts and ticks: .PP .in +4n .EX $ \fBsprof \-p libdemo.so.1 $LD_PROFILE_OUTPUT/libdemo.so.1.profile\fP Flat profile: Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls us/call us/call name 60.00 0.06 0.06 100 600.00 consumeCpu1 40.00 0.10 0.04 1000 40.00 consumeCpu2 0.00 0.10 0.00 1 0.00 x1 0.00 0.10 0.00 1 0.00 x2 .EE .in .PP The .B sprof \-q option generates a call graph: .PP .in +4n .EX $ \fBsprof \-q libdemo.so.1 $LD_PROFILE_OUTPUT/libdemo.so.1.profile\fP index % time self children called name 0.00 0.00 100/100 x1 [1] [0] 100.0 0.00 0.00 100 consumeCpu1 [0] \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 0.00 0.00 1/1 [1] 0.0 0.00 0.00 1 x1 [1] 0.00 0.00 100/100 consumeCpu1 [0] \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 0.00 0.00 1000/1000 x2 [3] [2] 0.0 0.00 0.00 1000 consumeCpu2 [2] \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 0.00 0.00 1/1 [3] 0.0 0.00 0.00 1 x2 [3] 0.00 0.00 1000/1000 consumeCpu2 [2] \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .EE .in .PP Above and below, the "" strings represent identifiers that are outside of the profiled object (in this example, these are instances of .IR main() ). .PP The .B sprof \-c option generates a list of call pairs and the number of their occurrences: .PP .in +4n .EX $ \fBsprof \-c libdemo.so.1 $LD_PROFILE_OUTPUT/libdemo.so.1.profile\fP x1 1 x1 consumeCpu1 100 x2 1 x2 consumeCpu2 1000 .EE .in .SH SEE ALSO .BR gprof (1), .BR ldd (1), .BR ld.so (8)