diff --git a/doc/kernel/nanokernel/nanokernel.rst b/doc/kernel/nanokernel/nanokernel.rst index 30699420b67..ae06313ffa3 100644 --- a/doc/kernel/nanokernel/nanokernel.rst +++ b/doc/kernel/nanokernel/nanokernel.rst @@ -16,3 +16,4 @@ applications and nanokernel applications. nanokernel_synchronization nanokernel_data nanokernel_interrupts + nanokernel_kernel_event_logger diff --git a/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst b/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst new file mode 100644 index 00000000000..6bef5061e08 --- /dev/null +++ b/doc/kernel/nanokernel/nanokernel_kernel_event_logger.rst @@ -0,0 +1,230 @@ +.. _nanokernel_event_logger: + +Kernel Event Logger +################### + +Definition +********** + +The kernel event logger is a standardized mechanism to record events within the Kernel while +providing a single interface for the user to collect the data. This mechanism is currently used +to log the following events: + +* Sleep events (entering and exiting low power conditions). +* Context switch events. +* Interrupt events. + +Kernel Event Logger Configuration +********************************* + +Kconfig provides the ability to enable and disable the collection of events and to configure the +size of the buffer used by the event logger. + +These options can be found in the following path :file:`kernel/Kconfig`. + +General kernel event logger configuration: + +* :option:`KERNEL_EVENT_LOGGER_BUFFER_SIZE` + + Default size: 128 words, 32-bit length. + +Profiling points configuration: + +* :option:`KERNEL_EVENT_INTERRUPT` + + Enables recording of interrupt-driven events by providing timestamp information. + +* :option:`KERNEL_EVENT_SLEEP` + + Enables recording of sleep events: + + * Timestamp when the CPU went to sleep mode. + * Timestamp when the CPU woke up. + * The interrupt Id that woke the CPU up. + +* :option:`KERNEL_EVENT_CONTEXT` + + Enables recording of context-switching events. Details include: + + * Which thread is leaving the CPU. + * Timestamp when the event has occurred. + +Adding a Kernel Event Logging Point +*********************************** + +Custom trace points can be added with the following API: + +* :cpp:func:`sys_k_event_logger_put()` + + Adds the profile of a new event with custom data. + +* :cpp:func:`sys_k_event_logger_put_timed()` + + Adds timestamped profile of a new event. + +.. important:: + + The data must be in 32-bit sized blocks. + +Retrieving Kernel Event Data +**************************** + +Applications are required to implement a fiber for accessing the recorded event messages +in both the nanokernel and microkernel systems. Developers can use the provided API to +retrieve the data, or may write their own routines using the ring buffer provided by the +event logger. + +The API functions provided are: + +* :cpp:func:`sys_k_event_logger_get()` +* :cpp:func:`sys_k_event_logger_get_wait()` +* :cpp:func:`sys_k_event_logger_get_wait_timeout()` + +The above functions specify various ways to retrieve a event message and to copy it to +the provided buffer. When the buffer size is smaller than the message, the function will +return an error. All three functions retrieve messages via a FIFO method. The :literal:`wait` +and :literal:`wait_timeout` functions allow the caller to pend until a new message is +logged, or until the timeout expires. + +Message Formats +*************** + +Interrupt-driven Event Messaging +-------------------------------- + +The data of the interrupt-driven event message comes in two block of 32 bits: + +* The first block contains the timestamp occurrence of the interrupt event. +* The second block contains the Id of the interrupt. + +Example: + +.. code-block:: c + + uint32_t data[2]; + data[0] = timestamp_event; + data[1] = interrupt_id; + +Context-switch Event Messaging +------------------------------ + +The data of the context-switch event message comes in two block of 32 bits: + +* The first block contains the timestamp occurrence of the context-switch event. +* The second block contains the thread id of the context involved. + +Example: + +.. code-block:: c + + uint32_t data[2]; + data[0] = timestamp_event; + data[1] = context_id; + +Sleep Event Messaging +--------------------- + +The data of the sleep event message comes in three block of 32 bits: + +* The first block contains the timestamp when the CPU went to sleep mode. +* The second block contains the timestamp when the CPU woke up. +* The third block contains the interrupt Id that woke the CPU up. + +Example: + +.. code-block:: c + + uint32_t data[3]; + data[0] = timestamp_went_sleep; + data[1] = timestamp woke_up. + data[2] = interrupt_id. + +Example: Retrieving Profiling Messages +====================================== + +.. code-block:: c + + uint32_t data[3]; + uint8_t data_length = SIZE32_OF(data); + uint8_t dropped_count; + + while(1) { + /* collect the data */ + res = sys_k_event_logger_get_wait(&event_id, &dropped_count, data, + &data_length); + + if (dropped_count > 0) { + /* process the message dropped count */ + } + + if (res > 0) { + /* process the data */ + switch (event_id) { + case KERNEL_EVENT_CONTEXT_SWITCH_EVENT_ID: + /* ... Process the context switch event data ... */ + break; + case KERNEL_EVENT_INTERRUPT_EVENT_ID: + /* ... Process the interrupt event data ... */ + break; + case KERNEL_EVENT_SLEEP_EVENT_ID: + /* ... Process the data for a sleep event ... */ + break; + default: + printf("unrecognized event id %d\n", event_id); + } + } else { + if (res == -EMSGSIZE) { + /* ERROR - The buffer provided to collect the + * profiling events is too small. + */ + } else if (ret == -EAGAIN) { + /* There is no message available in the buffer */ + } + } + } + +.. note:: + + To see an example that shows how to collect the kernel event data, check the sample + project: :file:`samples/microkernel/apps/kernel_event_logger_sample`. + +Example: Adding a Kernel Event Logging Point +============================================ + +.. code-block:: c + + uint32_t data[2]; + + data[0] = custom_data_1; + data[1] = custom_data_2; + + sys_k_event_logger_put(KERNEL_EVENT_LOGGER_CUSTOM_ID, data, ARRAY_SIZE(data)); + +Use the following function to register only the time of an event. + +.. code-block:: c + + sys_k_event_logger_put_timed(KERNEL_EVENT_LOGGER_CUSTOM_ID); + +APIs +**** + +The following APIs are provided by the :file:`k_event_logger.h` file: + +:cpp:func:`sys_k_event_logger_register_as_collector()` + Register the current fiber as the collector fiber. + +:cpp:func:`sys_k_event_logger_put()` + Enqueue a kernel event logger message with custom data. + +:cpp:func:`sys_k_event_logger_put_timed()` + Enqueue a kernel event logger message with the current time. + +:cpp:func:`sys_k_event_logger_get()` + De-queue a kernel event logger message. + +:cpp:func:`sys_k_event_logger_get_wait()` + De-queue a kernel event logger message. Wait if the buffer is empty. + +:cpp:func:`sys_k_event_logger_get_wait_timeout()` + De-queue a kernel event logger message. Wait if the buffer is empty until the timeout expires.