1 /*
2 * Copyright © 2020 Endless Mobile, Inc.
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Philip Withnall <withnall@endlessm.com>
20 */
21
22 /*
23 * The performance tracing functions allow for the performance of code using
24 * GLib to be measured by passing metrics from the current process to an
25 * external measurement process such as `sysprof-cli` or `sysprofd`.
26 *
27 * They are designed to execute quickly, especially in the common case where no
28 * measurement process is connected. They are guaranteed to not block the caller
29 * and are guaranteed to have zero runtime cost if tracing support is disabled
30 * at configure time.
31 *
32 * Tracing information can be provided as ‘marks’ with a start time and
33 * duration; or as marks with a start time and no duration. Marks with a
34 * duration are intended to show the execution time of a piece of code. Marks
35 * with no duration are intended to show an instantaneous performance problem,
36 * such as an unexpectedly large allocation, or that a slow path has been taken
37 * in some code.
38 *
39 * |[<!-- language="C" -->
40 * gint64 begin_time_nsec G_GNUC_UNUSED;
41 *
42 * begin_time_nsec = G_TRACE_CURRENT_TIME;
43 *
44 * // some code which might take a while
45 *
46 * g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec,
47 * "GLib", "GSource.dispatch",
48 * "%s ⇒ %s", g_source_get_name (source), need_destroy ? "destroy" : "keep");
49 * ]|
50 *
51 * The tracing API is currently internal to GLib.
52 *
53 * Since: 2.66
54 */
55
56 #include "config.h"
57
58 #include "gtrace-private.h"
59
60 #include <stdarg.h>
61
62 /*
63 * g_trace_mark:
64 * @begin_time_nsec: start time of the mark, as returned by %G_TRACE_CURRENT_TIME
65 * @duration_nsec: duration of the mark, in nanoseconds
66 * @group: name of the group for categorising this mark
67 * @name: name of the mark
68 * @message_format: format for the detailed message for the mark, in `printf()` format
69 * @...: arguments to substitute into @message_format; none of these should have
70 * side effects
71 *
72 * Add a mark to the trace, starting at @begin_time_nsec and having length
73 * @duration_nsec (which may be zero). The @group should typically be `GLib`,
74 * and the @name should concisely describe the call site.
75 *
76 * All of the arguments to this function must not have side effects, as the
77 * entire function call may be dropped if sysprof support is not available.
78 *
79 * Since: 2.66
80 */
81 void
82 (g_trace_mark) (gint64 begin_time_nsec,
83 gint64 duration_nsec,
84 const gchar *group,
85 const gchar *name,
86 const gchar *message_format,
87 ...)
88 {
89 #ifdef HAVE_SYSPROF
90 va_list args;
91
92 va_start (args, message_format);
93 sysprof_collector_mark_vprintf (begin_time_nsec, duration_nsec, group, name, message_format, args);
94 va_end (args);
95 #endif /* HAVE_SYSPROF */
96 }
97
98 /*
99 * g_trace_define_int64_counter:
100 * @group: name of the group for categorising this counter
101 * @name: name of the counter
102 * @description: description for the counter
103 *
104 * Defines a new counter with integer values.
105 *
106 * The name should be unique within all counters defined with
107 * the same @group. The description will be shown in the sysprof UI.
108 *
109 * To add entries for this counter to a trace, use
110 * g_trace_set_int64_counter().
111 *
112 * Returns: ID of the counter, for use with g_trace_set_int64_counter(),
113 * guaranteed to never be zero
114 *
115 * Since: 2.68
116 */
117 guint
118 (g_trace_define_int64_counter) (const char *group,
119 const char *name,
120 const char *description)
121 {
122 #ifdef HAVE_SYSPROF
123 SysprofCaptureCounter counter;
124
125 counter.id = sysprof_collector_request_counters (1);
126
127 /* sysprof not enabled? */
128 if (counter.id == 0)
129 return (guint) -1;
130
131 counter.type = SYSPROF_CAPTURE_COUNTER_INT64;
132 counter.value.v64 = 0;
133 g_strlcpy (counter.category, group, sizeof counter.category);
134 g_strlcpy (counter.name, name, sizeof counter.name);
135 g_strlcpy (counter.description, description, sizeof counter.description);
136
137 sysprof_collector_define_counters (&counter, 1);
138
139 g_assert (counter.id != 0);
140
141 return counter.id;
142 #else
143 return (guint) -1;
144 #endif
145 }
146
147 /*
148 * g_trace_set_int64_counter:
149 * @id: ID of the counter
150 * @val: the value to set the counter to
151 *
152 * Adds a counter value to a trace.
153 *
154 * The ID must be obtained via g_trace_define_int64_counter()
155 * before using this function.
156 *
157 * Since: 2.68
158 */
159 void
160 (g_trace_set_int64_counter) (guint id,
161 gint64 val)
162 {
163 #ifdef HAVE_SYSPROF
164 SysprofCaptureCounterValue value;
165
166 g_return_if_fail (id != 0);
167
168 /* Ignore setting the counter if we failed to define it in the first place. */
169 if (id == (guint) -1)
170 return;
171
172 value.v64 = val;
173 sysprof_collector_set_counters (&id, &value, 1);
174 #endif
175 }