diff --git a/src/tests/allocs-within-mark.c b/src/tests/allocs-within-mark.c new file mode 100644 index 00000000..dda7a1d2 --- /dev/null +++ b/src/tests/allocs-within-mark.c @@ -0,0 +1,217 @@ +/* allocs-within-mark.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 +#include +#include +#include + +typedef struct +{ + gint64 begin; + gint64 end; + gint64 allocated; +} Interval; + +static gint +compare_interval (gconstpointer a, + gconstpointer b) +{ + const Interval *aptr = a; + const Interval *bptr = b; + + if (aptr->begin < bptr->begin) + return -1; + else if (aptr->begin > bptr->begin) + return 1; + + if (aptr->end < bptr->end) + return -1; + else if (aptr->end > bptr->end) + return 1; + + return 0; +} + +static gint +find_time_cb (gconstpointer key, + gconstpointer b) +{ + const Interval *keyptr = key; + const Interval *bptr = b; + + if (keyptr->begin >= bptr->begin && keyptr->end <= bptr->end) + return 0; + + return compare_interval (key, b); +} + +static inline Interval * +find_time (GArray *ar, + gint64 time) +{ + Interval key = {time, time, 0}; + + return bsearch (&key, ar->data, ar->len, sizeof (Interval), find_time_cb); +} + +static void +allocs_within_mark (SysprofCaptureReader *reader, + const gchar *category, + const gchar *name) +{ + g_autoptr(GArray) intervals = g_array_new (FALSE, FALSE, sizeof (Interval)); + SysprofCaptureFrameType type; + gint64 begin; + struct { + gint64 total; + gint64 min; + gint64 max; + } st = { 0, G_MAXINT64, G_MININT64 }; + + g_assert (reader); + g_assert (category); + g_assert (name); + + begin = sysprof_capture_reader_get_start_time (reader); + + while (sysprof_capture_reader_peek_type (reader, &type)) + { + if (type == SYSPROF_CAPTURE_FRAME_MARK) + { + const SysprofCaptureMark *ev; + Interval *iv; + + if (!(ev = sysprof_capture_reader_read_mark (reader))) + break; + + if (strcmp (category, ev->group) != 0 || + strcmp (name, ev->name) != 0) + continue; + + g_array_set_size (intervals, intervals->len + 1); + + iv = &g_array_index (intervals, Interval, intervals->len - 1); + iv->begin = ev->frame.time; + iv->end = ev->frame.time + ev->duration; + } + else if (!sysprof_capture_reader_skip (reader)) + break; + } + + g_array_sort (intervals, compare_interval); + + sysprof_capture_reader_reset (reader); + + while (sysprof_capture_reader_peek_type (reader, &type)) + { + if (type == SYSPROF_CAPTURE_FRAME_ALLOCATION) + { + const SysprofCaptureAllocation *ev; + Interval *iv; + + if (!(ev = sysprof_capture_reader_read_allocation (reader))) + break; + + if (ev->alloc_size <= 0) + continue; + + if (!(iv = find_time (intervals, ev->frame.time))) + continue; + + iv->allocated += ev->alloc_size; + } + else if (!sysprof_capture_reader_skip (reader)) + break; + } + + for (guint i = 0; i < intervals->len; i++) + { + const Interval *iv = &g_array_index (intervals, Interval, i); + g_autofree gchar *size = NULL; + gdouble t1; + gdouble t2; + + if (iv->allocated <= 0) + continue; + + st.total += iv->allocated; + st.min = MIN (st.min, iv->allocated); + st.max = MAX (st.max, iv->allocated); + + size = g_format_size_full (iv->allocated, G_FORMAT_SIZE_IEC_UNITS); + + t1 = (iv->begin - begin) / (gdouble)SYSPROF_NSEC_PER_SEC; + t2 = (iv->end - begin) / (gdouble)SYSPROF_NSEC_PER_SEC; + + g_print ("%lf-%lf: %s\n", + t1, t2, size); + } + + if (intervals->len) + { + g_autofree gchar *minstr = g_format_size_full (st.min, G_FORMAT_SIZE_IEC_UNITS); + g_autofree gchar *maxstr = g_format_size_full (st.max, G_FORMAT_SIZE_IEC_UNITS); + g_autofree gchar *avgstr = g_format_size_full (st.total/(gdouble)intervals->len, G_FORMAT_SIZE_IEC_UNITS); + + g_print ("Min: %s, Max: %s, Avg: %s\n", minstr, maxstr, avgstr); + } +} + +gint +main (gint argc, + gchar *argv[]) +{ + SysprofCaptureReader *reader; + const gchar *filename; + g_autoptr(GError) error = NULL; + const gchar *category; + const gchar *name; + + if (argc < 4) + { + g_printerr ("usage: %s FILENAME MARK_CATEGORY MARK_NAME\n", argv[0]); + return EXIT_FAILURE; + } + + filename = argv[1]; + category = argv[2]; + name = argv[3]; + + /* Set up gettext translations */ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + if (!(reader = sysprof_capture_reader_new (filename, &error))) + { + g_printerr ("%s\n", error->message); + return EXIT_FAILURE; + } + + allocs_within_mark (reader, category, name); + + sysprof_capture_reader_unref (reader); + + return EXIT_SUCCESS; +} diff --git a/src/tests/meson.build b/src/tests/meson.build index f1698185..2d8d8edb 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -81,6 +81,12 @@ allocs_by_size = executable('allocs-by-size', dependencies: test_deps, ) +allocs_within_mark = executable('allocs-within-mark', + ['allocs-within-mark.c'], + c_args: test_cflags, + dependencies: test_deps, +) + cross_thread_frees = executable('cross-thread-frees', ['cross-thread-frees.c'], c_args: test_cflags,