tests: add in-tree testing tool to list allocations within mark

This would be nice to have more generally useful via filters in the
allocations view. But for now, just make something simple work.
This commit is contained in:
Christian Hergert
2020-02-24 15:11:01 -08:00
parent d711c2a5ce
commit a9dcb58ca6
2 changed files with 223 additions and 0 deletions

View File

@ -0,0 +1,217 @@
/* allocs-within-mark.c
*
* Copyright 2020 Christian Hergert <chergert@redhat.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include <glib/gi18n.h>
#include <locale.h>
#include <stdlib.h>
#include <sysprof.h>
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;
}

View File

@ -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,