Skip to content

Commit 1c0b495

Browse files
committed
[UserEvents] Write events to tracepoints
1 parent b8ad60a commit 1c0b495

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
@@ -166,13 +166,31 @@ event_reg(uint32_t fd, const char *command, uint32_t *write, uint32_t *enabled)
166166
reg.enable_size = sizeof(*enabled); // uint8_t
167167
// reg.flags //uint16_t
168168
reg.enable_addr = (uint64_t)enabled; // uint64_t
169-
reg.name_args = (uint64_t)command; // uint64_t
170169

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

174191
*write = reg.write_index; // uint32_t
175192

193+
free(name_args);
176194
return 0;
177195
#else // HAVE_LINUX_USER_EVENTS_H
178196
// Not Supported
@@ -624,6 +642,158 @@ ep_session_write_all_buffers_to_file (EventPipeSession *session, bool *events_wr
624642
return !ep_file_has_errors (session->file);
625643
}
626644

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