aras-p / ClangBuildAnalyzer

Clang build analysis tool using -ftime-trace

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Same file is reported multiple times when relative paths are used

i-ky opened this issue · comments

commented

Here is the output I've got when analyzing one project:

*** Expensive headers:
4826 ms: ../../../include/common.h (included 82 times, avg 58 ms), included via:
  ...

1657 ms: ../../../../include/common.h (included 28 times, avg 59 ms), included via:
  ...

938 ms: ../../include/common.h (included 16 times, avg 58 ms), included via:
  ...

This is actually the same header and in the project it is always included via

#include "common.h"

Project folder structure looks like this:

├ include/
└ src/
  └ foo/
    └ bar/
      └ baz/

... with each directory having its own Makefile listing subdirectories and make is called recursively. Top-level make gets -Iinclude and down the line we get -I../include, -I../../include, etc.

I think ClangBuildAnalyzer should report either absolute paths to files or paths relative to its working directory combining paths from *.json files and relative locations of *.json files themselves. Path fragments like <some directory>/../ should be squashed.

I suspect the issue might be due to different working directories used during the build (due to recursive makefiles). But kinda hard to say. Would help if you could attach your .json files produced during the build.

commented

I suspect the issue might be due to different working directories used during the build (due to recursive makefiles).

Yes, I think this is exactly what happens.

Would help if you could attach your .json files produced during the build.

I've done some analysis. I hope the following one-liner illustrates the situation.

  • find -name '*.json' looks for JSON files,
  • dirname $file gets the directory where file is located,
  • jq --raw-output '.traceEvents[] | select(.args.detail | . and contains("/include/common.h")) | .args.detail' $file looks for inclusions of common.h in JSON,
  • echo .../... concatenates both paths,
  • sort and uniq remove duplicates.

So, here are locations of JSON files concatenated with relative path to common.h header(s) they include:

$ for file in $(find -name '*.json'); do echo `dirname $file`/`jq --raw-output '.traceEvents[] | select(.args.detail | . and contains("/include/common.h")) | .args.detail' $file`; done | sort | uniq
./src/libs/zbxalgo/../../../include/common.h
./src/libs/zbxcommon/../../../include/common.h
./src/libs/zbxcommshigh/../../../include/common.h
./src/libs/zbxcomms/../../../include/common.h
./src/libs/zbxcompress/../../../include/common.h
./src/libs/zbxconf/../../../include/common.h
./src/libs/zbxcrypto/../../../include/common.h
./src/libs/zbxdbcache/../../../include/common.h
./src/libs/zbxdbhigh/../../../include/common.h
./src/libs/zbxdb/../../../include/common.h
./src/libs/zbxdbupgrade/../../../include/common.h
./src/libs/zbxembed/
./src/libs/zbxembed/../../../include/common.h
./src/libs/zbxexec/../../../include/common.h
./src/libs/zbxhistory/../../../include/common.h
./src/libs/zbxhttp/../../../include/common.h
./src/libs/zbxicmpping/../../../include/common.h
./src/libs/zbxipcservice/../../../include/common.h
./src/libs/zbxjson/../../../include/common.h
./src/libs/zbxlog/../../../include/common.h
./src/libs/zbxmedia/../../../include/common.h
./src/libs/zbxmemory/../../../include/common.h
./src/libs/zbxmodules/../../../include/common.h
./src/libs/zbxnix/../../../include/common.h
./src/libs/zbxprometheus/../../../include/common.h
./src/libs/zbxregexp/../../../include/common.h
./src/libs/zbxself/../../../include/common.h
./src/libs/zbxserver/../../../include/common.h
./src/libs/zbxsys/../../../include/common.h
./src/libs/zbxsysinfo/agent/../../../../include/common.h
./src/libs/zbxsysinfo/common/../../../../include/common.h
./src/libs/zbxsysinfo/../../../include/common.h
./src/libs/zbxsysinfo/linux/../../../../include/common.h
./src/libs/zbxsysinfo/simple/../../../../include/common.h
./src/libs/zbxtasks/../../../include/common.h
./src/zabbix_agent/../../include/common.h
./src/zabbix_get/../../include/common.h
./src/zabbix_proxy/datasender/../../../include/common.h
./src/zabbix_proxy/heart/../../../include/common.h
./src/zabbix_proxy/housekeeper/../../../include/common.h
./src/zabbix_proxy/../../include/common.h
./src/zabbix_proxy/proxyconfig/../../../include/common.h
./src/zabbix_proxy/taskmanager/../../../include/common.h
./src/zabbix_sender/../../include/common.h
./src/zabbix_server/alerter/../../../include/common.h
./src/zabbix_server/dbconfig/../../../include/common.h
./src/zabbix_server/dbsyncer/../../../include/common.h
./src/zabbix_server/discoverer/../../../include/common.h
./src/zabbix_server/escalator/../../../include/common.h
./src/zabbix_server/housekeeper/../../../include/common.h
./src/zabbix_server/httppoller/../../../include/common.h
./src/zabbix_server/../../include/common.h
./src/zabbix_server/ipmi/../../../include/common.h
./src/zabbix_server/lld/../../../include/common.h
./src/zabbix_server/odbc/../../../include/common.h
./src/zabbix_server/pinger/../../../include/common.h
./src/zabbix_server/poller/../../../include/common.h
./src/zabbix_server/preprocessor/../../../include/common.h
./src/zabbix_server/proxypoller/../../../include/common.h
./src/zabbix_server/scripts/../../../include/common.h
./src/zabbix_server/selfmon/../../../include/common.h
./src/zabbix_server/snmptrapper/../../../include/common.h
./src/zabbix_server/taskmanager/../../../include/common.h
./src/zabbix_server/timer/../../../include/common.h
./src/zabbix_server/trapper/../../../include/common.h
./src/zabbix_server/vmware/../../../include/common.h

As you see, if we squash .. with the directory on the left (recursively) we will always get ./include/common.h.

Same here. Built with ninja though, i.e. no recursive makefiles.

../src/f1/f2/../../f1/f2/file.h
../src/f1/f3/../../f1/f2/file.h

PoC fix:

#include <filesystem>
namespace fs = std::filesystem;

std::string utils::GetNicePath(const std::string_view& path)
{
    return fs::path(path).lexically_normal();
}