aras-p / ClangBuildAnalyzer

Clang build analysis tool using -ftime-trace
The Unlicense
995 stars 64 forks source link

Same file is reported multiple times when relative paths are used #8

Closed i-ky closed 2 years ago

i-ky commented 5 years ago

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.

aras-p commented 5 years ago

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.

i-ky commented 5 years ago

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.

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.

Trass3r commented 3 years ago

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
Trass3r commented 3 years ago

PoC fix:

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

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