Skip to content

Commit

Permalink
Approximate time helpers (#4013)
Browse files Browse the repository at this point in the history
* Approximate time helpers

Signed-off-by: Alan Jowett <[email protected]>

* PR feedback

Signed-off-by: Alan Jowett <[email protected]>

* Update expected c files

Signed-off-by: Alan Jowett <[email protected]>

* Apply suggestions from code review

Co-authored-by: Dave Thaler <[email protected]>

* Pickup latest usersim

Signed-off-by: Alan Jowett <[email protected]>

---------

Signed-off-by: Alan Jowett <[email protected]>
Co-authored-by: Alan Jowett <[email protected]>
Co-authored-by: Dave Thaler <[email protected]>
  • Loading branch information
3 people authored Dec 2, 2024
1 parent a08905c commit f1401bb
Show file tree
Hide file tree
Showing 15 changed files with 479 additions and 309 deletions.
22 changes: 22 additions & 0 deletions include/bpf_helper_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,25 @@ EBPF_HELPER(size_t, bpf_strnlen_s, (const char* str, size_t str_size));
#define memcpy_s bpf_memcpy
#define memmove_s bpf_memmove
#endif

/**
* @brief Return time elapsed since boot in milliseconds including time while suspended.
* This function uses a lower resolution clock source than bpf_ktime_get_boot_ns, but is faster.
*
* @return Time elapsed since boot in milliseconds.
*/
EBPF_HELPER(uint64_t, bpf_ktime_get_boot_ms, ());
#ifndef __doxygen
#define bpf_ktime_get_boot_ms ((bpf_ktime_get_boot_ms_t)BPF_FUNC_ktime_get_boot_ms)
#endif

/**
* @brief Return time elapsed since boot in milliseconds excluding time while suspended.
* This function uses a lower resolution clock source than bpf_ktime_get_ns, but is faster.
*
* @return Time elapsed since boot in milliseconds.
*/
EBPF_HELPER(uint64_t, bpf_ktime_get_ms, ());
#ifndef __doxygen
#define bpf_ktime_get_ms ((bpf_ktime_get_ms_t)BPF_FUNC_ktime_get_ms)
#endif
2 changes: 2 additions & 0 deletions include/ebpf_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ typedef enum
BPF_FUNC_strncpy_s = 27, ///< \ref bpf_strncpy_s
BPF_FUNC_strncat_s = 28, ///< \ref bpf_strncat_s
BPF_FUNC_strnlen_s = 29, ///< \ref bpf_strnlen_s
BPF_FUNC_ktime_get_boot_ms = 30, ///< \ref bpf_ktime_get_boot_ms
BPF_FUNC_ktime_get_ms = 31, ///< \ref bpf_ktime_get_ms
} ebpf_helper_id_t;

// Cross-platform BPF program types.
Expand Down
32 changes: 28 additions & 4 deletions libs/execution_context/ebpf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ _ebpf_core_memmove(
_In_reads_(source_length) const void* source,
size_t source_length);

static uint64_t
_ebpf_core_get_time_since_boot_ms();

static uint64_t
_ebpf_core_get_time_ms();

#define EBPF_CORE_GLOBAL_HELPER_EXTENSION_VERSION 0

