kopia lustrzana https://github.com/espressif/esp-idf
ci: Delete ccomp_timer in IDF(witch has been moved to component manager)
rodzic
2327c5cd00
commit
0f83970368
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
ccomp_timer: "^1.0.0"
|
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
ccomp_timer: "^1.0.0"
|
|
@ -0,0 +1,2 @@
|
|||
dependencies:
|
||||
ccomp_timer: "^1.0.0"
|
|
@ -1,5 +1,4 @@
|
|||
set(srcs "ccomp_timer.c"
|
||||
"memory_checks.c"
|
||||
set(srcs "memory_checks.c"
|
||||
"test_runner.c"
|
||||
"test_utils.c")
|
||||
|
||||
|
@ -14,17 +13,8 @@ else()
|
|||
list(APPEND srcs "ref_clock_impl_timergroup.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_IDF_TARGET_ARCH_RISCV)
|
||||
list(APPEND srcs "ccomp_timer_impl_riscv.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
list(APPEND srcs "ccomp_timer_impl_xtensa.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS private_include
|
||||
REQUIRES esp_partition idf_test cmock
|
||||
PRIV_REQUIRES perfmon driver esp_netif)
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ccomp_timer.h"
|
||||
|
||||
#include "ccomp_timer_impl.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
static const char TAG[] = "ccomp_timer";
|
||||
|
||||
esp_err_t ccomp_timer_start(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
ccomp_timer_impl_lock();
|
||||
if (ccomp_timer_impl_is_init()) {
|
||||
if (ccomp_timer_impl_is_active()) {
|
||||
err = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = ccomp_timer_impl_init();
|
||||
}
|
||||
ccomp_timer_impl_unlock();
|
||||
|
||||
if (err != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = ccomp_timer_impl_reset();
|
||||
|
||||
if (err != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = ccomp_timer_impl_start();
|
||||
|
||||
if (err == ESP_OK) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
fail:
|
||||
ESP_LOGE(TAG, "Unable to start performance timer");
|
||||
return err;
|
||||
}
|
||||
|
||||
int64_t IRAM_ATTR ccomp_timer_stop(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
ccomp_timer_impl_lock();
|
||||
if (!ccomp_timer_impl_is_active()) {
|
||||
err = ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ccomp_timer_impl_unlock();
|
||||
|
||||
if (err != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = ccomp_timer_impl_stop();
|
||||
if (err != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int64_t t = ccomp_timer_get_time();
|
||||
|
||||
err = ccomp_timer_impl_deinit();
|
||||
|
||||
if (err == ESP_OK && t != -1) {
|
||||
return t;
|
||||
}
|
||||
|
||||
fail:
|
||||
ESP_LOGE(TAG, "Unable to stop performance timer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t IRAM_ATTR ccomp_timer_get_time(void)
|
||||
{
|
||||
return ccomp_timer_impl_get_time();
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "freertos/portmacro.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
typedef enum {
|
||||
PERF_TIMER_UNINIT = 0, // timer has not been initialized yet
|
||||
PERF_TIMER_IDLE, // timer has been initialized but is not tracking elapsed time
|
||||
PERF_TIMER_ACTIVE // timer is tracking elapsed time
|
||||
} ccomp_timer_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t last_ccount; // last CCOUNT value, updated every os tick
|
||||
ccomp_timer_state_t state; // state of the timer
|
||||
int64_t ccount; // accumulated processors cycles during the time when timer is active
|
||||
} ccomp_timer_status_t;
|
||||
|
||||
// Each core has its independent timer
|
||||
ccomp_timer_status_t s_status[SOC_CPU_CORES_NUM];
|
||||
|
||||
static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static void IRAM_ATTR update_ccount(void)
|
||||
{
|
||||
if (s_status[esp_cpu_get_core_id()].state == PERF_TIMER_ACTIVE) {
|
||||
int64_t new_ccount = esp_cpu_get_cycle_count();
|
||||
if (new_ccount > s_status[esp_cpu_get_core_id()].last_ccount) {
|
||||
s_status[esp_cpu_get_core_id()].ccount += new_ccount - s_status[esp_cpu_get_core_id()].last_ccount;
|
||||
} else {
|
||||
// CCOUNT has wrapped around
|
||||
s_status[esp_cpu_get_core_id()].ccount += new_ccount + (UINT32_MAX - s_status[esp_cpu_get_core_id()].last_ccount);
|
||||
}
|
||||
s_status[esp_cpu_get_core_id()].last_ccount = new_ccount;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_init(void)
|
||||
{
|
||||
s_status[esp_cpu_get_core_id()].state = PERF_TIMER_IDLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_deinit(void)
|
||||
{
|
||||
s_status[esp_cpu_get_core_id()].state = PERF_TIMER_UNINIT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_start(void)
|
||||
{
|
||||
s_status[esp_cpu_get_core_id()].state = PERF_TIMER_ACTIVE;
|
||||
s_status[esp_cpu_get_core_id()].last_ccount = esp_cpu_get_cycle_count();
|
||||
// Update elapsed cycles every OS tick
|
||||
esp_register_freertos_tick_hook_for_cpu(update_ccount, esp_cpu_get_core_id());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR ccomp_timer_impl_stop(void)
|
||||
{
|
||||
esp_deregister_freertos_tick_hook_for_cpu(update_ccount, esp_cpu_get_core_id());
|
||||
update_ccount();
|
||||
s_status[esp_cpu_get_core_id()].state = PERF_TIMER_IDLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int64_t IRAM_ATTR ccomp_timer_impl_get_time(void)
|
||||
{
|
||||
update_ccount();
|
||||
int64_t cycles = s_status[esp_cpu_get_core_id()].ccount;
|
||||
return (cycles * 1000000) / esp_clk_cpu_freq();
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_reset(void)
|
||||
{
|
||||
s_status[esp_cpu_get_core_id()].ccount = 0;
|
||||
s_status[esp_cpu_get_core_id()].last_ccount = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool ccomp_timer_impl_is_init(void)
|
||||
{
|
||||
return s_status[esp_cpu_get_core_id()].state != PERF_TIMER_UNINIT;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR ccomp_timer_impl_is_active(void)
|
||||
{
|
||||
return s_status[esp_cpu_get_core_id()].state == PERF_TIMER_ACTIVE;
|
||||
}
|
||||
|
||||
void IRAM_ATTR ccomp_timer_impl_lock(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR ccomp_timer_impl_unlock(void)
|
||||
{
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccomp_timer_impl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "eri.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "perfmon.h"
|
||||
#include "xtensa/core-macros.h"
|
||||
#include "xtensa/xt_perf_consts.h"
|
||||
#include "xtensa-debug-module.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
|
||||
#define D_STALL_COUNTER_ID 0
|
||||
#define I_STALL_COUNTER_ID 1
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PERF_TIMER_UNINIT = 0, // timer has not been initialized yet
|
||||
PERF_TIMER_IDLE, // timer has been initialized but is not tracking elapsed time
|
||||
PERF_TIMER_ACTIVE // timer is tracking elapsed time
|
||||
} ccomp_timer_state_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int i_ovfl; // number of times instruction stall counter has overflowed
|
||||
int d_ovfl; // number of times data stall counter has overflowed
|
||||
uint32_t last_ccount; // last CCOUNT value, updated every os tick
|
||||
ccomp_timer_state_t state; // state of the timer
|
||||
intr_handle_t intr_handle; // handle to allocated handler for perfmon counter overflows, so that it can be freed during deinit
|
||||
int64_t ccount; // accumulated processors cycles during the time when timer is active
|
||||
} ccomp_timer_status_t;
|
||||
|
||||
// Each core has its independent timer
|
||||
ccomp_timer_status_t s_status[] = {
|
||||
(ccomp_timer_status_t){
|
||||
.i_ovfl = 0,
|
||||
.d_ovfl = 0,
|
||||
.ccount = 0,
|
||||
.last_ccount = 0,
|
||||
.state = PERF_TIMER_UNINIT,
|
||||
.intr_handle = NULL,
|
||||
},
|
||||
(ccomp_timer_status_t){
|
||||
.i_ovfl = 0,
|
||||
.d_ovfl = 0,
|
||||
.ccount = 0,
|
||||
.last_ccount = 0,
|
||||
.state = PERF_TIMER_UNINIT,
|
||||
.intr_handle = NULL
|
||||
}
|
||||
};
|
||||
|
||||
static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static void IRAM_ATTR update_ccount(void)
|
||||
{
|
||||
if (s_status[xPortGetCoreID()].state == PERF_TIMER_ACTIVE) {
|
||||
int64_t new_ccount = xthal_get_ccount();
|
||||
if (new_ccount > s_status[xPortGetCoreID()].last_ccount) {
|
||||
s_status[xPortGetCoreID()].ccount += new_ccount - s_status[xPortGetCoreID()].last_ccount;
|
||||
} else {
|
||||
// CCOUNT has wrapped around
|
||||
s_status[xPortGetCoreID()].ccount += new_ccount + (UINT32_MAX - s_status[xPortGetCoreID()].last_ccount);
|
||||
}
|
||||
s_status[xPortGetCoreID()].last_ccount = new_ccount;
|
||||
}
|
||||
}
|
||||
|
||||
static void inline update_overflow(int id, int *cnt)
|
||||
{
|
||||
uint32_t pmstat = eri_read(ERI_PERFMON_PMSTAT0 + id * sizeof(int32_t));
|
||||
if (pmstat & PMSTAT_OVFL) {
|
||||
*cnt += 1;
|
||||
// Clear overflow and PerfMonInt asserted bits. The only valid bits in PMSTAT is the ones we're trying to clear. So it should be
|
||||
// ok to just modify the whole register.
|
||||
eri_write(ERI_PERFMON_PMSTAT0 + id, ~0x0);
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR perf_counter_overflow_handler(void *args)
|
||||
{
|
||||
update_overflow(D_STALL_COUNTER_ID, &s_status[xPortGetCoreID()].d_ovfl);
|
||||
update_overflow(I_STALL_COUNTER_ID, &s_status[xPortGetCoreID()].i_ovfl);
|
||||
}
|
||||
|
||||
static void set_perfmon_interrupt(bool enable)
|
||||
{
|
||||
uint32_t d_pmctrl = eri_read(ERI_PERFMON_PMCTRL0 + D_STALL_COUNTER_ID * sizeof(int32_t));
|
||||
uint32_t i_pmctrl = eri_read(ERI_PERFMON_PMCTRL0 + I_STALL_COUNTER_ID * sizeof(int32_t));
|
||||
|
||||
if (enable) {
|
||||
d_pmctrl |= PMCTRL_INTEN;
|
||||
i_pmctrl |= PMCTRL_INTEN;
|
||||
}
|
||||
else {
|
||||
d_pmctrl &= ~PMCTRL_INTEN;
|
||||
i_pmctrl &= ~PMCTRL_INTEN;
|
||||
}
|
||||
|
||||
eri_write(ERI_PERFMON_PMCTRL0 + D_STALL_COUNTER_ID * sizeof(int32_t), d_pmctrl);
|
||||
eri_write(ERI_PERFMON_PMCTRL0 + I_STALL_COUNTER_ID * sizeof(int32_t), i_pmctrl);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t ccomp_timer_impl_init(void)
|
||||
{
|
||||
// Keep track of how many times each counter has overflowed.
|
||||
esp_err_t err = esp_intr_alloc(ETS_INTERNAL_PROFILING_INTR_SOURCE, 0,
|
||||
perf_counter_overflow_handler, NULL, &s_status[xPortGetCoreID()].intr_handle);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
xtensa_perfmon_init(D_STALL_COUNTER_ID,
|
||||
XTPERF_CNT_D_STALL,
|
||||
XTPERF_MASK_D_STALL_BUSY, 0, -1);
|
||||
xtensa_perfmon_init(I_STALL_COUNTER_ID,
|
||||
XTPERF_CNT_I_STALL,
|
||||
XTPERF_MASK_I_STALL_BUSY, 0, -1);
|
||||
|
||||
set_perfmon_interrupt(true);
|
||||
s_status[xPortGetCoreID()].state = PERF_TIMER_IDLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_deinit(void)
|
||||
{
|
||||
set_perfmon_interrupt(false);
|
||||
|
||||
esp_err_t err = esp_intr_free(s_status[xPortGetCoreID()].intr_handle);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
s_status[xPortGetCoreID()].intr_handle = NULL;
|
||||
s_status[xPortGetCoreID()].state = PERF_TIMER_UNINIT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_start(void)
|
||||
{
|
||||
s_status[xPortGetCoreID()].state = PERF_TIMER_ACTIVE;
|
||||
s_status[xPortGetCoreID()].last_ccount = xthal_get_ccount();
|
||||
// Update elapsed cycles every OS tick
|
||||
esp_register_freertos_tick_hook_for_cpu(update_ccount, xPortGetCoreID());
|
||||
xtensa_perfmon_start();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t IRAM_ATTR ccomp_timer_impl_stop(void)
|
||||
{
|
||||
xtensa_perfmon_stop();
|
||||
esp_deregister_freertos_tick_hook_for_cpu(update_ccount, xPortGetCoreID());
|
||||
update_ccount();
|
||||
s_status[xPortGetCoreID()].state = PERF_TIMER_IDLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int64_t IRAM_ATTR ccomp_timer_impl_get_time(void)
|
||||
{
|
||||
update_ccount();
|
||||
int64_t d_stalls = xtensa_perfmon_value(D_STALL_COUNTER_ID) +
|
||||
s_status[xPortGetCoreID()].d_ovfl * (1 << sizeof(int32_t));
|
||||
int64_t i_stalls = xtensa_perfmon_value(I_STALL_COUNTER_ID) +
|
||||
s_status[xPortGetCoreID()].i_ovfl * (1 << sizeof(int32_t));
|
||||
int64_t stalls = d_stalls + i_stalls;
|
||||
int64_t cycles = s_status[xPortGetCoreID()].ccount;
|
||||
return ((cycles - stalls) * 1000000) / esp_clk_cpu_freq();
|
||||
}
|
||||
|
||||
esp_err_t ccomp_timer_impl_reset(void)
|
||||
{
|
||||
xtensa_perfmon_reset(D_STALL_COUNTER_ID);
|
||||
xtensa_perfmon_reset(I_STALL_COUNTER_ID);
|
||||
s_status[xPortGetCoreID()].d_ovfl = 0;
|
||||
s_status[xPortGetCoreID()].i_ovfl = 0;
|
||||
s_status[xPortGetCoreID()].ccount = 0;
|
||||
s_status[xPortGetCoreID()].last_ccount = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool ccomp_timer_impl_is_init(void)
|
||||
{
|
||||
return s_status[xPortGetCoreID()].state != PERF_TIMER_UNINIT;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR ccomp_timer_impl_is_active(void)
|
||||
{
|
||||
return s_status[xPortGetCoreID()].state == PERF_TIMER_ACTIVE;
|
||||
}
|
||||
|
||||
void IRAM_ATTR ccomp_timer_impl_lock(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
}
|
||||
|
||||
void IRAM_ATTR ccomp_timer_impl_unlock(void)
|
||||
{
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Start the timer on the current core.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_STATE: The timer has already been started previously.
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_start(void);
|
||||
|
||||
/**
|
||||
* @brief Stop the timer on the current core.
|
||||
*
|
||||
* @note Returns -1 if an error has occured and stopping the timer failed.
|
||||
*
|
||||
* @return The time elapsed from the last ccomp_timer_start call on the current
|
||||
* core.
|
||||
*/
|
||||
int64_t ccomp_timer_stop(void);
|
||||
|
||||
/**
|
||||
* Return the current timer value on the current core without stopping the timer.
|
||||
*
|
||||
* @note Returns -1 if an error has occured and stopping the timer failed.
|
||||
*
|
||||
* @note If called while timer is active i.e. between ccomp_timer_start and ccomp_timer_stop,
|
||||
* this function returns the elapsed time from ccomp_timer_start. Once ccomp_timer_stop
|
||||
* has been called, the timer becomes inactive and stops keeping time. As a result, if this function gets
|
||||
* called after esp_cccomp_timer_stop, this function will return the same value as when the timer was stopped.
|
||||
*
|
||||
* @return The elapsed time from the last ccomp_timer_start call on the current
|
||||
* core.
|
||||
*/
|
||||
int64_t ccomp_timer_get_time(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,102 +0,0 @@
|
|||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize the underlying implementation for cache compensated timer. This might involve
|
||||
* setting up architecture-specific event counters and or allocating interrupts that handle events for those counters.
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_STATE: The timer has already been started previously.
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_impl_init(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the underlying implementation for cache compensated timer. This should restore
|
||||
* the state of the program to before ccomp_timer_impl_init.
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - ESP_ERR_INVALID_STATE: The timer has already been started previously.
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_impl_deinit(void);
|
||||
|
||||
/**
|
||||
* @brief Make the underlying implementation start keeping time.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_impl_start(void);
|
||||
|
||||
/**
|
||||
* @brief Make the underlying implementation stop keeping time.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_impl_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Reset the timer to its initial state.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: Success
|
||||
* - Others: Fail
|
||||
*/
|
||||
esp_err_t ccomp_timer_impl_reset(void);
|
||||
|
||||
/**
|
||||
* @brief Get the elapsed time kept track of by the underlying implementation in microseconds.
|
||||
*
|
||||
* @return The elapsed time in microseconds. Set to -1 if the operation is unsuccessful.
|
||||
*/
|
||||
int64_t ccomp_timer_impl_get_time(void);
|
||||
|
||||
/**
|
||||
* @brief Obtain an internal critical section used in the implementation. Should be treated
|
||||
* as a spinlock.
|
||||
*/
|
||||
void ccomp_timer_impl_lock(void);
|
||||
|
||||
/**
|
||||
* @brief Start the performance timer on the current core.
|
||||
*/
|
||||
void ccomp_timer_impl_unlock(void);
|
||||
|
||||
/**
|
||||
* @brief Check if timer has been initialized.
|
||||
*
|
||||
* @return
|
||||
* - true: the timer has been initialized using ccomp_timer_impl_init
|
||||
* - false: the timer has not been initialized, or ccomp_timer_impl_deinit has been called recently
|
||||
*/
|
||||
bool ccomp_timer_impl_is_init(void);
|
||||
|
||||
/**
|
||||
* @brief Check if timer is keeping time.
|
||||
*
|
||||
* @return
|
||||
* - true: the timer is keeping track of elapsed time from ccomp_timer_impl_start
|
||||
* - false: the timer is not keeping track of elapsed time since ccomp_timer_impl_start has not yet been called or ccomp_timer_impl_stop has been called recently
|
||||
*/
|
||||
bool ccomp_timer_impl_is_active(void);
|
|
@ -1,167 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "ccomp_timer.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
#include "esp_ipc.h"
|
||||
#endif
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
static void start_timer(void *param)
|
||||
{
|
||||
esp_err_t *err = (esp_err_t *)param;
|
||||
*err = ccomp_timer_start();
|
||||
}
|
||||
|
||||
static void stop_timer(void *param)
|
||||
{
|
||||
int64_t *t = (int64_t *)param;
|
||||
*t = ccomp_timer_stop();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void computation(void *param)
|
||||
{
|
||||
int *l = (int *)param;
|
||||
for (volatile int i = 0, a = 0; i < *l; i++)
|
||||
{
|
||||
a += i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("starting and stopping works", "[test_utils][ccomp_timer]")
|
||||
{
|
||||
esp_err_t err;
|
||||
int64_t t;
|
||||
|
||||
/*
|
||||
* Test on the same task
|
||||
*/
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
// Start an already started timer
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, err);
|
||||
|
||||
t = ccomp_timer_stop();
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t);
|
||||
|
||||
// Stopping a non started timer
|
||||
t = ccomp_timer_stop();
|
||||
TEST_ASSERT_EQUAL(-1, t);
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
/*
|
||||
* Test on different task on same core
|
||||
*/
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
esp_ipc_call_blocking(xPortGetCoreID(), start_timer, &err);
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, err);
|
||||
|
||||
t = ccomp_timer_stop();
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t);
|
||||
|
||||
esp_ipc_call_blocking(xPortGetCoreID(), stop_timer, &t);
|
||||
TEST_ASSERT_EQUAL(-1, t);
|
||||
|
||||
/*
|
||||
* Timer being stopped from another task on the same core
|
||||
*/
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
esp_ipc_call_blocking(xPortGetCoreID(), stop_timer, &t);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t);
|
||||
|
||||
/*
|
||||
* Test on different task on same core
|
||||
*/
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, start_timer, &err);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
t = ccomp_timer_stop();
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t);
|
||||
|
||||
esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, stop_timer, &t);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("getting the time works", "[test_utils][ccomp_timer]")
|
||||
{
|
||||
// Get wall time and start ccomp timer
|
||||
int64_t start = esp_timer_get_time();
|
||||
ccomp_timer_start();
|
||||
|
||||
int64_t t_a = ccomp_timer_get_time();
|
||||
|
||||
int temp = 10000;
|
||||
computation(&temp);
|
||||
|
||||
int64_t t_b = ccomp_timer_get_time();
|
||||
|
||||
// Check that ccomp time after computation is more than
|
||||
// ccomp time before computation.
|
||||
TEST_ASSERT_LESS_THAN(t_b, t_a);
|
||||
|
||||
// Get time diff between wall time and ccomp time
|
||||
int64_t t_1 = ccomp_timer_stop();
|
||||
int64_t t_2 = esp_timer_get_time() - start;
|
||||
|
||||
// The times should at least be in the same ballpark (at least within 10%)
|
||||
float diff = (llabs(t_1 - t_2)) / ((float)t_2);
|
||||
TEST_ASSERT(diff <= 10.0f);
|
||||
|
||||
// Since the timer was already stopped, test that ccomp_timer_get_time
|
||||
// returns the same time as ccomp_timer_stop
|
||||
int64_t t_c = ccomp_timer_get_time();
|
||||
TEST_ASSERT_EQUAL(t_1, t_c);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
TEST_CASE("timers for each core counts independently", "[test_utils][ccomp_timer]")
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
// Start a timer on this core
|
||||
err = ccomp_timer_start();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
// Do some work on this core
|
||||
int temp = 10000;
|
||||
computation(&temp);
|
||||
|
||||
// Start a timer on the other core
|
||||
esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, start_timer, &err);
|
||||
TEST_ASSERT_EQUAL(ESP_OK, err);
|
||||
|
||||
// Do some work on other core (less work than this core did)
|
||||
temp = 5000;
|
||||
esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, computation, &temp);
|
||||
|
||||
// Stop timers from both cores
|
||||
int64_t t_1 = ccomp_timer_stop();
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t_1);
|
||||
|
||||
int64_t t_2;
|
||||
esp_ipc_call_blocking(xPortGetCoreID() == 0 ? 1 : 0, stop_timer, &t_2);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL(0, t_2);
|
||||
|
||||
// Since this core did more work, it probably has longer measured time
|
||||
TEST_ASSERT_GREATER_THAN(t_2, t_1);
|
||||
}
|
||||
#endif
|
|
@ -1,180 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "ccomp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define CACHE_WAYS 2
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 15)
|
||||
// Only test half due to lack of memory
|
||||
#define TEST_SIZE (CACHE_SIZE / 2)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
// Default cache configuration - no override specified on
|
||||
// test_utils config
|
||||
#define CACHE_WAYS 8
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 13)
|
||||
#define TEST_SIZE (CACHE_SIZE)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#define CACHE_WAYS 8
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 14)
|
||||
#define TEST_SIZE (CACHE_SIZE)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint8_t **accesses;
|
||||
size_t len;
|
||||
} ccomp_test_access_t;
|
||||
|
||||
typedef struct {
|
||||
int64_t wall;
|
||||
int64_t ccomp;
|
||||
} ccomp_test_time_t;
|
||||
|
||||
/* No performance monitor in RISCV for now
|
||||
*/
|
||||
#if !__riscv
|
||||
//IDF-5052
|
||||
|
||||
static const char* TAG = "test_ccomp_timer";
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
static uint8_t *flash_mem;
|
||||
#else
|
||||
static const uint8_t flash_mem[2 * CACHE_SIZE] = {0};
|
||||
#endif
|
||||
|
||||
static IRAM_ATTR void perform_accesses(ccomp_test_access_t *access)
|
||||
{
|
||||
volatile int a = 0;
|
||||
for (int i = 0; i < access->len; i++) {
|
||||
a += (int)(*(access->accesses[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_cache(const uint8_t *to_cache)
|
||||
{
|
||||
volatile int a = 0;
|
||||
for (int i = 0; i < CACHE_SIZE; i++) {
|
||||
a += to_cache[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_access_pattern(int hit_rate, const uint8_t *cached, ccomp_test_access_t *out)
|
||||
{
|
||||
assert(hit_rate <= 100);
|
||||
assert(hit_rate >= 0);
|
||||
|
||||
int misses = (100 - hit_rate) * CACHE_LINE_SIZE;
|
||||
int hits = hit_rate * CACHE_LINE_SIZE;
|
||||
|
||||
uint8_t **accesses = calloc(TEST_SIZE, sizeof(uint8_t *));
|
||||
|
||||
for (int i = 0, h = 0, i_h = 1, m = -1, i_m = 0; i < TEST_SIZE; i++, h += i_h, m += i_m) {
|
||||
if (i_m) {
|
||||
accesses[i] = (uint8_t*) (cached + CACHE_SIZE + i);
|
||||
}
|
||||
else {
|
||||
accesses[i] = (uint8_t*) (cached + i);
|
||||
}
|
||||
|
||||
if (h >= hits) {
|
||||
h = -1;
|
||||
i_h = 0;
|
||||
|
||||
m = 0;
|
||||
i_m = 1;
|
||||
}
|
||||
|
||||
if (m >= misses) {
|
||||
m = -1;
|
||||
i_m = 0;
|
||||
|
||||
h = 0;
|
||||
i_h = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out->accesses = accesses;
|
||||
out->len = TEST_SIZE;
|
||||
}
|
||||
|
||||
static ccomp_test_time_t perform_test_at_hit_rate(int hit_rate, const uint8_t *mem)
|
||||
{
|
||||
ccomp_test_access_t access;
|
||||
prepare_access_pattern(hit_rate, mem, &access);
|
||||
|
||||
prepare_cache(mem);
|
||||
|
||||
int64_t start = esp_timer_get_time();
|
||||
ccomp_timer_start();
|
||||
perform_accesses(&access);
|
||||
ccomp_test_time_t t = {
|
||||
.ccomp = ccomp_timer_stop(),
|
||||
.wall = esp_timer_get_time() - start
|
||||
};
|
||||
|
||||
free(access.accesses);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static ccomp_test_time_t ccomp_test_ref_time(void)
|
||||
{
|
||||
#if CONFIG_SPIRAM
|
||||
uint8_t *mem = heap_caps_malloc(2 * CACHE_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DEFAULT);
|
||||
#else
|
||||
uint8_t *mem = heap_caps_malloc(sizeof(flash_mem), MALLOC_CAP_INTERNAL | MALLOC_CAP_DEFAULT);
|
||||
#endif
|
||||
ccomp_test_time_t t = perform_test_at_hit_rate(0, mem);
|
||||
free(mem);
|
||||
return t;
|
||||
}
|
||||
|
||||
TEST_CASE("data cache hit rate sweep", "[test_utils][ccomp_timer]")
|
||||
{
|
||||
ccomp_test_time_t t_ref;
|
||||
ccomp_test_time_t t_hr;
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
flash_mem = heap_caps_malloc(2 * CACHE_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
#endif
|
||||
|
||||
// Perform accesses on RAM. The time recorded here serves as
|
||||
// reference.
|
||||
t_ref = ccomp_test_ref_time();
|
||||
|
||||
ESP_LOGI(TAG, "Reference Time(us): %lld", (long long)t_ref.ccomp);
|
||||
|
||||
// Measure time at particular hit rates
|
||||
for (int i = 0; i <= 100; i += 5)
|
||||
{
|
||||
t_hr = perform_test_at_hit_rate(i, flash_mem);
|
||||
float error = (llabs(t_ref.ccomp - t_hr.ccomp) / (float)t_ref.ccomp) * 100.0f;
|
||||
|
||||
ESP_LOGI(TAG, "Hit Rate(%%): %d Wall Time(us): %lld Compensated Time(us): %lld Error(%%): %f", i, (long long)t_hr.wall, (long long)t_hr.ccomp, error);
|
||||
|
||||
// Check if the measured time is at least within some percent of the
|
||||
// reference.
|
||||
TEST_ASSERT(error <= 5.0f);
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
free(flash_mem);
|
||||
#endif
|
||||
}
|
||||
#endif // __riscv
|
|
@ -1,232 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "ccomp_timer.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define CACHE_WAYS 2
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 15)
|
||||
// Only test half due to lack of memory
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
// Default cache configuration - no override specified on
|
||||
// test_utils config
|
||||
#define CACHE_WAYS 8
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 13)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
|
||||
#define CACHE_WAYS 8
|
||||
#define CACHE_LINE_SIZE 32
|
||||
#define CACHE_SIZE (1 << 14)
|
||||
#endif
|
||||
|
||||
typedef void (*ccomp_test_func_t)(void);
|
||||
|
||||
static const char* TAG = "test_ccomp_timer";
|
||||
|
||||
typedef struct {
|
||||
int64_t wall;
|
||||
int64_t ccomp;
|
||||
} ccomp_test_time_t;
|
||||
|
||||
typedef struct {
|
||||
ccomp_test_func_t *funcs;
|
||||
size_t len;
|
||||
} ccomp_test_call_t;
|
||||
|
||||
#define FUNC() \
|
||||
do \
|
||||
{ \
|
||||
volatile int a = 0; \
|
||||
a++; \
|
||||
} while (0);
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func1(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func2(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func3(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
#if TEMPORARY_DISABLED_FOR_TARGETS(ESP32)
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func4(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func5(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func6(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func7(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func8(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
__aligned(CACHE_SIZE / CACHE_WAYS) static void test_func9(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void IRAM_ATTR iram_func(void)
|
||||
{
|
||||
FUNC();
|
||||
}
|
||||
|
||||
static void IRAM_ATTR perform_calls(ccomp_test_call_t *call)
|
||||
{
|
||||
for (int i = 0; i < call->len; i++) {
|
||||
call->funcs[i]();
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR prepare_cache(ccomp_test_call_t *call)
|
||||
{
|
||||
perform_calls(call);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR prepare_calls(int hit_rate, ccomp_test_func_t *alts, size_t alts_len, size_t len, ccomp_test_call_t *out)
|
||||
{
|
||||
assert(hit_rate <= 100);
|
||||
assert(hit_rate >= 0);
|
||||
|
||||
int misses = (100 - hit_rate);
|
||||
int hits = hit_rate;
|
||||
|
||||
ccomp_test_func_t *funcs = calloc(len, sizeof(ccomp_test_func_t));
|
||||
|
||||
for (int i = 0, h = 0, i_h = 1, m = -1, i_m = 0, l = 0; i < len; i++, h += i_h, m += i_m) {
|
||||
funcs[i] = alts[l % alts_len];
|
||||
|
||||
if (i_m) {
|
||||
l++;
|
||||
}
|
||||
|
||||
if (h >= hits) {
|
||||
h = -1;
|
||||
i_h = 0;
|
||||
|
||||
m = 0;
|
||||
i_m = 1;
|
||||
}
|
||||
|
||||
if (m >= misses) {
|
||||
m = -1;
|
||||
i_m = 0;
|
||||
|
||||
h = 0;
|
||||
i_h = 1;
|
||||
}
|
||||
}
|
||||
|
||||
out->funcs = funcs;
|
||||
out->len = len;
|
||||
}
|
||||
|
||||
static ccomp_test_time_t IRAM_ATTR perform_test_at_hit_rate(int hit_rate)
|
||||
{
|
||||
static portMUX_TYPE m = portMUX_INITIALIZER_UNLOCKED;
|
||||
ccomp_test_call_t calls;
|
||||
ccomp_test_func_t alts[] = {test_func1, test_func2, test_func3,
|
||||
#if TEMPORARY_DISABLED_FOR_TARGETS(ESP32)
|
||||
test_func4, test_func5, test_func6, test_func7, test_func8, test_func9,
|
||||
#endif
|
||||
};
|
||||
prepare_calls(hit_rate, alts, sizeof(alts)/sizeof(alts[0]), 10000, &calls);
|
||||
|
||||
ccomp_test_func_t f[] = {test_func1, test_func2};
|
||||
ccomp_test_call_t cache = {
|
||||
.funcs = f,
|
||||
.len = sizeof(f) / sizeof(f[0])};
|
||||
|
||||
portENTER_CRITICAL(&m);
|
||||
|
||||
prepare_cache(&cache);
|
||||
|
||||
int64_t start = esp_timer_get_time();
|
||||
ccomp_timer_start();
|
||||
perform_calls(&calls);
|
||||
ccomp_test_time_t t = {
|
||||
.ccomp = ccomp_timer_stop(),
|
||||
.wall = esp_timer_get_time() - start
|
||||
};
|
||||
|
||||
portEXIT_CRITICAL(&m);
|
||||
|
||||
free(calls.funcs);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static ccomp_test_time_t ccomp_test_ref_time(void)
|
||||
{
|
||||
ccomp_test_call_t calls;
|
||||
ccomp_test_func_t alts[] = {iram_func};
|
||||
prepare_calls(0, alts, 1, 10000, &calls);
|
||||
|
||||
int64_t start = esp_timer_get_time();
|
||||
ccomp_timer_start();
|
||||
perform_calls(&calls);
|
||||
ccomp_test_time_t t = {
|
||||
.ccomp = ccomp_timer_stop(),
|
||||
.wall = esp_timer_get_time() - start
|
||||
};
|
||||
|
||||
free(calls.funcs);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
TEST_CASE("instruction cache hit rate sweep test", "[test_utils][ccomp_timer]")
|
||||
{
|
||||
ccomp_test_time_t t_ref;
|
||||
ccomp_test_time_t t_hr;
|
||||
|
||||
// Perform accesses on RAM. The time recorded here serves as
|
||||
// reference.
|
||||
t_ref = ccomp_test_ref_time();
|
||||
|
||||
ESP_LOGI(TAG, "Reference Time(us): %lld", (long long)t_ref.ccomp);
|
||||
|
||||
// Measure time at particular hit rates
|
||||
for (int i = 0; i <= 100; i += 5)
|
||||
{
|
||||
t_hr = perform_test_at_hit_rate(i);
|
||||
float error = (llabs(t_ref.ccomp - t_hr.ccomp) / (float)t_ref.wall) * 100.0f;
|
||||
|
||||
ESP_LOGI(TAG, "Hit Rate(%%): %d Wall Time(us): %lld Compensated Time(us): %lld Error(%%): %f", i, (long long)t_hr.wall, (long long)t_hr.ccomp, error);
|
||||
|
||||
// Check if the measured time is at least within some percent of the
|
||||
// reference.
|
||||
TEST_ASSERT(error <= 5.0f);
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue