Page History
As part of work funded by OpenSFS, a plugin for Clang has been developed. This plugin , together with gcov, can be used to identify code in the Lustre source tree that is never called. In addition, these tools can be used to more generally illuminate code usage. For example, hot and cold areas of data and functions, structures that are read and never written, and unused variables can also be identified. The purpose of this document is to enable a developer to begin working with these tools.
...
Building Lustre for static analysis
- Build a Lustre patched kernel with ggov enabledGCC. This document assumes a Lustre patched kernel version: 2.6.32-279.19.1.el6_lustre_gcov.x86_64.
To enable gcov set
CONFIG_GCOV_KERNEL=y
. It is not necessary to setCONFIG_GCOV_PROFILE_ALL
. With the first option set, profiling can be enable on a per-module basis during the Lustre build. Build the kernel as usual (i.e. using GCC). Trying to build it with Clang is unlikely to succeed.- Build SPL and ZFS if necessary.
Build Lustre software using a script included in lustre-static-analysis for assistance:
Code Block language none # cd lustre-release # git clean -fxd # sh autogen.sh && ./configure # ~/lustre-static-analysis/DeclUse/decl_use_make GCOV_PROFILE=y
For each
.c
to.o
compilation performed by GCC,decl_use_make
will also run Clang with the lustre-static-analysis plugin. When compilingfile.c
the outputfile.o
is produced by GCC and should be identical to a normal Lustre build. Simultaneouslydecl_use_make
instructs Clang to read file.c and produce correspondingfile.o._Ref
andfile.o._Err
. Note: Clang does not compile file.c to an object file. Clang parses file.c and produces an AST in memory. Thefile.o._Err
file records the errors Clang discovered during processingfile.c
.Info In practice,
file.o
is first build as.tmp_file.o
then renamed tofile.o
. This happens in the Makefile so GCC and Clang are unaware of thefile.o
.
Useful products from Clang static analysis produced by decl_use_make
For the purposes of static analysis provided by the Clang plugin, the file.o._Ref
are intermediate file and not of general interest. THe The files of interest include:
Err
GetOnly
MacroUnused
SetOnly
Undefined
Automatic processing of analysis output
Executing the script useage-post.sh
will create a directory called Unused-2.4.50
(or more generally: Unused-$(git describe)
)
The file Ref
is the sorted and uniqed concatenation of the ._Ref files produced by usage-make.sh
. The remaining files are produced by filtering and comparing various parts of Ref. For example, there are the unused declarations in lustre/llite
:
Code Block |
---|
# grep /llite/ DeclUse-2.4.50/Unused
EnumConstant lustre/llite/llite_internal.h:121:9:LLIF_CONTENDED
EnumConstant lustre/llite/llite_internal.h:123:9:LLIF_SRVLOCK
EnumConstant lustre/llite/llite_internal.h:379:9:STATS_TRACK_LAST
Field lustre/llite/llite_internal.h:1020:8:vvp_thread_info:vti_lvb
Field lustre/llite/llite_internal.h:1020:8:vvp_thread_info:vti_queue
Field lustre/llite/llite_internal.h:1078:8:ll_lock_tree:lt_fd
Field lustre/llite/llite_internal.h:1078:8:ll_lock_tree:lt_locked_list
Field lustre/llite/llite_internal.h:1078:8:ll_lock_tree:lt_root
Field lustre/llite/llite_internal.h:1611:8:if_quotactl_18:obd_type
Field lustre/llite/llite_internal.h:638:8:it_cb_data:hash
Field lustre/llite/llite_internal.h:71:8:ll_dentry_data:lld_cwd_och
Field lustre/llite/llite_internal.h:71:8:ll_dentry_data:lld_mnt_och
Field lustre/llite/llite_internal.h:920:8:vvp_io:cui_partpage
Function lustre/llite/llite_internal.h:1086:28:ll_node_from_inode
Function lustre/llite/llite_internal.h:1154:19:ll_mds_max_easize
Function lustre/llite/llite_internal.h:1216:5:ll_is_file_contended
Function lustre/llite/llite_internal.h:663:20:ll_ra_read_get
Function lustre/llite/llite_internal.h:713:6:ll_removepage
Function lustre/llite/llite_internal.h:716:5:ll_file_punch
Function lustre/llite/llite_internal.h:717:9:ll_file_lockless_io
Function lustre/llite/llite_internal.h:718:6:ll_clear_file_contended
Function lustre/llite/llite_internal.h:719:5:ll_sync_page_range
Function lustre/llite/llite_internal.h:830:7:ll_read_opt
Function lustre/llite/llite_internal.h:836:15:ll_inode_from_lock
Function lustre/llite/llite_internal.h:864:6:lustre_dump_inode
Function lustre/llite/llite_lib.c:1085:6:lu_context_keys_dump
Function lustre/llite/llite_mmap.c:577:29:file_to_user
Function lustre/llite/llite_mmap.c:58:14:ll_nopage
Function lustre/llite/lloop.c:901:1:__inittest
Function lustre/llite/lloop.c:902:1:__exittest
Function lustre/llite/lloop.c:904:1:__check_max_loop
Function lustre/llite/namei.c:78:5:ll_unlock
Function lustre/llite/super25.c:232:1:__inittest
Function lustre/llite/super25.c:233:1:__exittest
Function lustre/llite/vvp_dev.c:172:5:vvp_global_init
Function lustre/llite/vvp_dev.c:185:6:vvp_global_fini
Record lustre/llite/llite_internal.h:1078:8:ll_lock_tree
Typedef lustre/llite/llite_internal.h:1075:25:rb_node_t
Var lustre/llite/llite_internal.h:658:25:ll_async_page_slab
Var lustre/llite/llite_internal.h:659:15:ll_async_page_slab_size
Var lustre/llite/llite_internal.h:84:31:ll_pgcache_seq_fops
Var lustre/llite/llite_internal.h:884:31:ll_special_chr_inode_fops
Var lustre/llite/llite_internal.h:885:31:ll_special_chr_file_fops
Var lustre/llite/llite_internal.h:886:31:ll_special_blk_inode_fops
Var lustre/llite/llite_internal.h:887:31:ll_special_fifo_inode_fops
Var lustre/llite/llite_internal.h:888:31:ll_special_fifo_file_fops
Var lustre/llite/llite_internal.h:889:31:ll_special_sock_inode_fops
Var lustre/llite/rw26.c:559:33:ll_aops
Var lustre/llite/vvp_dev.c:544:24:vvp_dump_pgcache_file_ops |
Info | ||
---|---|---|
| ||
Some of the variables listed above maybe recognised as in use. It is important to note that this is a list of variable declaration usage. The |
Profiling
In order to perform profiling, Lustre must be up and running. Once Lustre is mounted, a suitable workload must be performed to drive the profiling tools. For example, a general work-load might-be:
Info |
---|
# TESTS= "sanity sanityn sanity-benchmark metadata-updates racer lnet-selftest replay-single conf-sanity recovery-small replay-ost-single replay-dual replay-vbr insanity sanity-quota sanity-sec sanity-gss lustre-rsync-test ost-pools mmp obdfilter-survey sgpdd-survey sanity-scrub lfsck sanity-hsm" # export FSTYPE=ldiskfs # export MDSCOUNT= 2 # for test in $TESTS; do sh ./lustre/tests/$test.sh; done ... # export FSTYPE=zfs # export MDSCOUNT= 2 # for test in $TESTS; do sh ./lustre/tests/$test.sh; done ... # export SAHRED_DIRECTORY=/tmp/will- this -work # export MDSCOUNT= 1 # sh ./lustre/tests/lfsck.sh # ... |
To collect the profiling data first mount debugfs
then run gcov-collect
. GCOV helper scripts to be linked when available. Example output is:
Info |
---|
# mount -t debugfs none /sys/kernel/debug # ls -l /sys/kernel/debug/gcov/root/lustre-release/lustre/llite -rw------- 1 root root 0 May 17 13 : 54 dcache.gcda lrwxrwxrwx 1 root root 0 May 17 13 : 54 dcache.gcno -> /root/lustre-release/lustre/llite/.tmp_dcache.gcno -rw------- 1 root root 0 May 17 13 : 54 dir.gcda lrwxrwxrwx 1 root root 0 May 17 13 : 54 dir.gcno -> /root/lustre-release/lustre/llite/.tmp_dir.gcno -rw------- 1 root root 0 May 17 13 : 54 file.gcda lrwxrwxrwx 1 root root 0 May 17 13 : 54 file.gcno -> /root/lustre-release/lustre/llite/.tmp_file.gcno -rw------- 1 root root 0 May 17 13 : 54 llite_capa.gcda lrwxrwxrwx 1 root root 0 May 17 13 : 54 llite_capa.gcno -> /root/lustre-release/lustre/llite/.tmp_llite_capa.gcno -rw------- 1 root root 0 May 17 13 : 54 llite_close.gcda ... # mkdir /tmp/gcov- 2.4 . 50 # gcov-collect /tmp/gcov- 2.4 . 50 # ls -lh /tmp/gcov- 2.4 . 50 /root/lustre-release/lustre/llite/file.c.gcov -rw------- 1 root root 164K May 16 21 : 15 /tmp/gcov- 2.4 . 50 /root/lustre-release/lustre/llite/file.c.gcov # cat /tmp/gcov- 2.4 . 50 /root/lustre-release/lustre/llite/file.c.gcov -: 0 :Source:/root/lustre-release/lustre/llite/file.c -: 0 :Graph:/sys/kernel/debug/gcov/root/lustre-release/lustre/llite/file.gcno -: 0 :Data:/sys/kernel/debug/gcov/root/lustre-release/lustre/llite/file.gcda -: 0 :Runs: 0 -: 0 :Programs: 0 ... 588675 : 1062 : static ssize_t ll_file_read(struct file *file, char *buf, size_t count, -: 1063 : loff_t *ppos) -: 1064 :{ -: 1065 : struct lu_env *env; -: 1066 : struct iovec *local_iov; -: 1067 : struct kiocb *kiocb; -: 1068 : ssize_t result; -: 1069 : int refcheck; 588675 : 1070 : ENTRY; -: 1071 : 588675 : 1072 : env = cl_env_get(&refcheck); 588734 : 1073 : if (IS_ERR(env)) #####: 1074 : RETURN(PTR_ERR(env)); -: 1075 : 588734 : 1076 : local_iov = &vvp_env_info(env)->vti_local_iov; 588740 : 1077 : kiocb = &vvp_env_info(env)->vti_kiocb; 588740 : 1078 : local_iov->iov_base = ( void __user *)buf; 588740 : 1079 : local_iov->iov_len = count; 1177480 : 1080 : init_sync_kiocb(kiocb, file); 588740 : 1081 : kiocb->ki_pos = *ppos; 588740 : 1082 : kiocb->ki_left = count; -: 1083 : 588740 : 1084 : result = ll_file_aio_read(kiocb, local_iov, 1 , kiocb->ki_pos); 588716 : 1085 : *ppos = kiocb->ki_pos; -: 1086 : 588716 : 1087 : cl_env_put(env, &refcheck); 588741 : 1088 : RETURN(result); -: 1089 :} ... |
The output from gcov reads as follows
Column 1 | Column 2 | Column3 |
---|---|---|
A count of times the line was executed. '-' means no code was generated. '#####' means count=0. | The number of the line of interest in the source file. | The line of interest. |
The output from this profiling phase can be used to prune the ._Ref
data to provide an enhanced usage picture. To do this, we eliminate references form dead lines ('#####
').
Code Block |
---|
# export LC_ALL=C# cd Unused-2.4.50# gcov-filter.py /tmp/gcov-2.4.50 Ref > LiveRef# awk '$1 == "Use" && $2 != "Macro" { print $2, $3; }' LiveRef | sort | uniq > LiveUse# comm -23 Decl LiveUse > Dead# wc -l Dead3277 Dead## comm -23 Dead Unused | grep /llite/Field lustre/llite/llite_internal.h:992:9:-:sendfileField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_access_permField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_fsgidField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_fsuidField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_gidField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_listField lustre/llite/llite_internal.h:99:8:ll_remote_perm:lrp_uidField lustre/llite/llite_nfs.c:118:8:lustre_nfs_fid:lnf_childField lustre/llite/llite_nfs.c:118:8:lustre_nfs_fid:lnf_parentFunction lustre/llite/dir.c:919:12:ll_ioc_copy_startFunction lustre/llite/dir.c:992:12:ll_ioc_copy_endFunction lustre/llite/file.c:1261:12:ll_lov_recreateFunction lustre/llite/file.c:1307:12:ll_lov_recreate_objFunction lustre/llite/file.c:1325:12:ll_lov_recreate_fidFunction lustre/llite/file.c:1523:12:ll_lov_getstripeFunction lustre/llite/file.c:1760:12:ll_ioctl_fiemap...Record lustre/llite/llite_nfs.c:118:8:lustre_nfs_fidVar lustre/llite/llite_capa.c:67:27:ll_capa_renewedVar lustre/llite/llite_capa.c:68:27:ll_capa_renewal_noentVar lustre/llite/llite_capa.c:69:27:ll_capa_renewal_failedVar lustre/llite/llite_capa.c:70:27:ll_capa_renewal_retriesVar lustre/llite/llite_internal.h:725:31:ll_file_operations |
._Err output file
Explain _Err file.
Code Block |
---|
Err Function /root/lustre-release/lustre/fid/fid_request.c:155:5:seq_client_alloc_super first declared without linkage in c file
Err Function /root/lustre-release/lustre/fid/fid_store.c:69:6:seq_update_cb first declared without linkage in c file
Err Function /root/lustre-release/lustre/fid/fid_store.c:82:5:seq_update_cb_add first declared without linkage in c file
Err Function /root/lustre-release/lustre/fld/fld_request.c:420:5:fld_client_rpc first declared without linkage in c file
Err Function /root/lustre-release/lustre/include/lclient.h:388:17:ccc_vmpage_page_transient was already declared
Err Function /root/lustre-release/lustre/include/liblustre.h:165:6:cfs_get_random_bytes was already declared
Err Function /root/lustre-release/lustre/include/lu_target.h:308:5:tgt_hpreq_handler was already declared
Err Function /root/lustre-release/lustre/include/lustre_dlm.h:1414:5:ldlm_handle_enqueue0 was already declared
Err Function /root/lustre-release/lustre/include/lustre_mdc.h:200:5:it_disposition was already declared
Err Function /root/lustre-release/lustre/include/lustre_mdc.h:201:6:it_clear_disposition was already declared
Err Function /root/lustre-release/lustre/include/lustre_mdc.h:202:6:it_set_disposition was already declared
Err Function /root/lustre-release/lustre/include/obd_class.h:1927:5:class_add_uuid was already declared
Err Function /root/lustre-release/lustre/include/obd_class.h:87:20:class_conn2export was already declared
Err Function /root/lustre-release/lustre/ldlm/ldlm_flock.c:72:5:ldlm_flock_blocking_ast first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_internal.h:163:5:ldlm_lock_remove_from_lru was already declared
Err Function /root/lustre-release/lustre/ldlm/ldlm_internal.h:244:5:ldlm_init was already declared
Err Function /root/lustre-release/lustre/ldlm/ldlm_lib.c:2129:6:target_recovery_fini first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lib.c:2150:6:target_recovery_init first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lib.c:2398:5:target_send_reply_msg first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lock.c:2214:5:ldlm_cancel_locks_for_export_cb first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lock.c:361:5:ldlm_lock_destroy_internal first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lock.c:711:6:ldlm_add_bl_work_item first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lock.c:732:6:ldlm_add_cp_work_item first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lockd.c:2420:5:ldlm_revoke_lock_cb first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_lockd.c:77:19:round_timeout first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_resource.c:318:6:ldlm_namespace_proc_unregister first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_resource.c:330:5:ldlm_namespace_proc_register first declared without linkage in c file
Err Function /root/lustre-release/lustre/ldlm/ldlm_resource.c:960:5:ldlm_namespace_get_return first declared without linkage in c file |
are contained in the directory DeclUse-2.5.60-40-g*/
. Useful file include:
File name | Description |
---|---|
Err | Errors reported by the Clang compiler. |
GetOnly | Structure members that are read somewhere but never set. |
MacroUnused | Macros that are never used. |
SetOnly | Structure members that are set somewhere but never read. |
Undefined | Variables that are never defined. |
Gotchas
- The static usage tracker is confused by disconnected declarations.
...