| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include <iostream>
- #include <iomanip>
- #include <locale>
- #include <unordered_map>
- #include <cstring>
- #include <ctime>
- #include <vector>
- constexpr auto kBufferSize = 1024 * 1024;
- char Buffer[kBufferSize];
- struct Fields {
- std::uint32_t time = 0;
- std::size_t mallocs = 0;
- std::size_t reallocs = 0;
- std::size_t frees = 0;
- std::size_t unknownReallocs = 0;
- std::size_t unknownFrees = 0;
- };
- Fields State;
- std::unordered_map<std::uint64_t, std::size_t> Map;
- std::vector<Fields> Snapshots;
- void WriteTime(std::uint32_t time) {
- std::time_t t = std::time_t(time);
- const auto parsed = std::localtime(&t);
- std::cout
- << std::setw(2) << std::setfill('0') << parsed->tm_hour
- << ":"
- << std::setw(2) << std::setfill('0') << parsed->tm_min
- << ":"
- << std::setw(2) << std::setfill('0') << parsed->tm_sec;
- }
- void PrintState() {
- if (!State.time) {
- return;
- }
- WriteTime(State.time);
- auto full = std::uint64_t(0);
- for (const auto &[address, amount] : Map) {
- full += amount;
- }
- class NumPunct final : public std::numpunct<char> {
- protected:
- char do_thousands_sep() const override { return '\''; }
- std::string do_grouping() const override { return "\03"; }
- };
- const auto &locale = std::cout.getloc();
- std::cout.imbue(std::locale(std::locale::classic(), new NumPunct()));
- std::cout
- << ": "
- << std::setw(13) << std::setfill(' ') << full
- << " (unknown: "
- << State.unknownFrees
- << ")"
- << std::endl;
- std::cout.imbue(locale);
- }
- void Add(std::uint64_t address, std::uint64_t size) {
- const auto i = Map.find(address);
- if (i != end(Map)) {
- std::cout
- << "WARNING: Repeated entry for "
- << address
- << " (size: "
- << size
- << ")."
- << std::endl;
- return;
- }
- Map.emplace(address, size);
- }
- void ParseMalloc(const char *buffer) {
- const auto size = *reinterpret_cast<const std::uint64_t*>(buffer);
- const auto address = *reinterpret_cast<const std::uint64_t*>(buffer + 8);
- Add(address, size);
- ++State.mallocs;
- }
- void ParseRealloc(const char *buffer) {
- const auto old = *reinterpret_cast<const std::uint64_t*>(buffer);
- const auto size = *reinterpret_cast<const std::uint64_t*>(buffer + 8);
- const auto address = *reinterpret_cast<const std::uint64_t*>(buffer + 16);
- const auto i = Map.find(old);
- if (i == end(Map)) {
- ++State.unknownReallocs;
- Add(address, size);
- } else if (old != address) {
- Map.erase(i);
- Add(address, size);
- ++State.reallocs;
- } else {
- i->second = size;
- ++State.reallocs;
- }
- }
- void ParseFree(const char *buffer) {
- const auto address = *reinterpret_cast<const std::uint64_t*>(buffer);
- const auto i = Map.find(address);
- if (i == end(Map)) {
- ++State.unknownFrees;
- } else {
- Map.erase(i);
- ++State.frees;
- }
- }
- long Parse(const char *buffer, const char *end) {
- auto result = 0;
- while (end > buffer) {
- const auto command = buffer[0];
- auto entry = 0;
- switch (command) {
- case 1: entry = 5 + 2 * sizeof(std::uint64_t); break;
- case 2: entry = 5 + 3 * sizeof(std::uint64_t); break;
- case 3: entry = 5 + sizeof(std::uint64_t); break;
- default:
- std::cout
- << "WARNING: Garbage in trace file, command: "
- << int(command)
- << "."
- << std::endl;
- return -1;
- }
- if (end - buffer < entry) {
- break;
- }
- const auto time = *reinterpret_cast<const std::uint32_t*>(++buffer);
- buffer += 4;
- if (time > State.time) {
- PrintState();
- State.time = time;
- } else if (time < State.time) {
- std::cout
- << "WARNING: Time "
- << time
- << " after "
- << State.time
- << "."
- << std::endl;
- }
- switch (command) {
- case 1: ParseMalloc(buffer); break;
- case 2: ParseRealloc(buffer); break;
- case 3: ParseFree(buffer); break;
- }
- buffer += entry - 5;
- result += entry;
- }
- return result;
- }
- int main(int argc, char *argv[]) {
- if (argc != 2) {
- std::cout
- << "Usage 'allocation_trace_reader [trace_file_path]'."
- << std::endl;
- return -1;
- }
- const auto file = fopen(argv[1], "rb");
- if (!file) {
- std::cout
- << "ERROR: Could not open '"
- << argv[1]
- << "'."
- << std::endl;
- return -1;
- }
- char *data = Buffer;
- while (true) {
- const auto read = fread(data, 1, Buffer + kBufferSize - data, file);
- if (read == 0) {
- if (data != Buffer) {
- std::cout
- << "WARNING: Trace file end is corrupt, could not parse: "
- << std::size_t(data - Buffer)
- << std::endl;
- }
- break;
- }
- data += read;
- const auto parsed = Parse(Buffer, data);
- if (parsed < 0) {
- break;
- }
- data -= parsed;
- if (data - Buffer > 0) {
- std::memmove(Buffer, Buffer + parsed, data - Buffer);
- }
- }
- PrintState();
- std::cout << "Mallocs: " << State.mallocs << "." << std::endl;
- std::cout << "Reallocs: " << State.reallocs << "." << std::endl;
- std::cout << "Frees: " << State.frees << "." << std::endl;
- if (State.unknownReallocs) {
- std::cout
- << "Unknown realloc() calls: "
- << State.unknownReallocs
- << "."
- << std::endl;
- }
- return 0;
- }
|