static ebpf_program_type_descriptor_t _ebpf_global_helper_program_descriptor = {
Expand Down Expand Up @@ -144,6 +150,8 @@ static const void* _ebpf_general_helpers[] = {
(void*)&_ebpf_core_strncpy_s,
(void*)&_ebpf_core_strncat_s,
(void*)&_ebpf_core_strlen_s,
(void*)&_ebpf_core_get_time_since_boot_ms,
(void*)&_ebpf_core_get_time_ms,
};

static const ebpf_helper_function_addresses_t _ebpf_global_helper_function_dispatch_table = {
Expand Down Expand Up @@ -2259,17 +2267,33 @@ _ebpf_core_random_uint32()
static uint64_t
_ebpf_core_get_time_since_boot_ns()
{
// ebpf_query_time_since_boot_precise returns time elapsed since
// cxplat_query_time_since_boot_precise returns time elapsed since
// boot in units of 100 ns.
return ebpf_query_time_since_boot_precise(true) * EBPF_NS_PER_FILETIME;
return cxplat_query_time_since_boot_precise(true) * EBPF_NS_PER_FILETIME;
}

static uint64_t
_ebpf_core_get_time_ns()
{
// ebpf_query_time_since_boot_precise returns time elapsed since
// cxplat_query_time_since_boot_precise returns time elapsed since
// boot in units of 100 ns.
return cxplat_query_time_since_boot_precise(false) * EBPF_NS_PER_FILETIME;
}

static uint64_t
_ebpf_core_get_time_since_boot_ms()
{
// cxplat_query_time_since_boot_approximate returns time elapsed since
// boot in units of 100 ns.
return cxplat_query_time_since_boot_approximate(true) / EBPF_FILETIME_PER_MS;
}

static uint64_t
_ebpf_core_get_time_ms()
{
// cxplat_query_time_since_boot_approximate returns time elapsed since
// boot in units of 100 ns.
return ebpf_query_time_since_boot_precise(false) * EBPF_NS_PER_FILETIME;
return cxplat_query_time_since_boot_approximate(false) / EBPF_FILETIME_PER_MS;
}

static uint64_t
Expand Down
6 changes: 6 additions & 0 deletions libs/execution_context/ebpf_general_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ ebpf_helper_function_prototype_t ebpf_core_helper_function_prototype_array[] = {
EBPF_ARGUMENT_TYPE_PTR_TO_READABLE_MEM,
EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO,
}},
{EBPF_HELPER_FUNCTION_PROTOTYPE_HEADER,
BPF_FUNC_ktime_get_boot_ms,
"bpf_ktime_get_boot_ms",
EBPF_RETURN_TYPE_INTEGER,
{0}},
{EBPF_HELPER_FUNCTION_PROTOTYPE_HEADER, BPF_FUNC_ktime_get_ms, "bpf_ktime_get_ms", EBPF_RETURN_TYPE_INTEGER, {0}},
};

