Skip to content

Commit 5c7c64a

Browse files
committed
[UserEvents] Write events to tracepoints
1 parent 2bab809 commit 5c7c64a

File tree

4 files changed

+193
-2
lines changed

4 files changed

+193
-2
lines changed

src/native/eventpipe/configure.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ check_include_files(
2222
HAVE_LINUX_USER_EVENTS_H
2323
)
2424

25+
check_include_files(
26+
"sys/uio.h"
27+
HAVE_SYS_UIO_H
28+
)
29+
2530
if (NOT DEFINED EP_GENERATED_HEADER_PATH)
2631
message(FATAL_ERROR "Required configuration EP_GENERATED_HEADER_PATH not set.")
2732
endif (NOT DEFINED EP_GENERATED_HEADER_PATH)

src/native/eventpipe/ep-session.c

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,31 @@ event_reg(uint32_t fd, const char *command, uint32_t *write, uint32_t *enabled)
168168
reg.enable_size = sizeof(*enabled); // uint8_t
169169
// reg.flags //uint16_t
170170
reg.enable_addr = (uint64_t)enabled; // uint64_t
171-
reg.name_args = (uint64_t)command; // uint64_t
172171

173-
if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
172+
// Hard-coded format as per the documentation
173+
const char *format = "u8 version; u16 event_id; __rel_loc u8[] extension; __rel_loc u8[] payload; __rel_loc u8[] meta";
174+
175+
// Dynamically allocate space for name_args
176+
size_t name_args_size = strlen(command) + strlen(format) + 2; // +2 for space and null terminator
177+
char *name_args = (char *)malloc(name_args_size);
178+
if (!name_args)
179+
return -1; // Memory allocation failed
180+
181+
if (snprintf(name_args, name_args_size, "%s %s", command, format) >= name_args_size) {
182+
free(name_args);
183+
return -1; // Name and format combination is too long
184+
}
185+
186+
reg.name_args = (uint64_t)name_args; // uint64_t
187+
188+
if (ioctl(fd, DIAG_IOCSREG, &reg) == -1) {
189+
free(name_args);
174190
return -1;
191+
}
175192

176193
*write = reg.write_index; // uint32_t
177194

195+
free(name_args);
178196
return 0;
179197
#else // HAVE_LINUX_USER_EVENTS_H
180198
// Not Supported
@@ -636,6 +654,158 @@ ep_session_write_all_buffers_to_file (EventPipeSession *session, bool *events_wr
636654
return !ep_file_has_errors (session->file);
637655
}
638656

