1
0
Fork 0
gnome-software/lib/gs-profiler.h
Daniel Baumann 68ee05b3fd
Adding upstream version 48.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 21:00:23 +02:00

153 lines
4.4 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
* vi:set noexpandtab tabstop=8 shiftwidth=8:
*
* Copyright (C) 2023 Endless OS Foundation LLC
*
* Authors:
* - Georges Basile Stavracas Neto <georges@endlessos.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "config.h"
#include <gnome-software.h>
/**
* SECTION:gs-profiler
* @short_description: Macros for profiling
*
* GNOME Software provides a simple profiling mechanism that both plugins
* and GNOME Software itself can make use. Use the GS_PROFILER_BEGIN_SCOPED()
* macro to start profiling a specific code section; and pair it with
* GS_PROFILER_END_SCOPED() to finish profiling the section:
*
* ```
* GS_PROFILER_BEGIN_SCOPED(Flatpak, "list-installed-refs", "Description");
* ... list all installed refs ...
* GS_PROFILER_END_SCOPED(Flatpak);
*
*
* GS_PROFILER_BEGIN_SCOPED(Foo, "parse-something", "Parse some data");
* ... parse some data ...
* GS_PROFILER_END_SCOPED(Foo);
* ```
*
* The macros are scoped, so work correctly with early returns in the middle:
*
* ```
* GS_PROFILER_BEGIN_SCOPED(Foo, "list-applications", NULL);
*
* if (!foo_is_correct (foo))
* return FALSE;
*
* if (!long_async_op (foo, &error))
* return FALSE;
*
* return TRUE;
*
* GS_PROFILER_END_SCOPED(Foo);
* ```
*
* The description argument is nullable:
*
* ```
* GS_PROFILER_BEGIN_SCOPED(Flatpak, "list-installed-refs", NULL);
* ... list all installed refs ...
* GS_PROFILER_END_SCOPED(Flatpak);
*```
*
* A rather common case is to allocate new strings for the Sysprof name
* and description. The convenience macro GS_PROFILER_BEGIN_SCOPED_TAKE() is
* provided for that:
*
* ```
* GS_PROFILER_BEGIN_SCOPED_TAKE(Foo, g_strdup_printf ("list-installed-refs:%s", name), NULL);
* ... list all installed refs ...
* GS_PROFILER_END_SCOPED(Foo);
*```
*
* Asynchronous operations might need to track the start and end times in
* separate functions. The convenience macros GS_PROFILER_ADD_MARK() and
* GS_PROFILER_ADD_MARK_TAKE() allow for passing an independent begin time:
*
* ```
* GS_PROFILER_ADD_MARK(Foo, task->begin_time, "do-something", NULL);
*```
*
* Since: 44
*/
#ifdef HAVE_SYSPROF
#include <sysprof-capture.h>
typedef struct
{
int64_t begin_time;
gchar *name;
gchar *description;
} GsProfilerHead;
static inline void
gs_profiler_tracing_end (GsProfilerHead *head)
{
sysprof_collector_mark (head->begin_time,
SYSPROF_CAPTURE_CURRENT_TIME - head->begin_time,
"gnome-software",
head->name,
head->description);
g_clear_pointer (&head->name, g_free);
g_clear_pointer (&head->description, g_free);
}
static inline void
gs_profiler_auto_trace_end_helper (GsProfilerHead **head)
{
if (*head)
gs_profiler_tracing_end (*head);
}
#define GS_PROFILER_BEGIN_SCOPED_TAKE(Name, sysprof_name, sysprof_description) \
G_STMT_START { \
GsProfilerHead GsProfiler##Name; \
__attribute__((cleanup (gs_profiler_auto_trace_end_helper))) \
GsProfilerHead *ScopedGsProfilerTraceHead##Name = &GsProfiler##Name; \
GsProfiler##Name = (GsProfilerHead) { \
.begin_time = SYSPROF_CAPTURE_CURRENT_TIME, \
.name = sysprof_name, \
.description = sysprof_description, \
};
#define GS_PROFILER_BEGIN_SCOPED(Name, sysprof_name, sysprof_description) \
GS_PROFILER_BEGIN_SCOPED_TAKE (Name, g_strdup (sysprof_name), g_strdup (sysprof_description))
#define GS_PROFILER_END_SCOPED(Name) \
} G_STMT_END
#define GS_PROFILER_ADD_MARK_TAKE(Name, begin_time, sysprof_name, sysprof_description) \
G_STMT_START { \
g_autofree char *_owned_sysprof_name_##Name = sysprof_name; \
g_autofree char *_owned_sysprof_description_##Name = sysprof_description; \
sysprof_collector_mark (begin_time, \
SYSPROF_CAPTURE_CURRENT_TIME - begin_time, \
"gnome-software", \
_owned_sysprof_name_##Name, \
_owned_sysprof_description_##Name); \
} G_STMT_END
#define GS_PROFILER_ADD_MARK(Name, begin_time, sysprof_name, sysprof_description) \
GS_PROFILER_ADD_MARK_TAKE (Name, begin_time, g_strdup (sysprof_name), g_strdup (sysprof_description))
#else
#define GS_PROFILER_BEGIN_SCOPED_TAKE(Name, sysprof_name, sysprof_description) \
G_STMT_START {
#define GS_PROFILER_BEGIN_SCOPED(Name, sysprof_name, sysprof_description) \
G_STMT_START {
#define GS_PROFILER_END_SCOPED(Name) \
} G_STMT_END
#define GS_PROFILER_ADD_MARK_TAKE(Name, begin_time, sysprof_name, sysprof_description)
#define GS_PROFILER_ADD_MARK(Name, begin_time, sysprof_name, sysprof_description)
#endif