Merge pull request #313 from brandonvu12/master
Preserve Size Information During Diff
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 3dbc924..200c6b4 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -18,6 +18,12 @@
// It's very hard to figure out why. For the moment this seems to fix it,
// but ideally we'd have a better solution here.
typedef size_t z_size_t;
+#include <assert.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <math.h>
+#include <signal.h>
+#include <stdlib.h>
#include <zlib.h>
#include <atomic>
@@ -33,13 +39,6 @@
#include <thread>
#include <unordered_map>
#include <vector>
-
-#include <assert.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <math.h>
-#include <signal.h>
-#include <stdlib.h>
#if !defined(_WIN32)
#include <sys/mman.h>
#include <sys/wait.h>
@@ -53,14 +52,13 @@
#include "absl/debugging/internal/demangle.h"
#include "absl/memory/memory.h"
#include "absl/strings/numbers.h"
-#include "absl/strings/string_view.h"
#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
#include "bloaty.h"
#include "bloaty.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+#include "google/protobuf/text_format.h"
#include "re.h"
#include "util.h"
@@ -187,8 +185,7 @@
return std::string(symbol);
}
} else if (source == DataSource::kFullSymbols) {
- char* demangled =
- __cxa_demangle(demangle_from.data(), NULL, NULL, NULL);
+ char* demangled = __cxa_demangle(demangle_from.data(), NULL, NULL, NULL);
if (demangled) {
std::string ret(demangled);
free(demangled);
@@ -202,10 +199,10 @@
}
}
-
// NameMunger //////////////////////////////////////////////////////////////////
-void NameMunger::AddRegex(const std::string& regex, const std::string& replacement) {
+void NameMunger::AddRegex(const std::string& regex,
+ const std::string& replacement) {
auto reg = absl::make_unique<ReImpl>(regex);
regexes_.push_back(std::make_pair(std::move(reg), replacement));
}
@@ -223,7 +220,6 @@
return name_str;
}
-
// Rollup //////////////////////////////////////////////////////////////////////
// A Rollup is a hierarchical tally of sizes. Its graphical representation is
@@ -259,8 +255,8 @@
Rollup(Rollup&& other) = default;
Rollup& operator=(Rollup&& other) = default;
- void AddSizes(const std::vector<std::string>& names,
- uint64_t size, bool is_vmsize) {
+ void AddSizes(const std::vector<std::string>& names, uint64_t size,
+ bool is_vmsize) {
// We start at 1 to exclude the base map (see base_map_).
AddInternal(names, 1, size, is_vmsize);
}
@@ -274,33 +270,17 @@
void CreateDiffModeRollupOutput(Rollup* base, const Options& options,
RollupOutput* output) const {
RollupRow* row = &output->toplevel_row_;
- row->vmsize = vm_total_;
- row->filesize = file_total_;
- row->filtered_vmsize = filtered_vm_total_;
- row->filtered_filesize = filtered_file_total_;
+ row->size.vm = vm_total_;
+ row->size.file = file_total_;
+ row->filtered_size.vm = filtered_vm_total_;
+ row->filtered_size.file = filtered_file_total_;
row->vmpercent = 100;
row->filepercent = 100;
output->diff_mode_ = true;
CreateRows(row, base, options, true);
}
- void SetFilterRegex(const ReImpl* regex) {
- filter_regex_ = regex;
- }
-
- // Subtract the values in "other" from this.
- void Subtract(const Rollup& other) {
- vm_total_ -= other.vm_total_;
- file_total_ -= other.file_total_;
-
- for (const auto& other_child : other.children_) {
- auto& child = children_[other_child.first];
- if (child.get() == NULL) {
- child.reset(new Rollup());
- }
- child->Subtract(*other_child.second);
- }
- }
+ void SetFilterRegex(const ReImpl* regex) { filter_regex_ = regex; }
// Add the values in "other" from this.
void Add(const Rollup& other) {
@@ -316,6 +296,17 @@
}
}
+ // Create entries for all children which exist in "other" but not in this.
+ void AddEntriesFrom(const Rollup& other) {
+ for (const auto& other_child : other.children_) {
+ auto& child = children_[other_child.first];
+ if (child.get() == NULL) {
+ child.reset(new Rollup());
+ }
+ child->AddEntriesFrom(*other_child.second);
+ }
+ }
+
int64_t file_total() const { return file_total_; }
int64_t filtered_file_total() const { return filtered_file_total_; }
@@ -413,11 +404,33 @@
}
for (const auto& value : children_) {
- if (value.second->vm_total_ != 0 || value.second->file_total_ != 0) {
+ int64_t vm_total = value.second->vm_total_;
+ int64_t file_total = value.second->file_total_;
+ Rollup* base_child = nullptr;
+
+ if (base) {
+ // Reassign sizes to base during a diff to compare to target sizes.
+ auto it = base->children_.find(value.first);
+ if (it != base->children_.end()) {
+ base_child = it->second.get();
+ vm_total -= base_child->vm_total_;
+ file_total -= base_child->file_total_;
+ }
+ }
+
+ if (vm_total != 0 || file_total != 0) {
row->sorted_children.emplace_back(value.first);
RollupRow& child_row = row->sorted_children.back();
- child_row.vmsize = value.second->vm_total_;
- child_row.filesize = value.second->file_total_;
+ child_row.size.vm = vm_total;
+ child_row.size.file = file_total;
+
+ // Preserve the old size for this label in the RollupRow output.
+ // If there is a diff base, the old sizes come from the size of the label
+ // in that base. Otherwise, the old size stays 0.
+ if (base_child) {
+ child_row.old_size.vm = base_child->vm_total_;
+ child_row.old_size.file = base_child->file_total_;
+ }
}
}
@@ -452,14 +465,14 @@
for (auto& child : child_rows) {
switch (options.sort_by()) {
case Options::SORTBY_VMSIZE:
- child.sortkey = std::abs(child.vmsize);
+ child.sortkey = std::abs(child.size.vm);
break;
case Options::SORTBY_FILESIZE:
- child.sortkey = std::abs(child.filesize);
+ child.sortkey = std::abs(child.size.file);
break;
case Options::SORTBY_BOTH:
child.sortkey =
- std::max(std::abs(child.vmsize), std::abs(child.filesize));
+ std::max(std::abs(child.size.vm), std::abs(child.size.file));
break;
default:
BLOATY_UNREACHABLE();
@@ -478,8 +491,8 @@
// out to "others_row".
size_t i = child_rows.size() - 1;
while (i >= options.max_rows_per_level()) {
- CheckedAdd(&others_row.vmsize, child_rows[i].vmsize);
- CheckedAdd(&others_row.filesize, child_rows[i].filesize);
+ CheckedAdd(&others_row.size.vm, child_rows[i].size.vm);
+ CheckedAdd(&others_row.size.file, child_rows[i].size.file);
if (base) {
auto it = base->children_.find(child_rows[i].name);
if (it != base->children_.end()) {
@@ -492,26 +505,26 @@
i--;
}
- if (std::abs(others_row.vmsize) > 0 || std::abs(others_row.filesize) > 0) {
+ if (std::abs(others_row.size.vm) > 0 || std::abs(others_row.size.file) > 0) {
child_rows.push_back(others_row);
- CheckedAdd(&others_rollup.vm_total_, others_row.vmsize);
- CheckedAdd(&others_rollup.file_total_, others_row.filesize);
+ CheckedAdd(&others_rollup.vm_total_, others_row.size.vm);
+ CheckedAdd(&others_rollup.file_total_, others_row.size.file);
}
// Now sort by actual value (positive or negative).
for (auto& child : child_rows) {
switch (options.sort_by()) {
case Options::SORTBY_VMSIZE:
- child.sortkey = child.vmsize;
+ child.sortkey = child.size.vm;
break;
case Options::SORTBY_FILESIZE:
- child.sortkey = child.filesize;
+ child.sortkey = child.size.file;
break;
case Options::SORTBY_BOTH:
- if (std::abs(child.vmsize) > std::abs(child.filesize)) {
- child.sortkey = child.vmsize;
+ if (std::abs(child.size.vm) > std::abs(child.size.file)) {
+ child.sortkey = child.size.vm;
} else {
- child.sortkey = child.filesize;
+ child.sortkey = child.size.file;
}
break;
default:
@@ -524,8 +537,8 @@
// For a non-diff, the percentage is compared to the total size of the parent.
if (!base) {
for (auto& child_row : child_rows) {
- child_row.vmpercent = Percent(child_row.vmsize, row->vmsize);
- child_row.filepercent = Percent(child_row.filesize, row->filesize);
+ child_row.vmpercent = Percent(child_row.size.vm, row->size.vm);
+ child_row.filepercent = Percent(child_row.size.file, row->size.file);
}
}
@@ -561,7 +574,6 @@
}
}
-
// RollupOutput ////////////////////////////////////////////////////////////////
// RollupOutput represents rollup data after we have applied output massaging
@@ -600,14 +612,14 @@
return ret;
}
-std::string DoubleStringPrintf(const char *fmt, double d) {
+std::string DoubleStringPrintf(const char* fmt, double d) {
char buf[1024];
snprintf(buf, sizeof(buf), fmt, d);
return std::string(buf);
}
std::string SiPrint(int64_t size, bool force_sign) {
- const char *prefixes[] = {"", "Ki", "Mi", "Gi", "Ti"};
+ const char* prefixes[] = {"", "Ki", "Mi", "Gi", "Ti"};
size_t num_prefixes = 5;
size_t n = 0;
double size_d = size;
@@ -677,10 +689,10 @@
PrettyPrint(options, out);
break;
case bloaty::OutputFormat::kCSV:
- PrintToCSV(out, /*tabs=*/false);
+ PrintToCSV(out, /*tabs=*/false, options.showAllSizesCSV);
break;
case bloaty::OutputFormat::kTSV:
- PrintToCSV(out, /*tabs=*/true);
+ PrintToCSV(out, /*tabs=*/true, options.showAllSizesCSV);
break;
default:
BLOATY_UNREACHABLE();
@@ -698,8 +710,8 @@
if (&row != &toplevel_row_) {
// Avoid printing this row if it is only zero.
// This can happen when using --domain if the row is zero for this domain.
- if ((!ShowFile(options) && row.vmsize == 0) ||
- (!ShowVM(options) && row.filesize == 0)) {
+ if ((!ShowFile(options) && row.size.vm == 0) ||
+ (!ShowVM(options) && row.size.file == 0)) {
return;
}
}
@@ -708,12 +720,12 @@
if (ShowFile(options)) {
*out << PercentString(row.filepercent, diff_mode_) << " "
- << SiPrint(row.filesize, diff_mode_) << " ";
+ << SiPrint(row.size.file, diff_mode_) << " ";
}
if (ShowVM(options)) {
*out << PercentString(row.vmpercent, diff_mode_) << " "
- << SiPrint(row.vmsize, diff_mode_) << " ";
+ << SiPrint(row.size.vm, diff_mode_) << " ";
}
*out << " " << row.name << "\n";
@@ -737,7 +749,7 @@
// Rows are printed before their sub-rows.
PrettyPrintRow(row, indent, options, out);
- if (!row.vmsize && !row.filesize) {
+ if (!row.size.vm && !row.size.file) {
return;
}
@@ -783,11 +795,12 @@
uint64_t file_filtered = 0;
uint64_t vm_filtered = 0;
+ uint64_t filtered = 0;
if (ShowFile(options)) {
- file_filtered = toplevel_row_.filtered_filesize;
+ filtered += toplevel_row_.filtered_size.file;
}
if (ShowVM(options)) {
- vm_filtered = toplevel_row_.filtered_vmsize;
+ filtered += toplevel_row_.filtered_size.vm;
}
if (vm_filtered == 0 && file_filtered == 0) {
@@ -805,19 +818,28 @@
*out << SiPrint(vm_filtered, /*force_sign=*/false);
}
- *out << " of entries\n";
+ *out << " of entries\n";
}
void RollupOutput::PrintRowToCSV(const RollupRow& row,
std::vector<std::string> parent_labels,
- std::ostream* out, bool tabs) const {
+ std::ostream* out, bool tabs, bool csvDiff) const {
while (parent_labels.size() < source_names_.size()) {
// If this label had no data at this level, append an empty string.
parent_labels.push_back("");
}
- parent_labels.push_back(std::to_string(row.vmsize));
- parent_labels.push_back(std::to_string(row.filesize));
+ parent_labels.push_back(std::to_string(row.size.vm));
+ parent_labels.push_back(std::to_string(row.size.file));
+
+ // If in diff where both old size are 0, get new size by adding diff size to
+ // old size.
+ if (csvDiff) {
+ parent_labels.push_back(std::to_string(row.old_size.vm));
+ parent_labels.push_back(std::to_string(row.old_size.file));
+ parent_labels.push_back(std::to_string(row.old_size.vm + (row.size.vm)));
+ parent_labels.push_back(
+ std::to_string(row.old_size.file + (row.size.file)));}
std::string sep = tabs ? "\t" : ",";
*out << absl::StrJoin(parent_labels, sep) << "\n";
@@ -825,7 +847,7 @@
void RollupOutput::PrintTreeToCSV(const RollupRow& row,
std::vector<std::string> parent_labels,
- std::ostream* out, bool tabs) const {
+ std::ostream* out, bool tabs, bool csvDiff) const {
if (tabs) {
parent_labels.push_back(row.name);
} else {
@@ -834,21 +856,28 @@
if (row.sorted_children.size() > 0) {
for (const auto& child_row : row.sorted_children) {
- PrintTreeToCSV(child_row, parent_labels, out, tabs);
+ PrintTreeToCSV(child_row, parent_labels, out, tabs, csvDiff);
}
} else {
- PrintRowToCSV(row, parent_labels, out, tabs);
+ PrintRowToCSV(row, parent_labels, out, tabs, csvDiff);
}
}
-void RollupOutput::PrintToCSV(std::ostream* out, bool tabs) const {
+void RollupOutput::PrintToCSV(std::ostream* out, bool tabs,
+ bool csvDiff) const {
std::vector<std::string> names(source_names_);
names.push_back("vmsize");
names.push_back("filesize");
+ if (csvDiff) {
+ names.push_back("original_vmsize");
+ names.push_back("original_filesize");
+ names.push_back("current_vmsize");
+ names.push_back("current_filesize");
+ }
std::string sep = tabs ? "\t" : ",";
*out << absl::StrJoin(names, sep) << "\n";
for (const auto& child_row : toplevel_row_.sorted_children) {
- PrintTreeToCSV(child_row, std::vector<std::string>(), out, tabs);
+ PrintTreeToCSV(child_row, std::vector<std::string>(), out, tabs, csvDiff);
}
}
@@ -856,7 +885,6 @@
constexpr uint64_t RangeSink::kUnknownSize;
-
// MmapInputFile ///////////////////////////////////////////////////////////////
#if !defined(_WIN32)
@@ -875,7 +903,6 @@
std::unique_ptr<InputFile>& file);
};
-
class FileDescriptor {
public:
FileDescriptor(int fd) : fd_(fd) {}
@@ -897,7 +924,7 @@
std::string str(filename);
FileDescriptor fd(open(str.c_str(), O_RDONLY));
struct stat buf;
- const char *map;
+ const char* map;
if (fd.fd() < 0) {
std::cerr << absl::Substitute("couldn't open file '$0': $1\n", filename,
@@ -945,7 +972,7 @@
return ret;
}
-#else // !_WIN32
+#else // !_WIN32
// MmapInputFile ///////////////////////////////////////////////////////////////
@@ -989,9 +1016,9 @@
bool Win32MMapInputFile::DoTryOpen(absl::string_view filename,
std::unique_ptr<InputFile>& file) {
std::string str(filename);
- Win32Handle fd(::CreateFileA(str.c_str(), FILE_GENERIC_READ,
- FILE_SHARE_READ, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL));
+ Win32Handle fd(::CreateFileA(str.c_str(), FILE_GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ NULL));
LARGE_INTEGER li = {};
const char* map;
@@ -1046,11 +1073,14 @@
// RangeSink ///////////////////////////////////////////////////////////////////
-RangeSink::RangeSink(const InputFile *file, const Options &options,
- DataSource data_source, const DualMap *translator,
- google::protobuf::Arena *arena)
- : file_(file), options_(options), data_source_(data_source),
- translator_(translator), arena_(arena) {}
+RangeSink::RangeSink(const InputFile* file, const Options& options,
+ DataSource data_source, const DualMap* translator,
+ google::protobuf::Arena* arena)
+ : file_(file),
+ options_(options),
+ data_source_(data_source),
+ translator_(translator),
+ arena_(arena) {}
RangeSink::~RangeSink() {}
@@ -1346,21 +1376,23 @@
}
uint64_t mb = 1 << 20;
// Limit for uncompressed size is 30x the compressed size + 128MB.
- if (uncompressed_size > static_cast<uint64_t>(data.size()) * 30 + (128 * mb)) {
+ if (uncompressed_size >
+ static_cast<uint64_t>(data.size()) * 30 + (128 * mb)) {
fprintf(stderr,
"warning: ignoring compressed debug data, implausible uncompressed "
"size (compressed: %zu, uncompressed: %" PRIu64 ")\n",
data.size(), uncompressed_size);
return absl::string_view();
}
- unsigned char *dbuf =
+ unsigned char* dbuf =
arena_->google::protobuf::Arena::CreateArray<unsigned char>(
arena_, uncompressed_size);
uLongf zliblen = uncompressed_size;
- if (uncompress(dbuf, &zliblen, (unsigned char*)(data.data()), data.size()) != Z_OK) {
+ if (uncompress(dbuf, &zliblen, (unsigned char*)(data.data()), data.size()) !=
+ Z_OK) {
THROW("Error decompressing debug info");
}
- string_view sv(reinterpret_cast<char *>(dbuf), zliblen);
+ string_view sv(reinterpret_cast<char*>(dbuf), zliblen);
return sv;
}
@@ -1403,7 +1435,6 @@
const int max_;
};
-
// Bloaty //////////////////////////////////////////////////////////////////////
// Represents a program execution and associated state.
@@ -1501,8 +1532,9 @@
std::unique_ptr<google::protobuf::Arena> arena_;
};
-Bloaty::Bloaty(const InputFileFactory &factory, const Options &options)
- : file_factory_(factory), options_(options),
+Bloaty::Bloaty(const InputFileFactory& factory, const Options& options)
+ : file_factory_(factory),
+ options_(options),
arena_(std::make_unique<google::protobuf::Arena>()) {
AddBuiltInSources(data_sources, options);
}
@@ -1563,8 +1595,10 @@
auto iter = all_known_sources_.find(source.base_data_source());
if (iter == all_known_sources_.end()) {
- THROWF("custom data source '$0': no such base source '$1'.\nTry --list-sources to see valid sources.", source.name(),
- source.base_data_source());
+ THROWF(
+ "custom data source '$0': no such base source '$1'.\nTry "
+ "--list-sources to see valid sources.",
+ source.name(), source.base_data_source());
} else if (!iter->second->munger->IsEmpty()) {
THROWF("custom data source '$0' tries to depend on custom data source '$1'",
source.name(), source.base_data_source());
@@ -1582,7 +1616,8 @@
source_names_.emplace_back(name);
auto it = all_known_sources_.find(name);
if (it == all_known_sources_.end()) {
- THROWF("no such data source: $0.\nTry --list-sources to see valid sources.", name);
+ THROWF("no such data source: $0.\nTry --list-sources to see valid sources.",
+ name);
}
sources_.emplace_back(it->second.get());
@@ -1649,7 +1684,8 @@
return ret;
}
- void PrintMapRow(string_view str, uint64_t start, uint64_t end, int hex_digits) {
+ void PrintMapRow(string_view str, uint64_t start, uint64_t end,
+ int hex_digits) {
printf("%.*" PRIx64 "-%.*" PRIx64 "\t %s\t\t%.*s\n", hex_digits, start,
hex_digits, end, LeftPad(std::to_string(end - start), 10).c_str(),
(int)str.size(), str.data());
@@ -1677,7 +1713,7 @@
std::vector<std::unique_ptr<DualMap>> maps_;
};
-void Bloaty::ScanAndRollupFile(const std::string &filename, Rollup* rollup,
+void Bloaty::ScanAndRollupFile(const std::string& filename, Rollup* rollup,
std::vector<std::string>* out_build_ids) const {
auto file = GetObjectFile(filename);
@@ -1694,9 +1730,9 @@
sink_ptrs.push_back(sinks.back().get());
for (auto source : sources_) {
- sinks.push_back(absl::make_unique<RangeSink>(&file->file_data(), options_,
- source->effective_source,
- maps.base_map(), arena_.get()));
+ sinks.push_back(absl::make_unique<RangeSink>(
+ &file->file_data(), options_, source->effective_source, maps.base_map(),
+ arena_.get()));
sinks.back()->AddOutput(maps.AppendMap(), source->munger.get());
// We handle the kInputFiles data source internally, without handing it off
// to the file format implementation. This seems slightly simpler, since
@@ -1719,8 +1755,8 @@
}
}
- int64_t filesize_before = rollup->file_total() +
- rollup->filtered_file_total();
+ int64_t filesize_before =
+ rollup->file_total() + rollup->filtered_file_total();
file->ProcessFile(sink_ptrs);
// kInputFile source: Copy the base map to the filename sink(s).
@@ -1740,8 +1776,8 @@
maps.ComputeRollup(rollup);
// The ObjectFile implementation must guarantee this.
- int64_t filesize = rollup->file_total() +
- rollup->filtered_file_total() - filesize_before;
+ int64_t filesize =
+ rollup->file_total() + rollup->filtered_file_total() - filesize_before;
(void)filesize;
assert(filesize == file->file_data().data().size());
@@ -1758,10 +1794,9 @@
}
}
-void Bloaty::ScanAndRollupFiles(
- const std::vector<std::string>& filenames,
- std::vector<std::string>* build_ids,
- Rollup * rollup) const {
+void Bloaty::ScanAndRollupFiles(const std::vector<std::string>& filenames,
+ std::vector<std::string>* build_ids,
+ Rollup* rollup) const {
int num_cpus = std::thread::hardware_concurrency();
int num_threads = std::min(num_cpus, static_cast<int>(filenames.size()));
@@ -1782,16 +1817,18 @@
for (int i = 0; i < num_threads; i++) {
thread_data[i].rollup.SetFilterRegex(regex.get());
- threads[i] = std::thread([this, &index, &filenames](PerThreadData* data) {
- try {
- int j;
- while (index.TryGetNext(&j)) {
- ScanAndRollupFile(filenames[j], &data->rollup, &data->build_ids);
- }
- } catch (const bloaty::Error& e) {
- index.Abort(e.what());
- }
- }, &thread_data[i]);
+ threads[i] = std::thread(
+ [this, &index, &filenames](PerThreadData* data) {
+ try {
+ int j;
+ while (index.TryGetNext(&j)) {
+ ScanAndRollupFile(filenames[j], &data->rollup, &data->build_ids);
+ }
+ } catch (const bloaty::Error& e) {
+ index.Abort(e.what());
+ }
+ },
+ &thread_data[i]);
}
for (int i = 0; i < num_threads; i++) {
@@ -1803,8 +1840,7 @@
rollup->Add(data->rollup);
}
- build_ids->insert(build_ids->end(),
- data->build_ids.begin(),
+ build_ids->insert(build_ids->end(), data->build_ids.begin(),
data->build_ids.end());
}
@@ -1838,7 +1874,7 @@
base_filenames.push_back(file_info.filename_);
}
ScanAndRollupFiles(base_filenames, &build_ids, &base);
- rollup.Subtract(base);
+ rollup.AddEntriesFrom(base);
rollup.CreateDiffModeRollupOutput(&base, options, output);
} else {
rollup.CreateRollupOutput(options, output);
@@ -1854,8 +1890,7 @@
std::string unused_debug;
for (const auto& pair : debug_files_) {
unused_debug += absl::Substitute(
- "$0 $1\n",
- absl::BytesToHexString(pair.first).c_str(),
+ "$0 $1\n", absl::BytesToHexString(pair.first).c_str(),
pair.second.c_str());
}
@@ -1869,9 +1904,8 @@
"$0 $1\n", absl::BytesToHexString(file_info.build_id_).c_str(),
file_info.filename_.c_str());
}
- THROWF(
- "Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
- unused_debug.c_str(), input_files.c_str());
+ THROWF("Debug file(s) did not match any input file:\n$0\nInput Files:\n$1",
+ unused_debug.c_str(), input_files.c_str());
}
}
@@ -1961,9 +1995,7 @@
return ret;
}
- void ConsumeAndSaveArg() {
- (*out_argv_)[(*out_argc_)++] = argv_[index_++];
- }
+ void ConsumeAndSaveArg() { (*out_argv_)[(*out_argc_)++] = argv_[index_++]; }
// Singular flag like --csv or -v.
bool TryParseFlag(string_view flag) {
@@ -2154,6 +2186,7 @@
}
} else {
if (saw_separator) {
+ output_options->showAllSizesCSV = true;
options->add_base_filename(std::string(args.ConsumeArg()));
} else {
options->add_filename(std::string(args.ConsumeArg()));
diff --git a/src/bloaty.h b/src/bloaty.h
index 82c0c55..5f8d470 100644
--- a/src/bloaty.h
+++ b/src/bloaty.h
@@ -337,18 +337,26 @@
class Rollup;
+struct DomainSizes {
+ int64_t vm;
+ int64_t file;
+};
+
struct RollupRow {
RollupRow(const std::string& name_) : name(name_) {}
std::string name;
- int64_t vmsize = 0;
- int64_t filesize = 0;
- int64_t filtered_vmsize = 0;
- int64_t filtered_filesize = 0;
+ DomainSizes size = {0, 0};
+ DomainSizes filtered_size = {0, 0};
+
int64_t other_count = 0;
int64_t sortkey;
double vmpercent;
double filepercent;
+
+ // The size of the base in a diff mode. Otherwise stay 0.
+ DomainSizes old_size = {0, 0};
+
std::vector<RollupRow> sorted_children;
static bool Compare(const RollupRow& a, const RollupRow& b) {
@@ -377,6 +385,7 @@
OutputFormat output_format = OutputFormat::kPrettyPrint;
size_t max_label_len = 80;
ShowDomain show = ShowDomain::kShowBoth;
+ bool showAllSizesCSV = false;
};
struct RollupOutput {
@@ -413,17 +422,17 @@
static bool IsSame(const std::string& a, const std::string& b);
void PrettyPrint(const OutputOptions& options, std::ostream* out) const;
- void PrintToCSV(std::ostream* out, bool tabs) const;
+ void PrintToCSV(std::ostream* out, bool tabs, bool csvDiff) const;
void PrettyPrintRow(const RollupRow& row, size_t indent,
const OutputOptions& options, std::ostream* out) const;
void PrettyPrintTree(const RollupRow& row, size_t indent,
const OutputOptions& options, std::ostream* out) const;
void PrintRowToCSV(const RollupRow& row,
std::vector<std::string> parent_labels,
- std::ostream* out, bool tabs) const;
+ std::ostream* out, bool tabs, bool csvDiff) const;
void PrintTreeToCSV(const RollupRow& row,
std::vector<std::string> parent_labels,
- std::ostream* out, bool tabs) const;
+ std::ostream* out, bool tabs, bool csvDiff) const;
};
bool ParseOptions(bool skip_unknown, int* argc, char** argv[], Options* options,
diff --git a/tests/bloaty_misc_test.cc b/tests/bloaty_misc_test.cc
index 3a4bf41..a1d5084 100644
--- a/tests/bloaty_misc_test.cc
+++ b/tests/bloaty_misc_test.cc
@@ -27,7 +27,7 @@
{"bloaty", "-d", "compileunits", "03-small-binary-that-crashed-inlines.bin"});
RunBloaty(
{"bloaty", "-d", "inlines", "03-small-binary-that-crashed-inlines.bin"});
- EXPECT_EQ(top_row_->vmsize, 2340);
+ EXPECT_EQ(top_row_->size.vm, 2340);
}
TEST_F(BloatyTest, GoBinary) {
@@ -46,7 +46,7 @@
TEST_F(BloatyTest, MultiThreaded) {
RunBloaty({"bloaty", "02-section-count-overflow.o"});
- size_t file_size = top_row_->filesize;
+ size_t file_size = top_row_->size.file;
// Bloaty doesn't know or care that you are passing the same file multiple
// times.
@@ -56,5 +56,5 @@
args.push_back("02-section-count-overflow.o");
}
RunBloaty(args); // Heavily multithreaded test.
- EXPECT_EQ(top_row_->filesize, file_size * 100);
+ EXPECT_EQ(top_row_->size.file, file_size * 100);
}
diff --git a/tests/bloaty_test.cc b/tests/bloaty_test.cc
index 8187aca..68eb9df 100644
--- a/tests/bloaty_test.cc
+++ b/tests/bloaty_test.cc
@@ -21,20 +21,20 @@
// Empty .c file should result in a .o file with no vmsize.
RunBloaty({"bloaty", file});
- EXPECT_EQ(top_row_->vmsize, 0);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_EQ(top_row_->size.vm, 0);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 1);
// Same with segments (we fake segments on .o files).
RunBloaty({"bloaty", "-d", "segments", file});
- EXPECT_EQ(top_row_->vmsize, 0);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_EQ(top_row_->size.vm, 0);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 1);
// Same with symbols.
RunBloaty({"bloaty", "-d", "symbols", file});
- EXPECT_EQ(top_row_->vmsize, 0);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_EQ(top_row_->size.vm, 0);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 1);
// We can't run any of these targets against object files.
@@ -50,16 +50,16 @@
// Test "-n 0" which should return an unlimited number of rows.
RunBloaty({"bloaty", "-n", "0", file});
- EXPECT_GT(top_row_->vmsize, 64);
- EXPECT_LT(top_row_->vmsize, 300);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 64);
+ EXPECT_LT(top_row_->size.vm, 300);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 1);
// Same with segments (we fake segments on .o files).
RunBloaty({"bloaty", "-d", "segments", file});
- EXPECT_GT(top_row_->vmsize, 64);
- EXPECT_LT(top_row_->vmsize, 300);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 64);
+ EXPECT_LT(top_row_->size.vm, 300);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 1);
// For inputfiles we should get everything attributed to the input file.
@@ -111,15 +111,15 @@
ASSERT_TRUE(GetFileSize(file, &size));
RunBloaty({"bloaty", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- //EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ //EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 3);
RunBloaty({"bloaty", "-d", "segments", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- //EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ //EXPECT_EQ(top_row_->size.file, size);
RunBloaty({"bloaty", "-d", "symbols", "-n", "40", "-s", "vm", file});
AssertChildren(*top_row_, {
@@ -174,15 +174,15 @@
ASSERT_TRUE(GetFileSize(file, &size));
RunBloaty({"bloaty", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 3);
RunBloaty({"bloaty", "-d", "segments", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ EXPECT_EQ(top_row_->size.file, size);
RunBloaty({"bloaty", "-d", "symbols", "-n", "50", file});
AssertChildren(*top_row_, {
@@ -199,15 +199,15 @@
ASSERT_TRUE(GetFileSize(file, &size));
RunBloaty({"bloaty", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ EXPECT_EQ(top_row_->size.file, size);
EXPECT_GT(top_row_->sorted_children.size(), 3);
RunBloaty({"bloaty", "-d", "segments", file});
- EXPECT_GT(top_row_->vmsize, 8000);
- EXPECT_LT(top_row_->vmsize, 12000);
- EXPECT_EQ(top_row_->filesize, size);
+ EXPECT_GT(top_row_->size.vm, 8000);
+ EXPECT_LT(top_row_->size.vm, 12000);
+ EXPECT_EQ(top_row_->size.file, size);
RunBloaty({"bloaty", "-d", "symbols", "-n", "50", "-s", "vm", file});
AssertChildren(*top_row_, {
diff --git a/tests/test.h b/tests/test.h
index dc864f0..99517d7 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -81,16 +81,16 @@
uint64_t vmtotal = 0;
uint64_t filetotal = 0;
for (const auto& child : row.sorted_children) {
- vmtotal += child.vmsize;
- filetotal += child.filesize;
+ vmtotal += child.size.vm;
+ filetotal += child.size.file;
CheckConsistencyForRow(child, false, diff_mode, count);
ASSERT_TRUE(names.insert(child.name).second);
- ASSERT_FALSE(child.vmsize == 0 && child.filesize == 0);
+ ASSERT_FALSE(child.size.vm == 0 && child.size.file == 0);
}
if (!diff_mode) {
- ASSERT_EQ(vmtotal, row.vmsize);
- ASSERT_EQ(filetotal, row.filesize);
+ ASSERT_EQ(vmtotal, row.size.vm);
+ ASSERT_EQ(filetotal, row.size.file);
}
} else {
// Count leaf rows.
@@ -147,7 +147,7 @@
ASSERT_TRUE(GetFileSize(filename, &size));
total_input_size += size;
}
- ASSERT_EQ(top_row_->filesize, total_input_size);
+ ASSERT_EQ(top_row_->size.file, total_input_size);
}
int rows = 0;
@@ -248,21 +248,21 @@
if (expected_vm == kUnknown) {
// Always pass.
} else if (expected_vm > 0) {
- EXPECT_GE(child.vmsize, expected_vm);
+ EXPECT_GE(child.size.vm, expected_vm);
// Allow some overhead.
- EXPECT_LE(child.vmsize, (expected_vm * 1.1) + 100);
+ EXPECT_LE(child.size.vm, (expected_vm * 1.1) + 100);
} else {
ASSERT_TRUE(false);
}
if (expected_file == kSameAsVM) {
- expected_file = child.vmsize;
+ expected_file = child.size.vm;
}
if (expected_file != kUnknown) {
- EXPECT_GE(child.filesize, expected_file);
+ EXPECT_GE(child.size.file, expected_file);
// Allow some overhead.
- EXPECT_LE(child.filesize, (expected_file * 1.2) + 180);
+ EXPECT_LE(child.size.file, (expected_file * 1.2) + 180);
}
if (++i == children.size()) {
diff --git a/tests/testdata/make_all_msvc_test_files.bat b/tests/testdata/make_all_msvc_test_files.bat
old mode 100644
new mode 100755