#ifdef __cplusplus
Expand Down
6 changes: 3 additions & 3 deletions libs/execution_context/ebpf_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,15 +1224,15 @@ _insert_into_hot_list(_Inout_ ebpf_core_lru_map_t* map, size_t partition, _Inout
switch (key_state) {
case EBPF_LRU_KEY_UNINITIALIZED:
EBPF_LRU_ENTRY_GENERATION_PTR(map, entry)[partition] = map->partitions[partition].current_generation;
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = ebpf_query_time_since_boot_approximate(false);
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = cxplat_query_time_since_boot_approximate(false);
ebpf_list_insert_tail(
&map->partitions[partition].hot_list, &EBPF_LRU_ENTRY_LIST_ENTRY_PTR(map, entry)[partition]);
map->partitions[partition].hot_list_size++;
break;
case EBPF_LRU_KEY_COLD:
// Remove from cold list.
EBPF_LRU_ENTRY_GENERATION_PTR(map, entry)[partition] = map->partitions[partition].current_generation;
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = ebpf_query_time_since_boot_approximate(false);
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = cxplat_query_time_since_boot_approximate(false);
ebpf_list_remove_entry(&EBPF_LRU_ENTRY_LIST_ENTRY_PTR(map, entry)[partition]);
ebpf_list_insert_tail(
&map->partitions[partition].hot_list, &EBPF_LRU_ENTRY_LIST_ENTRY_PTR(map, entry)[partition]);
Expand Down Expand Up @@ -1271,7 +1271,7 @@ _initialize_lru_entry(
// Only insert into the current partition's hot list.
ebpf_lock_state_t state = ebpf_lock_lock(&map->partitions[partition].lock);
EBPF_LRU_ENTRY_GENERATION_PTR(map, entry)[partition] = map->partitions[partition].current_generation;
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = ebpf_query_time_since_boot_approximate(false);
EBPF_LRU_ENTRY_LAST_USED_TIME_PTR(map, entry)[partition] = cxplat_query_time_since_boot_approximate(false);
ebpf_list_insert_tail(&map->partitions[partition].hot_list, &EBPF_LRU_ENTRY_LIST_ENTRY_PTR(map, entry)[partition]);
map->partitions[partition].hot_list_size++;

Expand Down
8 changes: 4 additions & 4 deletions libs/execution_context/ebpf_program.c
Original file line number Diff line number Diff line change
Expand Up @@ -2461,7 +2461,7 @@ _ebpf_program_test_run_work_item(_In_ cxplat_preemptible_work_item_t* work_item,
state_stored = true;
}

uint64_t start_time = ebpf_query_time_since_boot_precise(false);
uint64_t start_time = cxplat_query_time_since_boot_precise(false);
// Use a counter instead of performing a modulus operation to determine when to start a new epoch.
// This is because the modulus operation is expensive and we want to minimize the overhead of
// the test run.
Expand All @@ -2474,7 +2474,7 @@ _ebpf_program_test_run_work_item(_In_ cxplat_preemptible_work_item_t* work_item,
ebpf_epoch_exit(&epoch_state);
if (ebpf_should_yield_processor()) {
// Compute the elapsed time since the last yield.
end_time = ebpf_query_time_since_boot_precise(false);
end_time = cxplat_query_time_since_boot_precise(false);

// Add the elapsed time to the cumulative time.
cumulative_time += end_time - start_time;
Expand All @@ -2486,7 +2486,7 @@ _ebpf_program_test_run_work_item(_In_ cxplat_preemptible_work_item_t* work_item,
old_irql = ebpf_raise_irql(context->required_irql);

// Reset the start time.
start_time = ebpf_query_time_since_boot_precise(false);
start_time = cxplat_query_time_since_boot_precise(false);
}
ebpf_epoch_enter(&epoch_state);
}
Expand All @@ -2496,7 +2496,7 @@ _ebpf_program_test_run_work_item(_In_ cxplat_preemptible_work_item_t* work_item,
break;
}
}
end_time = ebpf_query_time_since_boot_precise(false);
end_time = cxplat_query_time_since_boot_precise(false);

cumulative_time += end_time - start_time;

Expand Down
28 changes: 0 additions & 28 deletions libs/runtime/ebpf_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,34 +222,6 @@ ebpf_allocate_process_state()
return state;
}

uint64_t
ebpf_query_time_since_boot_precise(bool include_suspended_time)
{
uint64_t qpc_time;
if (include_suspended_time) {
// KeQueryUnbiasedInterruptTimePrecise returns the current interrupt-time count in 100-nanosecond units.
// Unbiased Interrupt time is the total time since boot including time spent suspended.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kequeryunbiasedinterrupttimeprecise
return KeQueryUnbiasedInterruptTimePrecise(&qpc_time);
} else {
// KeQueryInterruptTimePrecise returns the current interrupt-time count in 100-nanosecond units.
// (Biased) Interrupt time is the total time since boot excluding time spent suspended. //
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-kequeryinterrupttimeprecise
return KeQueryInterruptTimePrecise(&qpc_time);
}
}

uint64_t
ebpf_query_time_since_boot_approximate(bool include_suspend_time)
{
if (include_suspend_time) {
ebpf_assert(!"Include suspend time not supported on this platform.");
return 0;
} else {
return KeQueryInterruptTime();
}
}

MDL*
ebpf_map_memory(size_t length)
{
Expand Down
24 changes: 1 addition & 23 deletions libs/runtime/ebpf_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extern "C"
}

#define EBPF_NS_PER_FILETIME 100
#define EBPF_FILETIME_PER_MS 10000

typedef enum _ebpf_code_integrity_state
{
Expand Down Expand Up @@ -632,29 +633,6 @@ extern "C"
ebpf_validate_security_descriptor(
_In_ const ebpf_security_descriptor_t* security_descriptor, size_t security_descriptor_length);

/**
* @brief Return time elapsed since boot in units of 100 nanoseconds.
*
* @param[in] include_suspended_time Include time the system spent in a suspended state.
* @return Time elapsed since boot in 100 nanosecond units.
*/
EBPF_INLINE_HINT
uint64_t
ebpf_query_time_since_boot_precise(bool include_suspended_time);

/**
* @brief Return time elapsed since boot in units of 100 nanoseconds.
* This function is faster than ebpf_query_time_since_boot_precise() but may not
* be as accurate.
*
* @param[in] include_suspended_time Include time the system spent in a suspended state.
*
* @return Time elapsed since boot in 100 nanosecond units.
*/
EBPF_INLINE_HINT
uint64_t
ebpf_query_time_since_boot_approximate(bool include_suspended_time);

/**
* @brief Affinitize the current thread to a specific CPU by index and return the old affinity.
*
Expand Down
Loading

0 comments on commit f1401bb

Please sign in to comment.