summaryrefslogtreecommitdiff
path: root/glib/gtrace.c
blob: 0ca1bb418ccf0121a586f38429e3ef871b8fbde3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * Copyright © 2020 Endless Mobile, Inc.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Philip Withnall <withnall@endlessm.com>
 */

/*
 * SECTION:trace
 * @Title: Performance tracing
 * @Short_description: Functions for measuring and tracing performance
 *
 * The performance tracing functions allow for the performance of code using
 * GLib to be measured by passing metrics from the current process to an
 * external measurement process such as `sysprof-cli` or `sysprofd`.
 *
 * They are designed to execute quickly, especially in the common case where no
 * measurement process is connected. They are guaranteed to not block the caller
 * and are guaranteed to have zero runtime cost if tracing support is disabled
 * at configure time.
 *
 * Tracing information can be provided as ‘marks’ with a start time and
 * duration; or as marks with a start time and no duration. Marks with a
 * duration are intended to show the execution time of a piece of code. Marks
 * with no duration are intended to show an instantaneous performance problem,
 * such as an unexpectedly large allocation, or that a slow path has been taken
 * in some code.
 *
 * |[<!-- language="C" -->
 * gint64 begin_time_nsec G_GNUC_UNUSED;
 *
 * begin_time_nsec = G_TRACE_CURRENT_TIME;
 *
 * // some code which might take a while
 *
 * g_trace_mark (begin_time_nsec, G_TRACE_CURRENT_TIME - begin_time_nsec,
 *               "GLib", "GSource.dispatch",
 *               "%s ⇒ %s", g_source_get_name (source), need_destroy ? "destroy" : "keep");
 * ]|
 *
 * The tracing API is currently internal to GLib.
 *
 * Since: 2.66
 */

#include "config.h"

#include "gtrace-private.h"

#include <stdarg.h>

/*
 * g_trace_mark:
 * @begin_time_nsec: start time of the mark, as returned by %G_TRACE_CURRENT_TIME
 * @duration_nsec: duration of the mark, in nanoseconds
 * @group: name of the group for categorising this mark
 * @name: name of the mark
 * @message_format: format for the detailed message for the mark, in `printf()` format
 * @...: arguments to substitute into @message_format; none of these should have
 *    side effects
 *
 * Add a mark to the trace, starting at @begin_time_nsec and having length
 * @duration_nsec (which may be zero). The @group should typically be `GLib`,
 * and the @name should concisely describe the call site.
 *
 * All of the arguments to this function must not have side effects, as the
 * entire function call may be dropped if sysprof support is not available.
 *
 * Since: 2.66
 */
void
(g_trace_mark) (gint64       begin_time_nsec,
                gint64       duration_nsec,
                const gchar *group,
                const gchar *name,
                const gchar *message_format,
                ...)
{
#ifdef HAVE_SYSPROF
  va_list args;

  va_start (args, message_format);
  sysprof_collector_mark_vprintf (begin_time_nsec, duration_nsec, group, name, message_format, args);
  va_end (args);
#endif  /* HAVE_SYSPROF */
}

/*
 * g_trace_define_int64_counter:
 * @group: name of the group for categorising this counter
 * @name: name of the counter
 * @description: description for the counter
 *
 * Defines a new counter with integer values.
 *
 * The name should be unique within all counters defined with
 * the same @group. The description will be shown in the sysprof UI.
 *
 * To add entries for this counter to a trace, use
 * g_trace_set_int64_counter().
 *
 * Returns: ID of the counter, for use with g_trace_set_int64_counter(),
 *     guaranteed to never be zero
 *
 * Since: 2.68
 */
guint
(g_trace_define_int64_counter) (const char *group,
                                const char *name,
                                const char *description)
{
#ifdef HAVE_SYSPROF
  SysprofCaptureCounter counter;

  counter.id = sysprof_collector_request_counters (1);

  /* sysprof not enabled? */
  if (counter.id == 0)
    return (guint) -1;

  counter.type = SYSPROF_CAPTURE_COUNTER_INT64;
  counter.value.v64 = 0;
  g_strlcpy (counter.category, group, sizeof counter.category);
  g_strlcpy (counter.name, name, sizeof counter.name);
  g_strlcpy (counter.description, description, sizeof counter.description);

  sysprof_collector_define_counters (&counter, 1);

  g_assert (counter.id != 0);

  return counter.id;
#else
  return (guint) -1;
#endif
}

/*
 * g_trace_set_int64_counter:
 * @id: ID of the counter
 * @val: the value to set the counter to
 *
 * Adds a counter value to a trace.
 *
 * The ID must be obtained via g_trace_define_int64_counter()
 * before using this function.
 *
 * Since: 2.68
 */
void
(g_trace_set_int64_counter) (guint  id,
                             gint64 val)
{
#ifdef HAVE_SYSPROF
  SysprofCaptureCounterValue value;

  g_return_if_fail (id != 0);

  /* Ignore setting the counter if we failed to define it in the first place. */
  if (id == (guint) -1)
    return;

  value.v64 = val;
  sysprof_collector_set_counters (&id, &value, 1);
#endif
}