diff --git a/src/tests/find-temp-allocs.c b/src/tests/find-temp-allocs.c new file mode 100644 index 00000000..f2115e9d --- /dev/null +++ b/src/tests/find-temp-allocs.c @@ -0,0 +1,155 @@ +/* find-temp-allocs.c + * + * Copyright 2020 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +static struct { + gint64 total; + gint64 temp; + gint64 leaked; +} allocinfo; + +typedef struct +{ + gint pid; + gint tid; + SysprofCaptureAddress addr; + gint64 size; +} Alloc; + +static gint +compare_alloc (gconstpointer a, + gconstpointer b) +{ + const Alloc *aptr = a; + const Alloc *bptr = b; + + if (aptr->pid < bptr->pid) + return -1; + else if (aptr->pid > bptr->pid) + return 1; + + if (aptr->tid < bptr->tid) + return -1; + else if (aptr->tid > bptr->tid) + return 1; + + if (aptr->addr < bptr->addr) + return -1; + else if (aptr->addr > bptr->addr) + return 1; + else + return 0; +} + +static void +find_temp_allocs (SysprofCaptureReader *reader) +{ + g_autoptr(GArray) ar = NULL; + SysprofCaptureFrameType type; + SysprofCaptureAddress last_addr = 0; + + g_assert (reader != NULL); + + ar = g_array_new (FALSE, FALSE, sizeof (Alloc)); + + while (sysprof_capture_reader_peek_type (reader, &type)) + { + if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION) + { + const SysprofCaptureAllocation *ev; + Alloc a; + + if (!(ev = sysprof_capture_reader_read_allocation (reader))) + break; + + a.pid = ev->frame.pid; + a.tid = ev->tid; + a.addr = ev->alloc_addr; + a.size = ev->alloc_size; + + g_array_append_val (ar, a); + } + else + { + if (!sysprof_capture_reader_skip (reader)) + break; + } + } + + /* Ensure items are in order because threads may have + * reordered things and raced to write out malloc data. + */ + g_array_sort (ar, compare_alloc); + + for (guint i = 0; i < ar->len; i++) + { + const Alloc *a = &g_array_index (ar, Alloc, i); + + if (a->size <= 0) + { + if (last_addr == a->addr) + allocinfo.temp++; + + allocinfo.leaked--; + last_addr = 0; + } + else + { + allocinfo.total++; + allocinfo.leaked++; + last_addr = a->addr; + } + } + + g_printerr ("Allocations: %"G_GUINT64_FORMAT"\n", allocinfo.total); + g_printerr (" Temporary: %"G_GUINT64_FORMAT" (%lf%%)\n", + allocinfo.temp, allocinfo.temp / (gdouble)allocinfo.total * 100.0); + g_printerr (" Leaked: %"G_GUINT64_FORMAT"\n", allocinfo.leaked); +} + +gint +main (gint argc, + gchar *argv[]) +{ + SysprofCaptureReader *reader; + const gchar *filename = argv[1]; + g_autoptr(GError) error = NULL; + + if (argc < 2) + { + g_printerr ("usage: %s FILENAME\n", argv[0]); + return EXIT_FAILURE; + } + + if (!(reader = sysprof_capture_reader_new (filename, &error))) + { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + + find_temp_allocs (reader); + + sysprof_capture_reader_unref (reader); + + return EXIT_SUCCESS; +} diff --git a/src/tests/meson.build b/src/tests/meson.build index 7138bd79..f1698185 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -27,6 +27,11 @@ test_mapped_ring_buffer = executable('test-mapped-ring-buffer', 'test-mapped-rin dependencies: [libsysprof_capture_dep], ) +find_temp_allocs = executable('find-temp-allocs', 'find-temp-allocs.c', + c_args: test_cflags, + dependencies: [libsysprof_capture_dep], +) + test('test-capture', test_capture, env: test_env) test('test-capture-cursor', test_capture_cursor, env: test_env) test('test-mapped-ring-buffer', test_mapped_ring_buffer, env: test_env)