/* -*- 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 * * SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "config.h" #include /** * 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 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