Skip to content

Commit 3ad4951

Browse files
committed
Merge pull request #2107 from pguyot/w08/dump-largest-binaries-on-oom
Dump largest refc binaries on oom crashes These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents 2e63bff + 5e8d98d commit 3ad4951

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed

src/libAtomVM/context.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ COLD_FUNC void context_dump(Context *ctx)
13001300
fprintf(stderr, "process_count = %zu\n", process_count);
13011301
fprintf(stderr, "ports_count = %zu\n", ports_count);
13021302
fprintf(stderr, "atoms_count = %zu\n", atom_table_count(glb->atom_table));
1303-
fprintf(stderr, "refc_binary_total_size = %zu\n", refc_binary_total_size(ctx));
1303+
refc_binary_dump_info(ctx);
13041304
}
13051305
fprintf(stderr, "\n\n**End Of Crash Report**\n");
13061306
}

src/libAtomVM/refc_binary.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,86 @@ size_t refc_binary_total_size(Context *ctx)
146146
synclist_unlock(&ctx->global->refc_binaries);
147147
return size;
148148
}
149+
150+
COLD_FUNC void refc_binary_dump_info(Context *ctx)
151+
{
152+
struct ListHead *item;
153+
struct ListHead *refc_binaries = synclist_rdlock(&ctx->global->refc_binaries);
154+
155+
// Note: This only counts non-const refc binaries (ones that allocate memory).
156+
// Const binaries (created by term_from_const_binary) point to existing data
157+
// and are never added to the global refc_binaries list, so they don't appear here.
158+
159+
// First pass: count and calculate total size
160+
size_t count = 0;
161+
size_t total_size = 0;
162+
LIST_FOR_EACH (item, refc_binaries) {
163+
struct RefcBinary *refc = GET_LIST_ENTRY(item, struct RefcBinary, head);
164+
count++;
165+
total_size += refc->size;
166+
}
167+
168+
fprintf(stderr, "refc_binary_count = %d\n", (int) count);
169+
fprintf(stderr, "refc_binary_total_size = %d\n", (int) total_size);
170+
171+
if (count == 0) {
172+
synclist_unlock(&ctx->global->refc_binaries);
173+
return;
174+
}
175+
176+
// Find top 5 largest binaries
177+
#define TOP_N 5
178+
struct RefcBinary *top[TOP_N] = { NULL };
179+
size_t top_indices[TOP_N] = { 0 };
180+
181+
size_t index = 0;
182+
LIST_FOR_EACH (item, refc_binaries) {
183+
struct RefcBinary *refc = GET_LIST_ENTRY(item, struct RefcBinary, head);
184+
185+
// Try to insert into top 5
186+
for (size_t i = 0; i < TOP_N; i++) {
187+
if (top[i] == NULL || refc->size > top[i]->size) {
188+
// Shift down
189+
for (size_t j = TOP_N - 1; j > i; j--) {
190+
top[j] = top[j - 1];
191+
top_indices[j] = top_indices[j - 1];
192+
}
193+
top[i] = refc;
194+
top_indices[i] = index;
195+
break;
196+
}
197+
}
198+
index++;
199+
}
200+
201+
// Display top binaries
202+
fprintf(stderr, "\nTop %d largest refc binaries:\n", TOP_N);
203+
for (size_t i = 0; i < TOP_N && top[i] != NULL; i++) {
204+
struct RefcBinary *refc = top[i];
205+
fprintf(stderr, " [%zu] size=%d bytes (%.1f%%), refcount=%d",
206+
top_indices[i],
207+
(int) refc->size,
208+
(double) refc->size * 100.0 / (double) total_size,
209+
(int) refc->ref_count);
210+
211+
if (refc->resource_type) {
212+
fprintf(stderr, " [resource]");
213+
}
214+
215+
// Print first 32 bytes as hex
216+
fprintf(stderr, "\n data: ");
217+
size_t print_size = refc->size < 32 ? refc->size : 32;
218+
for (size_t j = 0; j < print_size; j++) {
219+
fprintf(stderr, "%02x", refc->data[j]);
220+
if (j % 4 == 3 && j < print_size - 1) {
221+
fprintf(stderr, " ");
222+
}
223+
}
224+
if (refc->size > 32) {
225+
fprintf(stderr, "...");
226+
}
227+
fprintf(stderr, "\n");
228+
}
229+
230+
synclist_unlock(&ctx->global->refc_binaries);
231+
}

src/libAtomVM/refc_binary.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ term refc_binary_create_binary_info(Context *ctx);
142142
*/
143143
size_t refc_binary_total_size(Context *ctx);
144144

145+
/**
146+
* @brief Dump detailed information about reference counted binaries
147+
*
148+
* @details This function prints diagnostic information including the count,
149+
* total size, and details about the top 5 largest binaries including
150+
* their first bytes. Used for debugging memory issues.
151+
* @param ctx the context
152+
*/
153+
COLD_FUNC void refc_binary_dump_info(Context *ctx);
154+
145155
#ifdef __cplusplus
146156
}
147157
#endif

0 commit comments

Comments
 (0)