init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
# 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
add_library(linux_allocation_tracer STATIC)
add_library(desktop-app::linux_allocation_tracer ALIAS linux_allocation_tracer)
nice_target_sources(linux_allocation_tracer ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE
linux_allocation_tracer.cpp
linux_allocation_tracer.h
)
add_executable(allocation_trace_reader WIN32)
init_target(allocation_trace_reader)
target_sources(allocation_trace_reader
PRIVATE
linux_allocation_trace_reader.cpp
)
set_target_properties(allocation_trace_reader PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

View File

@@ -0,0 +1,215 @@
// 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;
}

View File

@@ -0,0 +1,171 @@
// 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 "linux_allocation_tracer.h"
#include <atomic>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <malloc.h>
#include <dlfcn.h>
#include <stdio.h>
namespace {
std::atomic<void(*)(size_t, void *)> MallocLogger;
std::atomic<void(*)(size_t, void *)> VallocLogger;
std::atomic<void(*)(size_t, void *)> PVallocLogger;
std::atomic<void(*)(size_t, size_t, void *)> CallocLogger;
std::atomic<void(*)(void *, size_t, void *)> ReallocLogger;
std::atomic<void(*)(size_t, size_t, void *)> MemAlignLogger;
std::atomic<void(*)(size_t, size_t, void *)> AlignedAllocLogger;
std::atomic<void(*)(size_t, size_t, void *)> PosixMemAlignLogger;
std::atomic<void(*)(void *)> FreeLogger;
} // namespace
extern "C" {
//void *__real___malloc(size_t size);
void *__real___libc_malloc(size_t size);
void *__real_malloc(size_t size);
void *__real_valloc(size_t size);
void *__real_pvalloc(size_t size);
void *__real_calloc(size_t num, size_t size);
void *__real_realloc(void *ptr, size_t size);
void *__real_memalign(size_t alignment, size_t size);
void *__real_aligned_alloc(size_t alignment, size_t size);
int __real_posix_memalign(void **memptr, size_t alignment, size_t size);
void __real_free(void *ptr);
// void *__wrap___malloc(size_t size) {
// const auto result = __real___malloc(size);
// if (const auto logger = MallocLogger.load()) {
// logger(size, result);
// }
// return result;
// }
void *__wrap___libc_malloc(size_t size) {
const auto result = __real___libc_malloc(size);
if (const auto logger = MallocLogger.load()) {
logger(size, result);
}
return result;
}
void *__wrap_malloc(size_t size) {
const auto result = __real_malloc(size);
if (const auto logger = MallocLogger.load()) {
logger(size, result);
}
return result;
}
void *__wrap_valloc(size_t size) {
const auto result = __real_valloc(size);
if (const auto logger = VallocLogger.load()) {
logger(size, result);
}
return result;
}
void *__wrap_pvalloc(size_t size) {
const auto result = __real_pvalloc(size);
if (const auto logger = PVallocLogger.load()) {
logger(size, result);
}
return result;
}
void *__wrap_calloc(size_t num, size_t size) {
const auto result = __real_calloc(num, size);
if (const auto logger = CallocLogger.load()) {
logger(num, size, result);
}
return result;
}
void *__wrap_realloc(void *ptr, size_t size) {
const auto result = __real_realloc(ptr, size);
if (const auto logger = ReallocLogger.load()) {
logger(ptr, size, result);
}
return result;
}
void *__wrap_memalign(size_t alignment, size_t size) {
const auto result = __real_memalign(alignment, size);
if (const auto logger = MemAlignLogger.load()) {
logger(alignment, size, result);
}
return result;
}
void *__wrap_aligned_alloc(size_t alignment, size_t size) {
const auto result = __real_aligned_alloc(alignment, size);
if (const auto logger = AlignedAllocLogger.load()) {
logger(alignment, size, result);
}
return result;
}
int __wrap_posix_memalign(void **memptr, size_t alignment, size_t size) {
const auto result = __real_posix_memalign(memptr, alignment, size);
if (!result) {
if (const auto logger = PosixMemAlignLogger.load()) {
logger(alignment, size, *memptr);
}
}
return result;
}
void __wrap_free(void *ptr) {
if (const auto logger = FreeLogger.load()) {
logger(ptr);
}
__real_free(ptr);
}
} // extern "C"
void SetMallocLogger(void (*logger)(size_t, void *)) {
MallocLogger = logger;
}
void SetVallocLogger(void (*logger)(size_t, void *)) {
VallocLogger = logger;
}
void SetPVallocLogger(void (*logger)(size_t, void *)) {
PVallocLogger = logger;
}
void SetCallocLogger(void (*logger)(size_t, size_t, void *)) {
CallocLogger = logger;
}
void SetReallocLogger(void (*logger)(void *, size_t, void *)) {
ReallocLogger = logger;
}
void SetMemAlignLogger(void (*logger)(size_t, size_t, void *)) {
MemAlignLogger = logger;
}
void SetAlignedAllocLogger(void (*logger)(size_t, size_t, void *)) {
AlignedAllocLogger = logger;
}
void SetPosixMemAlignLogger(void (*logger)(size_t, size_t, void *)) {
PosixMemAlignLogger = logger;
}
void SetFreeLogger(void (*logger)(void *)) {
FreeLogger = logger;
}

View File

@@ -0,0 +1,19 @@
// 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
//
#pragma once
#include <cstdlib>
void SetMallocLogger(void (*logger)(size_t, void *));
void SetVallocLogger(void (*logger)(size_t, void *));
void SetPVallocLogger(void (*logger)(size_t, void *));
void SetCallocLogger(void (*logger)(size_t, size_t, void *));
void SetReallocLogger(void (*logger)(void *, size_t, void *));
void SetMemAlignLogger(void (*logger)(size_t, size_t, void *));
void SetAlignedAllocLogger(void (*logger)(size_t, size_t, void *));
void SetPosixMemAlignLogger(void (*logger)(size_t, size_t, void *));
void SetFreeLogger(void (*logger)(void *));