657+
bool
658+
ep_tracepoint_write (
659+
EventPipeSession *session,
660+
ep_rt_thread_handle_t thread,
661+
EventPipeEvent *ep_event,
662+
EventPipeEventPayload *ep_event_payload,
663+
const uint8_t *activity_id,
664+
const uint8_t *related_activity_id,
665+
ep_rt_thread_handle_t event_thread,
666+
EventPipeStackContents *stack)
667+
{
668+
#ifdef HAVE_SYS_UIO_H
669+
EventPipeProvider *provider = ep_event_get_provider (ep_event);
670+
671+
EventPipeSessionProviderList *session_provider_list = ep_session_get_providers (session);
672+
EventPipeSessionProvider *session_provider = ep_session_provider_list_find_by_name (ep_session_provider_list_get_providers (session_provider_list), ep_provider_get_provider_name (provider));
673+
674+
uint32_t event_id = ep_event_get_event_id (ep_event);
675+
676+
dn_umap_t *event_id_to_tracepoint_map = ep_session_provider_get_event_id_to_tracepoint_map (session_provider);
677+
dn_umap_it_t found1 = dn_umap_find (event_id_to_tracepoint_map, &event_id);
678+
EventPipeTracepoint *tracepoint = NULL;
679+
if (dn_umap_it_end (found1)) {
680+
// If we don't have a tracepoint for this event_id, use the default tracepoint
681+
tracepoint = session_provider->default_tracepoint;
682+
} else {
683+
// We have a tracepoint for this event_id
684+
tracepoint = dn_umap_it_value_t (found1, EventPipeTracepoint *);
685+
}
686+
if (tracepoint == NULL) {
687+
// No tracepoint for this event_id and no default tracepoint, so we can't write the event.
688+
return false;
689+
}
690+
691+
if (tracepoint->enabled == 0) {
692+
// No listeners
693+
return false;
694+
}
695+
696+
struct iovec io[9];
697+
698+
io[0].iov_base = &tracepoint->write_index; // __u32 from event_reg
699+
io[0].iov_len = sizeof(tracepoint->write_index);
700+
701+
uint8_t version = 0x01; // hardcoded for the first tracepoint format version
702+
io[1].iov_base = &version;
703+
io[1].iov_len = sizeof(version);
704+
705+
uint16_t truncated_event_id = event_id & 0xFFFF;
706+
io[2].iov_base = &truncated_event_id;
707+
io[2].iov_len = sizeof(truncated_event_id);
708+
709+
// The data transmitted in version 1 is
710+
// extension - a NetTrace V6 LabelList
711+
// payload - the EventPipe Event Payload
712+
// meta - the EventPipe Event metadata
713+
714+
bool activity_id_is_empty = true;
715+
if (activity_id != NULL) {
716+
// If the activity_id is not empty, then we don't consider it empty.
717+
for (int i = 0; i < EP_ACTIVITY_ID_SIZE; ++i) {
718+
if (activity_id[i] != 0) {
719+
activity_id_is_empty = false;
720+
break;
721+
}
722+
}
723+
}
724+
bool related_activity_id_is_empty = true;
725+
if (related_activity_id != NULL) {
726+
// If the related_activity_id is not empty, then we don't consider it empty.
727+
for (int i = 0; i < EP_ACTIVITY_ID_SIZE; ++i) {
728+
if (related_activity_id[i] != 0) {
729+
related_activity_id_is_empty = false;
730+
break;
731+
}
732+
}
733+
}
734+
// extension generation helper
735+
uint16_t extension_len = 0;
736+
if (activity_id != NULL && !activity_id_is_empty)
737+
extension_len += 1 + EP_ACTIVITY_ID_SIZE; // ActivityId kind + value
738+
if (related_activity_id != NULL && !related_activity_id_is_empty)
739+
extension_len += 1 + EP_ACTIVITY_ID_SIZE; // RelatedActivityId kind + value
740+
741+
uint8_t *extension = NULL;
742+
if (extension_len > 0) {
743+
extension = (uint8_t *)malloc(extension_len);
744+
EP_ASSERT(extension != NULL);
745+
uint16_t offset = 0;
746+
if (activity_id != NULL && !activity_id_is_empty) {
747+
// If there is a related_activity_id, use 0x81 (more follows), else 0x01 (no more follows)
748+
extension[offset] = (related_activity_id != NULL && !related_activity_id_is_empty) ? 0x81 : 0x01;
749+
memcpy(extension + offset + 1, activity_id, EP_ACTIVITY_ID_SIZE);
750+
offset += 1 + EP_ACTIVITY_ID_SIZE;
751+
}
752+
if (related_activity_id != NULL && !related_activity_id_is_empty) {
753+
// RelatedActivityId: 0x02 (no more follows)
754+
extension[offset] = 0x02;
755+
memcpy(extension + offset + 1, related_activity_id, EP_ACTIVITY_ID_SIZE);
756+
offset += 1 + EP_ACTIVITY_ID_SIZE;
757+
}
758+
}
759+
760+
uint32_t payload_len = ep_event_payload_get_size (ep_event_payload);
761+
if ((payload_len & 0xFFFF0000) != 0) {
762+
// Payload is too large, we can't write it.
763+
return false;
764+
}
765+
uint8_t *payload = (uint8_t *)malloc (payload_len);
766+
EP_ASSERT (payload != NULL);
767+
ep_event_payload_copy_data (ep_event_payload, payload);
768+
769+
// meta
770+
const uint8_t *metadata = ep_event_get_metadata (ep_event);
771+
uint32_t metadata_len = ep_event_get_metadata_len (ep_event);
772+
773+
// calculated __rel_loc values
774+
uint32_t meta_rel_loc = metadata_len << 16 | ((extension_len + payload_len) & 0xFFFF);
775+
uint32_t payload_rel_loc = payload_len << 16 | ((sizeof(meta_rel_loc) + extension_len) & 0xFFFF);
776+
uint32_t extension_rel_loc = extension_len << 16 | ((sizeof(payload_rel_loc) + sizeof(meta_rel_loc)) & 0xFFFF);
777+
io[3].iov_base = &extension_rel_loc;
778+
io[3].iov_len = sizeof(extension_rel_loc);
779+
780+
io[4].iov_base = &payload_rel_loc;
781+
io[4].iov_len = sizeof(payload_rel_loc);
782+
783+
io[5].iov_base = &meta_rel_loc;
784+
io[5].iov_len = sizeof(meta_rel_loc);
785+
786+
// Actual data buffers
787+
io[6].iov_base = extension;
788+
io[6].iov_len = extension_len;
789+
790+
io[7].iov_base = payload;
791+
io[7].iov_len = payload_len;
792+
793+
io[8].iov_base = (void *)metadata;
794+
io[8].iov_len = metadata_len;
795+
int32_t result = writev(session->user_events_data_fd, (const struct iovec *)io, 9);
796+
if (result == -1) {
797+
// Failed to write the event, return false.
798+
// return false;
799+
return false;
800+
}
801+
802+
return true;
803+
#else // HAVE_SYS_UIO_H
804+
// Not Supported
805+
return false;
806+
#endif // HAVE_SYS_UIO_H
807+
}
808+
639809
bool
640810
ep_session_write_event (
641811
EventPipeSession *session,
@@ -673,6 +843,17 @@ ep_session_write_event (
673843
stack == NULL ? NULL : (uintptr_t *)ep_stack_contents_get_pointer (stack),
674844
session->callback_additional_data);
675845
result = true;
846+
} else if (session->session_type == EP_SESSION_TYPE_USEREVENTS) {
847+
EP_ASSERT (session->user_events_data_fd != 0);
848+
result = ep_tracepoint_write (
849+
session,
850+
thread,
851+
ep_event,
852+
payload,
853+
activity_id,
854+
related_activity_id,
855+
event_thread,
856+
stack);
676857
} else {
677858
EP_ASSERT (session->buffer_manager != NULL);
678859
result = ep_buffer_manager_write_event (

src/native/eventpipe/ep-session.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include <sys/ioctl.h> // event_reg
1919
#endif // HAVE_LINUX_USER_EVENTS_H
2020

21+
22+
#ifdef HAVE_SYS_UIO_H
23+
#include <sys/uio.h> // iovec
24+
#endif // HAVE_SYS_UIO_H
2125
/*
2226
* EventPipeSession.
2327
*/

src/native/eventpipe/ep-shared-config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#cmakedefine01 HAVE_SYS_SOCKET_H
55
#cmakedefine01 HAVE_LINUX_USER_EVENTS_H
6+
#cmakedefine01 HAVE_SYS_UIO_H
67
/* This platforms supports setting flags atomically when accepting connections. */
78
#cmakedefine01 HAVE_ACCEPT4
89

0 commit comments

Comments
 (0)