diff --git a/config.h.meson b/config.h.meson index ce1c9a6..198c84c 100644 --- a/config.h.meson +++ b/config.h.meson @@ -7,3 +7,4 @@ #mesondefine HAVE_FUNC_ATTRIBUTE_VISIBILITY #mesondefine HAVE_EVENTFD_H #mesondefine HAVE_DLFCN_H +#mesondefine ENABLE_TRACING diff --git a/meson.build b/meson.build index 440ea24..f4d1c04 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,20 @@ m_dep = cc.find_library('m') conf_data = configuration_data() conf_data.set('VERSION', '0.8.1') +with_tracing = get_option('tracing') + +if with_tracing != 'none' + if not cc.compiles('void f(void* v){}; int main () { void *dummy __attribute__((cleanup (f))) = 0;}') + error('Tracing requires compiler support for __attribute__((cleanup))') +endif + +endif + +if with_tracing == 'perfetto' + vperfetto_min_dep = dependency('vperfetto_min') + conf_data.set('ENABLE_TRACING', 'TRACE_WITH_PERFETTO') +endif + if cc.has_header('sys/uio.h') conf_data.set('HAVE_SYS_UIO_H', 1) endif @@ -199,6 +213,7 @@ lines += 'minigbm_alloc: ' + (with_minigbm_allocation ? 'yes' : 'no' ) lines += '' lines += 'tests: ' + (with_tests ? 'yes' : 'no' ) lines += 'fuzzer: ' + (with_fuzzer ? 'yes' : 'no' ) +lines += 'tracing: ' + with_tracing indent = ' ' summary = indent + ('\n' + indent).join(lines) diff --git a/meson_options.txt b/meson_options.txt index 9d7e5b5..e7f3e12 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -58,3 +58,11 @@ option( value : 'false', description : 'enable running unit tests with valgrind' ) + +option( + 'tracing', + type : 'combo', + value : 'none', + choices : [ 'perfetto', 'none' ], + description : 'enable emitting traces for Perfetto' +) diff --git a/src/meson.build b/src/meson.build index 297726b..d854027 100644 --- a/src/meson.build +++ b/src/meson.build @@ -79,9 +79,13 @@ virgl_depends = [ epoxy_dep, libdrm_dep, thread_dep, - m_dep + m_dep, ] +if with_tracing == 'perfetto' + virgl_depends += [vperfetto_min_dep] +endif + virgl_sources += vrend_sources if have_egl diff --git a/src/virgl_util.c b/src/virgl_util.c index 2f30be8..0267acc 100644 --- a/src/virgl_util.c +++ b/src/virgl_util.c @@ -36,6 +36,17 @@ #include "util/u_pointer.h" +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if ENABLE_TRACING == TRACE_WITH_PERFETTO +#include +#endif + unsigned hash_func_u32(void *key) { intptr_t ip = pointer_to_intptr(key); @@ -98,3 +109,33 @@ void flush_eventfd(int fd) len = read(fd, &value, sizeof(value)); } while ((len == -1 && errno == EINTR) || len == sizeof(value)); } + +#if ENABLE_TRACING == TRACE_WITH_PERFETTO +void trace_init(void) +{ + struct vperfetto_min_config config = { + .init_flags = VPERFETTO_INIT_FLAG_USE_SYSTEM_BACKEND, + .filename = NULL, + .shmem_size_hint_kb = 32 * 1024, + }; + + vperfetto_min_startTracing(&config); +} + +char *trace_begin(const char* format, ...) +{ + char buffer[1024]; + va_list args; + va_start (args, format); + vsnprintf (buffer, sizeof(buffer), format, args); + va_end (args); + vperfetto_min_beginTrackEvent_VMM(buffer); + return (void *)1; +} + +void trace_end(char **dummy) +{ + (void)dummy; + vperfetto_min_endTrackEvent_VMM(); +} +#endif diff --git a/src/virgl_util.h b/src/virgl_util.h index cdb5778..29d6fed 100644 --- a/src/virgl_util.h +++ b/src/virgl_util.h @@ -28,6 +28,13 @@ #include #include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define TRACE_WITH_PERFETTO 1 + + #define BIT(n) (UINT32_C(1) << (n)) static inline bool has_bit(uint32_t mask, uint32_t bit) @@ -54,4 +61,24 @@ int create_eventfd(unsigned int initval); int write_eventfd(int fd, uint64_t val); void flush_eventfd(int fd); +#ifdef ENABLE_TRACING +void trace_init(void); +char *trace_begin(const char* format, ...); +void trace_end(char **dummy); + +#define TRACE_INIT() trace_init() +#define TRACE_FUNC() \ + char *trace_dummy __attribute__((cleanup (trace_end), unused)) = \ + trace_begin("%s", __func__) + +#define TRACE_SCOPE(FORMAT, ...) \ + char *trace_dummy __attribute__((cleanup (trace_end), unused)) = \ + trace_begin(FORMAT, __VA_ARGS__) + +#else +#define TRACE_INIT() +#define TRACE_FUNC() +#define TRACE_SCOPE(FORMAT, ...) +#endif + #endif /* VIRGL_UTIL_H */ diff --git a/src/virglrenderer.c b/src/virglrenderer.c index b09e2a2..8458b21 100644 --- a/src/virglrenderer.c +++ b/src/virglrenderer.c @@ -31,6 +31,7 @@ #include #include #include + #include "pipe/p_state.h" #include "util/u_format.h" #include "util/u_math.h" @@ -99,11 +100,13 @@ static int virgl_renderer_resource_create_internal(struct virgl_renderer_resourc int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs) { + TRACE_FUNC(); return virgl_renderer_resource_create_internal(args, iov, num_iovs, NULL); } int virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args *args, void *image) { + TRACE_FUNC(); return virgl_renderer_resource_create_internal(args, NULL, 0, image); } @@ -165,6 +168,8 @@ int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *na struct virgl_context *ctx; int ret; + TRACE_FUNC(); + /* user context id must be greater than 0 */ if (handle == 0) return EINVAL; @@ -187,6 +192,7 @@ int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *na void virgl_renderer_context_destroy(uint32_t handle) { + TRACE_FUNC(); virgl_context_remove(handle); } @@ -194,6 +200,7 @@ int virgl_renderer_submit_cmd(void *buffer, int ctx_id, int ndw) { + TRACE_FUNC(); struct virgl_context *ctx = virgl_context_lookup(ctx_id); if (!ctx) return EINVAL; @@ -210,6 +217,8 @@ int virgl_renderer_transfer_write_iov(uint32_t handle, struct iovec *iovec, unsigned int iovec_cnt) { + TRACE_FUNC(); + struct virgl_resource *res = virgl_resource_lookup(handle); struct vrend_transfer_info transfer_info; @@ -248,6 +257,7 @@ int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, uint64_t offset, struct iovec *iovec, int iovec_cnt) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(handle); struct vrend_transfer_info transfer_info; @@ -282,6 +292,7 @@ int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id, int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov, int num_iovs) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res) return EINVAL; @@ -291,6 +302,7 @@ int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov, void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res) return; @@ -305,16 +317,19 @@ void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, in int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id) { + TRACE_FUNC(); return vrend_renderer_create_fence(client_fence_id, ctx_id); } void virgl_renderer_force_ctx_0(void) { + TRACE_FUNC(); vrend_renderer_force_ctx_0(); } void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle) { + TRACE_FUNC(); struct virgl_context *ctx = virgl_context_lookup(ctx_id); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!ctx || !res) @@ -324,6 +339,7 @@ void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle) void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) { + TRACE_FUNC(); struct virgl_context *ctx = virgl_context_lookup(ctx_id); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!ctx || !res) @@ -334,6 +350,7 @@ void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle) int virgl_renderer_resource_get_info(int res_handle, struct virgl_renderer_resource_info *info) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res || !res->pipe_resource) @@ -357,6 +374,7 @@ int virgl_renderer_resource_get_info(int res_handle, void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, uint32_t *max_size) { + TRACE_FUNC(); switch (cap_set) { case VIRGL_RENDERER_CAPSET_VIRGL: case VIRGL_RENDERER_CAPSET_VIRGL2: @@ -372,6 +390,7 @@ void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver, void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs, uint32_t offset, int x, int y, int width, int height) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(resource_id); if (!res || !res->pipe_resource) return; @@ -439,12 +458,14 @@ void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint void virgl_renderer_poll(void) { + TRACE_FUNC(); if (state.vrend_initialized) vrend_renderer_check_fences(); } void virgl_renderer_cleanup(UNUSED void *cookie) { + TRACE_FUNC(); if (state.vrend_initialized) vrend_renderer_prepare_reset(); @@ -465,6 +486,9 @@ void virgl_renderer_cleanup(UNUSED void *cookie) int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs) { + TRACE_INIT(); + TRACE_FUNC(); + int ret; /* VIRGL_RENDERER_THREAD_SYNC is a hint and can be silently ignored */ @@ -543,6 +567,7 @@ fail: int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd) { + TRACE_FUNC(); if (state.winsys_initialized) return vrend_winsys_get_fd_for_texture(tex_id, fd); return -1; @@ -550,6 +575,7 @@ int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd) int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, int *offset) { + TRACE_FUNC(); if (state.winsys_initialized) return vrend_winsys_get_fd_for_texture2(tex_id, fd, stride, offset); return -1; @@ -557,6 +583,7 @@ int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, in void virgl_renderer_reset(void) { + TRACE_FUNC(); if (state.vrend_initialized) vrend_renderer_prepare_reset(); @@ -572,6 +599,7 @@ void virgl_renderer_reset(void) int virgl_renderer_get_poll_fd(void) { + TRACE_FUNC(); if (state.vrend_initialized) return vrend_renderer_get_poll_fd(); @@ -622,6 +650,7 @@ static int virgl_renderer_supported_structures(void *execute_args, uint32_t exec int virgl_renderer_execute(void *execute_args, uint32_t execute_size) { + TRACE_FUNC(); struct virgl_renderer_hdr *hdr = execute_args; if (hdr->stype_version != 0) return -EINVAL; @@ -638,6 +667,7 @@ int virgl_renderer_execute(void *execute_args, uint32_t execute_size) int virgl_renderer_resource_create_blob(const struct virgl_renderer_resource_create_blob_args *args) { + TRACE_FUNC(); struct virgl_context *ctx; struct virgl_context_blob blob; bool has_host_storage; @@ -719,6 +749,7 @@ int virgl_renderer_resource_create_blob(const struct virgl_renderer_resource_cre int virgl_renderer_resource_map(uint32_t res_handle, void **map, uint64_t *out_size) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res || !res->pipe_resource) return -EINVAL; @@ -728,6 +759,7 @@ int virgl_renderer_resource_map(uint32_t res_handle, void **map, uint64_t *out_s int virgl_renderer_resource_unmap(uint32_t res_handle) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res || !res->pipe_resource) return -EINVAL; @@ -737,6 +769,7 @@ int virgl_renderer_resource_unmap(uint32_t res_handle) int virgl_renderer_resource_get_map_info(uint32_t res_handle, uint32_t *map_info) { + TRACE_FUNC(); struct virgl_resource *res = virgl_resource_lookup(res_handle); if (!res || !res->pipe_resource) return -EINVAL; @@ -768,5 +801,6 @@ virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd) int virgl_renderer_export_fence(uint32_t client_fence_id, int *fd) { + TRACE_FUNC(); return vrend_renderer_export_fence(client_fence_id, fd); } diff --git a/src/vrend_decode.c b/src/vrend_decode.c index 9e573f1..7d50688 100644 --- a/src/vrend_decode.c +++ b/src/vrend_decode.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "util/u_memory.h" #include "pipe/p_defines.h" @@ -38,6 +39,7 @@ #include "tgsi/tgsi_text.h" #include "vrend_debug.h" #include "vrend_tweaks.h" +#include "virgl_util.h" /* decode side */ #define DECODE_MAX_TOKENS 8000 @@ -764,6 +766,8 @@ static int vrend_decode_create_object(struct vrend_decode_ctx *ctx, int length) VREND_DEBUG(dbg_object, ctx->grctx," CREATE %-18s handle:0x%x len:%d\n", vrend_get_object_type_name(obj_type), handle, length); + TRACE_SCOPE("CREATE %-18s", vrend_get_object_type_name(obj_type)); + switch (obj_type){ case VIRGL_OBJECT_BLEND: ret = vrend_decode_create_blend(ctx, handle, length); @@ -1466,6 +1470,7 @@ struct virgl_context *vrend_renderer_context_create(uint32_t handle, static void vrend_decode_ctx_destroy(struct virgl_context *ctx) { + TRACE_FUNC(); struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; vrend_destroy_context(dctx->grctx); @@ -1475,8 +1480,8 @@ static void vrend_decode_ctx_destroy(struct virgl_context *ctx) static void vrend_decode_ctx_attach_resource(struct virgl_context *ctx, struct virgl_resource *res) { + TRACE_FUNC(); struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; - /* in the future, we should import to create the pipe resource */ if (!res->pipe_resource) return; @@ -1488,6 +1493,7 @@ static void vrend_decode_ctx_attach_resource(struct virgl_context *ctx, static void vrend_decode_ctx_detach_resource(struct virgl_context *ctx, struct virgl_resource *res) { + TRACE_FUNC(); struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; vrend_renderer_detach_res_ctx(dctx->grctx, res->res_id); } @@ -1497,6 +1503,7 @@ static int vrend_decode_ctx_transfer_3d(struct virgl_context *ctx, const struct vrend_transfer_info *info, int transfer_mode) { + TRACE_FUNC(); struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; return vrend_renderer_transfer_iov(dctx->grctx, res->res_id, info, transfer_mode); @@ -1507,6 +1514,7 @@ static int vrend_decode_ctx_get_blob(struct virgl_context *ctx, UNUSED uint32_t blob_flags, struct virgl_context_blob *blob) { + TRACE_FUNC(); struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx; blob->type = VIRGL_RESOURCE_FD_INVALID; @@ -1520,6 +1528,7 @@ static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx, const void *buffer, size_t size) { + TRACE_FUNC(); struct vrend_decode_ctx *gdctx = (struct vrend_decode_ctx *)ctx; bool bret; int ret; @@ -1546,6 +1555,8 @@ static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx, VREND_DEBUG(dbg_cmd, gdctx->grctx,"%-4d %-20s len:%d\n", gdctx->ds->buf_offset, vrend_get_comand_name(header & 0xff), len); + TRACE_SCOPE("%s", vrend_get_comand_name(header & 0xff)); + switch (header & 0xff) { case VIRGL_CCMD_CREATE_OBJECT: ret = vrend_decode_create_object(gdctx, len);