zephyr/kernel/paging/statistics.c

252 lines
6.8 KiB
C

/*
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <kernel_internal.h>
#include <zephyr/internal/syscall_handler.h>
#include <zephyr/toolchain.h>
#include <zephyr/kernel/mm/demand_paging.h>
extern struct k_mem_paging_stats_t paging_stats;
#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM
struct k_mem_paging_histogram_t z_paging_histogram_eviction;
struct k_mem_paging_histogram_t z_paging_histogram_backing_store_page_in;
struct k_mem_paging_histogram_t z_paging_histogram_backing_store_page_out;
#ifdef CONFIG_DEMAND_PAGING_STATS_USING_TIMING_FUNCTIONS
/*
* The frequency of timing functions is highly dependent on
* architecture, SoC or board. It is also not available at build time.
* Therefore, the bounds for the timing histograms needs to be defined
* externally to this file, and must be tailored to the platform
* being used.
*/
extern unsigned long
k_mem_paging_eviction_histogram_bounds[
CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS];
extern unsigned long
k_mem_paging_backing_store_histogram_bounds[
CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS];
#else
#define NS_TO_CYC(ns) (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000000U * ns)
/*
* This provides the upper bounds of the bins in eviction timing histogram.
*/
__weak unsigned long
k_mem_paging_eviction_histogram_bounds[CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS] = {
NS_TO_CYC(1),
NS_TO_CYC(5),
NS_TO_CYC(10),
NS_TO_CYC(50),
NS_TO_CYC(100),
NS_TO_CYC(200),
NS_TO_CYC(500),
NS_TO_CYC(1000),
NS_TO_CYC(2000),
ULONG_MAX
};
/*
* This provides the upper bounds of the bins in backing store timing histogram
* (both page-in and page-out).
*/
__weak unsigned long
k_mem_paging_backing_store_histogram_bounds[
CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS] = {
NS_TO_CYC(10),
NS_TO_CYC(100),
NS_TO_CYC(125),
NS_TO_CYC(250),
NS_TO_CYC(500),
NS_TO_CYC(1000),
NS_TO_CYC(2000),
NS_TO_CYC(5000),
NS_TO_CYC(10000),
ULONG_MAX
};
#endif /* CONFIG_DEMAND_PAGING_STATS_USING_TIMING_FUNCTIONS */
#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */
unsigned long k_mem_num_pagefaults_get(void)
{
unsigned long ret;
unsigned int key;
key = irq_lock();
ret = paging_stats.pagefaults.cnt;
irq_unlock(key);
return ret;
}
void z_impl_k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats)
{
if (stats == NULL) {
return;
}
/* Copy statistics */
memcpy(stats, &paging_stats, sizeof(paging_stats));
}
#ifdef CONFIG_USERSPACE
static inline
void z_vrfy_k_mem_paging_stats_get(struct k_mem_paging_stats_t *stats)
{
K_OOPS(K_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats)));
z_impl_k_mem_paging_stats_get(stats);
}
#include <zephyr/syscalls/k_mem_paging_stats_get_mrsh.c>
#endif /* CONFIG_USERSPACE */
#ifdef CONFIG_DEMAND_PAGING_THREAD_STATS
void z_impl_k_mem_paging_thread_stats_get(struct k_thread *thread,
struct k_mem_paging_stats_t *stats)
{
if ((thread == NULL) || (stats == NULL)) {
return;
}
/* Copy statistics */
memcpy(stats, &thread->paging_stats, sizeof(thread->paging_stats));
}
#ifdef CONFIG_USERSPACE
static inline
void z_vrfy_k_mem_paging_thread_stats_get(struct k_thread *thread,
struct k_mem_paging_stats_t *stats)
{
K_OOPS(K_SYSCALL_OBJ(thread, K_OBJ_THREAD));
K_OOPS(K_SYSCALL_MEMORY_WRITE(stats, sizeof(*stats)));
z_impl_k_mem_paging_thread_stats_get(thread, stats);
}
#include <zephyr/syscalls/k_mem_paging_thread_stats_get_mrsh.c>
#endif /* CONFIG_USERSPACE */
#endif /* CONFIG_DEMAND_PAGING_THREAD_STATS */
#ifdef CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM
void z_paging_histogram_init(void)
{
/*
* Zero out the histogram structs and copy the bounds.
* The copying is done as the histogram structs need
* to be pinned in memory and never swapped out, while
* the source bound array may not be pinned.
*/
memset(&z_paging_histogram_eviction, 0, sizeof(z_paging_histogram_eviction));
memcpy(z_paging_histogram_eviction.bounds,
k_mem_paging_eviction_histogram_bounds,
sizeof(z_paging_histogram_eviction.bounds));
memset(&z_paging_histogram_backing_store_page_in, 0,
sizeof(z_paging_histogram_backing_store_page_in));
memcpy(z_paging_histogram_backing_store_page_in.bounds,
k_mem_paging_backing_store_histogram_bounds,
sizeof(z_paging_histogram_backing_store_page_in.bounds));
memset(&z_paging_histogram_backing_store_page_out, 0,
sizeof(z_paging_histogram_backing_store_page_out));
memcpy(z_paging_histogram_backing_store_page_out.bounds,
k_mem_paging_backing_store_histogram_bounds,
sizeof(z_paging_histogram_backing_store_page_out.bounds));
}
/**
* Increment the counter in the timing histogram.
*
* @param hist The timing histogram to be updated.
* @param cycles Time spent in measured operation.
*/
void z_paging_histogram_inc(struct k_mem_paging_histogram_t *hist,
uint32_t cycles)
{
int idx;
for (idx = 0;
idx < CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM_NUM_BINS;
idx++) {
if (cycles <= hist->bounds[idx]) {
hist->counts[idx]++;
break;
}
}
}
void z_impl_k_mem_paging_histogram_eviction_get(
struct k_mem_paging_histogram_t *hist)
{
if (hist == NULL) {
return;
}
/* Copy statistics */
memcpy(hist, &z_paging_histogram_eviction,
sizeof(z_paging_histogram_eviction));
}
void z_impl_k_mem_paging_histogram_backing_store_page_in_get(
struct k_mem_paging_histogram_t *hist)
{
if (hist == NULL) {
return;
}
/* Copy histogram */
memcpy(hist, &z_paging_histogram_backing_store_page_in,
sizeof(z_paging_histogram_backing_store_page_in));
}
void z_impl_k_mem_paging_histogram_backing_store_page_out_get(
struct k_mem_paging_histogram_t *hist)
{
if (hist == NULL) {
return;
}
/* Copy histogram */
memcpy(hist, &z_paging_histogram_backing_store_page_out,
sizeof(z_paging_histogram_backing_store_page_out));
}
#ifdef CONFIG_USERSPACE
static inline
void z_vrfy_k_mem_paging_histogram_eviction_get(
struct k_mem_paging_histogram_t *hist)
{
K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist)));
z_impl_k_mem_paging_histogram_eviction_get(hist);
}
#include <zephyr/syscalls/k_mem_paging_histogram_eviction_get_mrsh.c>
static inline
void z_vrfy_k_mem_paging_histogram_backing_store_page_in_get(
struct k_mem_paging_histogram_t *hist)
{
K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist)));
z_impl_k_mem_paging_histogram_backing_store_page_in_get(hist);
}
#include <zephyr/syscalls/k_mem_paging_histogram_backing_store_page_in_get_mrsh.c>
static inline
void z_vrfy_k_mem_paging_histogram_backing_store_page_out_get(
struct k_mem_paging_histogram_t *hist)
{
K_OOPS(K_SYSCALL_MEMORY_WRITE(hist, sizeof(*hist)));
z_impl_k_mem_paging_histogram_backing_store_page_out_get(hist);
}
#include <zephyr/syscalls/k_mem_paging_histogram_backing_store_page_out_get_mrsh.c>
#endif /* CONFIG_USERSPACE */
#endif /* CONFIG_DEMAND_PAGING_TIMING_HISTOGRAM */