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