Files
sysprof/src/libsysprof-capture/sysprof-collector.c
Christian Hergert 3a94170b0a libsysprof-capture: add frame type for tracing
This is like sample but has an "enter/exit" flag with it. This can be
useful when you want to provide tracing instead of sampling. We use a
different frame type so that we can denote that this isn't traditional
sampling, and the flag can be used to find the next exit for the current
enter for calculating durations.

The entire stack trace is provided to make things easier on tools
which may want to deal with indirect functions that were not instrumented
but can be unwound. That may allow for tooling to give the user some
insight that it's not *just* this function entering, but some functions
before it were entered too.

This also adds a SysprofTracer instrument which will preload a
libsysprof-tracer-6.so into the process providing the
__cyg_profile_func_enter() and __cyg_profile_func_leave() hooks.
2023-06-13 12:41:50 -07:00

917 lines
25 KiB
C

/* sysprof-collector.c
*
* Copyright 2020 Christian Hergert <chergert@redhat.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Subject to the terms and conditions of this license, each copyright holder
* and contributor hereby grants to those receiving rights under this license
* a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
* irrevocable (except for failure to satisfy the conditions of this license)
* patent license to make, have made, use, offer to sell, sell, import, and
* otherwise transfer this software, where such license applies only to those
* patent claims, already acquired or hereafter acquired, licensable by such
* copyright holder or contributor that are necessarily infringed by:
*
* (a) their Contribution(s) (the licensed copyrights of copyright holders
* and non-copyrightable additions of contributors, in source or binary
* form) alone; or
*
* (b) combination of their Contribution(s) with the work of authorship to
* which such Contribution(s) was added by such copyright holder or
* contributor, if, at the time the Contribution is added, such addition
* causes such combination to be necessarily infringed. The patent license
* shall not apply to any other combinations which include the
* Contribution.
*
* Except as expressly stated above, no rights or licenses from any copyright
* holder or contributor is granted under this license, whether expressly, by
* implication, estoppel or otherwise.
*
* DISCLAIMER
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#ifdef __linux__
# include <sched.h>
#endif
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include "mapped-ring-buffer.h"
#include "sysprof-capture-util-private.h"
#include "sysprof-collector.h"
#include "sysprof-macros-internal.h"
#define MAX_UNWIND_DEPTH 128
#define CREATRING "CreatRing\0"
#define CREATRING_LEN 10
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
#ifndef MSG_CMSG_CLOEXEC
#define MSG_CMSG_CLOEXEC 0
#endif
typedef struct
{
MappedRingBuffer *buffer;
bool is_shared;
int tid;
int pid;
int next_counter_id;
} SysprofCollector;
#define COLLECTOR_INVALID ((void *)&invalid)
static MappedRingBuffer *request_writer (void);
static void sysprof_collector_free (void *data);
static const SysprofCollector *sysprof_collector_get (void);
static pthread_mutex_t control_fd_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t collector_key; /* initialised in sysprof_collector_init() */
static pthread_key_t single_trace_key; /* initialised in sysprof_collector_init() */
static pthread_once_t collector_init = PTHREAD_ONCE_INIT;
static SysprofCollector *shared_collector;
static SysprofCollector invalid;
static inline bool
use_single_trace (void)
{
return (bool) pthread_getspecific (single_trace_key);
}
static inline int
_do_getcpu (void)
{
#ifdef __linux__
return sched_getcpu ();
#else
return -1;
#endif
}
static inline size_t
realign (size_t size)
{
return (size + SYSPROF_CAPTURE_ALIGN - 1) & ~(SYSPROF_CAPTURE_ALIGN - 1);
}
static bool
set_fd_blocking (int fd)
{
#ifdef F_GETFL
long fcntl_flags;
fcntl_flags = fcntl (peer_fd, F_GETFL);
if (fcntl_flags == -1)
return false;
#ifdef O_NONBLOCK
fcntl_flags &= ~O_NONBLOCK;
#else
fcntl_flags &= ~O_NDELAY;
#endif
if (fcntl (peer_fd, F_SETFL, fcntl_flags) == -1)
return false;
return true;
#else
return false;
#endif
}
static bool
block_on_poll (int fd,
int condition)
{
struct pollfd poll_fd;
poll_fd.fd = fd;
poll_fd.events = condition;
return (TEMP_FAILURE_RETRY (poll (&poll_fd, 1, -1)) == 1);
}
static ssize_t
send_blocking (int fd,
const uint8_t *buffer,
size_t buffer_len)
{
ssize_t res;
while ((res = TEMP_FAILURE_RETRY (send (fd, buffer, buffer_len, MSG_NOSIGNAL))) < 0)
{
int errsv = errno;
if (errsv == EWOULDBLOCK ||
errsv == EAGAIN)
{
if (!block_on_poll (fd, POLLOUT))
return -1;
}
else
{
return -1;
}
}
return res;
}
static bool
send_all_blocking (int fd,
const uint8_t *buffer,
size_t buffer_len,
size_t *bytes_written)
{
size_t _bytes_written;
_bytes_written = 0;
while (_bytes_written < buffer_len)
{
ssize_t res = send_blocking (fd, buffer + _bytes_written, buffer_len - _bytes_written);
if (res == -1)
{
if (bytes_written != NULL)
*bytes_written = _bytes_written;
return false;
}
assert (res > 0);
_bytes_written += res;
}
if (bytes_written != NULL)
*bytes_written = _bytes_written;
return true;
}
static int
receive_fd_blocking (int peer_fd)
{
ssize_t res;
struct msghdr msg;
struct iovec one_vector;
char one_byte;
uint8_t cmsg_buffer[CMSG_SPACE (sizeof (int))];
struct cmsghdr *cmsg;
const int *fds = NULL;
size_t n_fds = 0;
one_vector.iov_base = &one_byte;
one_vector.iov_len = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &one_vector;
msg.msg_iovlen = 1;
msg.msg_flags = MSG_CMSG_CLOEXEC;
msg.msg_control = &cmsg_buffer;
msg.msg_controllen = sizeof (cmsg_buffer);
while ((res = TEMP_FAILURE_RETRY (recvmsg (peer_fd, &msg, msg.msg_flags))) < 0)
{
int errsv = errno;
if (errsv == EWOULDBLOCK ||
errsv == EAGAIN)
{
if (!block_on_poll (peer_fd, POLLIN))
return -1;
}
else
{
return -1;
}
}
/* Decode the returned control message */
cmsg = CMSG_FIRSTHDR (&msg);
if (cmsg == NULL)
return -1;
if (cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS)
return -1;
/* non-integer number of FDs */
if ((cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg)) % 4 != 0)
return -1;
fds = (const int *)(void *)CMSG_DATA (cmsg);
n_fds = (cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg)) / sizeof (*fds);
/* only expecting one FD */
if (n_fds != 1)
goto close_fds_err;
for (size_t i = 0; i < n_fds; i++)
{
if (fds[i] < 0)
goto close_fds_err;
}
/* only expecting one control message */
cmsg = CMSG_NXTHDR (&msg, cmsg);
if (cmsg != NULL)
goto close_fds_err;
return fds[0];
close_fds_err:
for (size_t i = 0; i < n_fds; i++)
close (fds[i]);
return -1;
}
/* Called with @control_fd_lock held. */
static MappedRingBuffer *
request_writer (void)
{
static int peer_fd = -1;
MappedRingBuffer *buffer = NULL;
if (peer_fd == -1)
{
const char *fdstr = getenv ("SYSPROF_CONTROL_FD");
if (fdstr != NULL)
peer_fd = atoi (fdstr);
if (peer_fd > 0)
{
(void) set_fd_blocking (peer_fd);
#ifdef SO_NOSIGPIPE
{
int opt_value = 1;
(void) setsockopt (peer_fd, SOL_SOCKET, SO_NOSIGPIPE, &opt_value, sizeof (opt_value));
}
#endif
}
}
if (peer_fd >= 0)
{
if (send_all_blocking (peer_fd, (const uint8_t *) CREATRING, CREATRING_LEN, NULL))
{
int ring_fd = receive_fd_blocking (peer_fd);
if (ring_fd >= 0)
{
buffer = mapped_ring_buffer_new_writer (ring_fd);
close (ring_fd);
}
}
}
return sysprof_steal_pointer (&buffer);
}
static void
write_final_frame (MappedRingBuffer *ring)
{
SysprofCaptureFrame *fr;
assert (ring != NULL);
if ((fr = mapped_ring_buffer_allocate (ring, sizeof *fr)))
{
fr->len = sizeof *fr; /* aligned */
fr->type = 0xFF; /* Invalid */
fr->cpu = -1;
fr->pid = -1;
fr->time = SYSPROF_CAPTURE_CURRENT_TIME;
mapped_ring_buffer_advance (ring, fr->len);
}
}
static void
sysprof_collector_free (void *data)
{
SysprofCollector *collector = data;
if (collector != NULL && collector != COLLECTOR_INVALID)
{
MappedRingBuffer *buffer = sysprof_steal_pointer (&collector->buffer);
if (buffer != NULL)
{
write_final_frame (buffer);
mapped_ring_buffer_unref (buffer);
}
free (collector);
}
}
static const SysprofCollector *
sysprof_collector_get (void)
{
const SysprofCollector *collector;
sysprof_collector_init ();
collector = pthread_getspecific (collector_key);
/* We might have gotten here recursively */
if SYSPROF_UNLIKELY (collector == COLLECTOR_INVALID)
return COLLECTOR_INVALID;
if SYSPROF_LIKELY (collector != NULL)
return collector;
if (use_single_trace () && shared_collector != COLLECTOR_INVALID)
return shared_collector;
{
SysprofCollector *self, *old_collector;
/* First set the collector to invalid so anything recursive
* here fails instead of becoming re-entrant.
*/
pthread_setspecific (collector_key, COLLECTOR_INVALID);
/* Now we can malloc without ending up here again */
self = sysprof_malloc0 (sizeof (SysprofCollector));
if (self == NULL)
return COLLECTOR_INVALID;
self->pid = getpid ();
#ifdef __linux__
self->tid = syscall (__NR_gettid, 0);
#else
self->tid = self->pid;
#endif
self->next_counter_id = 1;
pthread_mutex_lock (&control_fd_lock);
if (getenv ("SYSPROF_CONTROL_FD") != NULL)
self->buffer = request_writer ();
/* Update the stored collector */
old_collector = pthread_getspecific (collector_key);
if (self->is_shared)
{
if (pthread_setspecific (collector_key, COLLECTOR_INVALID) != 0)
goto fail;
sysprof_collector_free (old_collector);
shared_collector = self;
}
else
{
if (pthread_setspecific (collector_key, self) != 0)
goto fail;
sysprof_collector_free (old_collector);
}
pthread_mutex_unlock (&control_fd_lock);
return self;
fail:
pthread_mutex_unlock (&control_fd_lock);
sysprof_collector_free (self);
return COLLECTOR_INVALID;
}
}
static void
collector_init_cb (void)
{
if (SYSPROF_UNLIKELY (pthread_key_create (&collector_key, sysprof_collector_free) != 0))
abort ();
if (SYSPROF_UNLIKELY (pthread_key_create (&single_trace_key, NULL) != 0))
abort ();
sysprof_clock_init ();
}
void
sysprof_collector_init (void)
{
if SYSPROF_UNLIKELY (pthread_once (&collector_init, collector_init_cb) != 0)
abort ();
}
#define COLLECTOR_BEGIN \
do { \
const SysprofCollector *collector = sysprof_collector_get (); \
if SYSPROF_LIKELY (collector->buffer) \
{ \
if SYSPROF_UNLIKELY (collector->is_shared) \
pthread_mutex_lock (&control_fd_lock); \
\
{
#define COLLECTOR_END \
} \
\
if SYSPROF_UNLIKELY (collector->is_shared) \
pthread_mutex_unlock (&control_fd_lock); \
} \
} while (0)
void
sysprof_collector_allocate (SysprofCaptureAddress alloc_addr,
int64_t alloc_size,
SysprofBacktraceFunc backtrace_func,
void *backtrace_data)
{
COLLECTOR_BEGIN {
SysprofCaptureAllocation *ev;
size_t len;
len = sizeof *ev + (sizeof (SysprofCaptureAllocation) * MAX_UNWIND_DEPTH);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
int n_addrs;
/* First take a backtrace, so that backtrace_func() can overwrite
* a little bit of data *BEFORE* ev->addrs as stratch space. This
* is useful to allow using unw_backtrace() or backtrace() to skip
* a small number of frames.
*
* We fill in all the other data afterwards which overwrites that
* scratch space anyway.
*/
if (backtrace_func)
n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data);
else
n_addrs = 0;
ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs);
ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs;
ev->frame.type = SYSPROF_CAPTURE_FRAME_ALLOCATION;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
ev->tid = collector->tid;
ev->alloc_addr = alloc_addr;
ev->alloc_size = alloc_size;
ev->padding1 = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_sample (SysprofBacktraceFunc backtrace_func,
void *backtrace_data)
{
COLLECTOR_BEGIN {
SysprofCaptureSample *ev;
size_t len;
len = sizeof *ev + (sizeof (SysprofCaptureSample) * MAX_UNWIND_DEPTH);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
int n_addrs;
/* See comment from sysprof_collector_allocate(). */
if (backtrace_func)
n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data);
else
n_addrs = 0;
ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs);
ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs;
ev->frame.type = SYSPROF_CAPTURE_FRAME_SAMPLE;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
ev->tid = collector->tid;
ev->padding1 = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_trace (SysprofBacktraceFunc backtrace_func,
void *backtrace_data,
bool entering)
{
COLLECTOR_BEGIN {
SysprofCaptureTrace *ev;
size_t len;
len = sizeof *ev + (sizeof (SysprofCaptureTrace) * MAX_UNWIND_DEPTH);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
int n_addrs;
/* See comment from sysprof_collector_allocate(). */
if (backtrace_func)
n_addrs = backtrace_func (ev->addrs, MAX_UNWIND_DEPTH, backtrace_data);
else
n_addrs = 0;
ev->n_addrs = ((n_addrs < 0) ? 0 : (n_addrs > MAX_UNWIND_DEPTH) ? MAX_UNWIND_DEPTH : n_addrs);
ev->frame.len = sizeof *ev + sizeof (SysprofCaptureAddress) * ev->n_addrs;
ev->frame.type = SYSPROF_CAPTURE_FRAME_TRACE;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
ev->tid = collector->tid;
ev->entering = !!entering;
ev->padding1 = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_mark (int64_t time,
int64_t duration,
const char *group,
const char *mark,
const char *message)
{
COLLECTOR_BEGIN {
SysprofCaptureMark *ev;
size_t len;
size_t sl;
if (group == NULL)
group = "";
if (mark == NULL)
mark = "";
if (message == NULL)
message = "";
sl = strlen (message);
len = realign (sizeof *ev + sl + 1);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
ev->frame.len = len;
ev->frame.type = SYSPROF_CAPTURE_FRAME_MARK;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = time;
ev->duration = duration;
_sysprof_strlcpy (ev->group, group, sizeof ev->group);
_sysprof_strlcpy (ev->name, mark, sizeof ev->name);
memcpy (ev->message, message, sl);
ev->message[sl] = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_mark_printf (int64_t time,
int64_t duration,
const char *group,
const char *mark,
const char *message_format,
...)
{
va_list args;
va_start (args, message_format);
sysprof_collector_mark_vprintf (time, duration, group, mark, message_format, args);
va_end (args);
}
void
sysprof_collector_mark_vprintf (int64_t time,
int64_t duration,
const char *group,
const char *mark,
const char *message_format,
va_list args)
{
COLLECTOR_BEGIN {
SysprofCaptureMark *ev;
size_t len;
size_t sl;
va_list args2;
/* Need to take a copy of @args since we iterate through it twice, once to
* work out the formatted string length, and once to format it. */
va_copy (args2, args);
if (group == NULL)
group = "";
if (mark == NULL)
mark = "";
if (message_format == NULL)
message_format = "";
/* Work out the formatted message length */
sl = vsnprintf (NULL, 0, message_format, args);
len = realign (sizeof *ev + sl + 1);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
ev->frame.len = len;
ev->frame.type = SYSPROF_CAPTURE_FRAME_MARK;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = time;
ev->duration = duration;
_sysprof_strlcpy (ev->group, group, sizeof ev->group);
_sysprof_strlcpy (ev->name, mark, sizeof ev->name);
vsnprintf (ev->message, sl + 1, message_format, args2);
ev->message[sl] = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
va_end (args2);
} COLLECTOR_END;
}
void
sysprof_collector_log (int severity,
const char *domain,
const char *message)
{
COLLECTOR_BEGIN {
SysprofCaptureLog *ev;
size_t len;
size_t sl;
if (domain == NULL)
domain = "";
if (message == NULL)
message = "";
sl = strlen (message);
len = realign (sizeof *ev + sl + 1);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
ev->frame.len = len;
ev->frame.type = SYSPROF_CAPTURE_FRAME_LOG;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
ev->severity = severity & 0xFFFF;
ev->padding1 = 0;
ev->padding2 = 0;
_sysprof_strlcpy (ev->domain, domain, sizeof ev->domain);
memcpy (ev->message, message, sl);
ev->message[sl] = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_log_printf (int severity,
const char *domain,
const char *format,
...)
{
COLLECTOR_BEGIN {
char formatted[2048];
SysprofCaptureLog *ev;
va_list args;
size_t len;
size_t sl;
va_start (args, format);
vsnprintf (formatted, sizeof (formatted), format, args);
va_end (args);
if (domain == NULL)
domain = "";
sl = strlen (formatted);
len = realign (sizeof *ev + sl + 1);
if ((ev = mapped_ring_buffer_allocate (collector->buffer, len)))
{
ev->frame.len = len;
ev->frame.type = SYSPROF_CAPTURE_FRAME_LOG;
ev->frame.cpu = _do_getcpu ();
ev->frame.pid = collector->pid;
ev->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
ev->severity = severity & 0xFFFF;
ev->padding1 = 0;
ev->padding2 = 0;
_sysprof_strlcpy (ev->domain, domain, sizeof ev->domain);
memcpy (ev->message, formatted, sl);
ev->message[sl] = 0;
mapped_ring_buffer_advance (collector->buffer, ev->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_define_counters (const SysprofCaptureCounter *counters,
unsigned int n_counters)
{
if (counters == NULL || n_counters == 0)
return;
COLLECTOR_BEGIN {
SysprofCaptureCounterDefine *def;
size_t len;
len = realign (sizeof *def + (sizeof *counters * n_counters));
if ((def = mapped_ring_buffer_allocate (collector->buffer, len)))
{
def->frame.len = len;
def->frame.type = SYSPROF_CAPTURE_FRAME_CTRDEF;
def->frame.cpu = _do_getcpu ();
def->frame.pid = collector->pid;
def->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
def->padding1 = 0;
def->padding2 = 0;
def->n_counters = n_counters;
memcpy (def->counters, counters, sizeof *counters * n_counters);
mapped_ring_buffer_advance (collector->buffer, def->frame.len);
}
} COLLECTOR_END;
}
void
sysprof_collector_set_counters (const unsigned int *counters_ids,
const SysprofCaptureCounterValue *values,
unsigned int n_counters)
{
if (n_counters == 0)
return;
COLLECTOR_BEGIN {
SysprofCaptureCounterSet *set;
size_t len;
unsigned int n_groups;
unsigned int group;
unsigned int field;
unsigned int i;
/* Determine how many value groups we need */
n_groups = n_counters / SYSPROF_N_ELEMENTS (set->values[0].values);
if ((n_groups * SYSPROF_N_ELEMENTS (set->values[0].values)) != n_counters)
n_groups++;
len = realign (sizeof *set + (n_groups * sizeof (SysprofCaptureCounterValues)));
if ((set = mapped_ring_buffer_allocate (collector->buffer, len)))
{
set->frame.len = len;
set->frame.type = SYSPROF_CAPTURE_FRAME_CTRSET;
set->frame.cpu = _do_getcpu ();
set->frame.pid = collector->pid;
set->frame.time = SYSPROF_CAPTURE_CURRENT_TIME;
set->padding1 = 0;
set->padding2 = 0;
set->n_values = n_groups;
for (i = 0, group = 0, field = 0; i < n_counters; i++)
{
set->values[group].ids[field] = counters_ids[i];
set->values[group].values[field] = values[i];
field++;
if (field == SYSPROF_N_ELEMENTS (set->values[0].values))
{
field = 0;
group++;
}
}
mapped_ring_buffer_advance (collector->buffer, set->frame.len);
}
} COLLECTOR_END;
}
unsigned int
sysprof_collector_request_counters (unsigned int n_counters)
{
unsigned int ret = 0;
if (n_counters == 0)
return 0;
COLLECTOR_BEGIN {
ret = collector->next_counter_id;
((SysprofCollector *)collector)->next_counter_id += n_counters;
} COLLECTOR_END;
return ret;
}
bool
sysprof_collector_is_active (void)
{
bool ret = false;
COLLECTOR_BEGIN {
ret = true;
} COLLECTOR_END;
return ret;
}