simplify getTimeNowNt() (#1876)

* remove old impl

* add cpp wrapper to os_access

* clean up os_access

* remove touchTimeCounter

* new impl

* put comment about lock free impl

* include cpp wrappers for BL

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-10-15 05:57:13 -07:00 committed by GitHub
parent 906675166e
commit 2083b34cf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 30 additions and 147 deletions

View File

@ -139,6 +139,7 @@ include $(CHIBIOS)/os/hal/osal/rt/osal.mk
# RTOS files (optional).
include $(CHIBIOS)/os/rt/rt.mk
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
include $(CHIBIOS)/os/various/cpp_wrappers/chcpp.mk
include $(CONFIG)/boards/$(PROJECT_BOARD)/board.mk
include $(PROJECT_DIR)/init/init.mk

View File

@ -50,7 +50,6 @@
#include "spark_logic.h"
#include "aux_valves.h"
#include "accelerometer.h"
#include "counter64.h"
#include "perf_trace.h"
#include "boost_control.h"
#include "launch_control.h"
@ -220,8 +219,6 @@ static void doPeriodicSlowCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
#if EFI_ENGINE_CONTROL && EFI_SHAFT_POSITION_INPUT
efiAssertVoid(CUSTOM_ERR_6661, getCurrentRemainingStack() > 64, "lowStckOnEv");
#if EFI_PROD_CODE
touchTimeCounter();
slowStartStopButtonCallback(PASS_ENGINE_PARAMETER_SIGNATURE);
#endif /* EFI_PROD_CODE */

View File

@ -17,7 +17,6 @@ void commonInitEngineController(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_S
void initStartStopButton(DECLARE_ENGINE_PARAMETER_SIGNATURE);
void initDataStructures(DECLARE_ENGINE_PARAMETER_SIGNATURE);
void touchTimeCounter();
void slowStartStopButtonCallback(DECLARE_ENGINE_PARAMETER_SIGNATURE);

View File

@ -7,7 +7,7 @@
#include "engine_controller.h"
#include "perf_trace.h"
#include "counter64.h"
#include "os_access.h"
#include "settings.h"
EXTERN_ENGINE;
@ -84,8 +84,6 @@ void setMockState(brain_pin_e pin, bool state DECLARE_ENGINE_PARAMETER_SUFFIX) {
#endif /* EFI_ENABLE_MOCK_ADC */
#if EFI_PROD_CODE
static Overflow64Counter halTime;
/**
* 64-bit result would not overflow, but that's complex stuff for our 32-bit MCU
*/
@ -95,34 +93,31 @@ efitimeus_t getTimeNowUs(void) {
return getTimeNowNt() / (CORE_CLOCK / 1000000);
}
//todo: macro to save method invocation
efitick_t getTimeNowNt(void) {
#if EFI_PROD_CODE
/* Entering a reentrant critical zone.*/
syssts_t sts = chSysGetStatusAndLockX();
efitime_t localH = halTime.state.highBits;
uint32_t localLow = halTime.state.lowBits;
volatile uint32_t lastLowerNt = 0;
volatile uint32_t upperTimeNt = 0;
uint32_t value = getTimeNowLowerNt();
efitick_t getTimeNowNt() {
chibios_rt::CriticalSectionLocker csl;
if (value < localLow) {
// new value less than previous value means there was an overflow in that 32 bit counter
localH += 0x100000000LL;
uint32_t stamp = getTimeNowLowerNt();
// Lower 32 bits of the timer has wrapped - time to step upper bits
if (stamp < lastLowerNt) {
upperTimeNt++;
}
efitime_t result = localH + value;
lastLowerNt = stamp;
/* Leaving the critical zone.*/
chSysRestoreStatusX(sts);
return result;
#else /* EFI_PROD_CODE */
// todo: why is this implementation not used?
/**
* this method is lock-free and thread-safe, that's because the 'update' method
* is atomic with a critical zone requirement.
*
* http://stackoverflow.com/questions/5162673/how-to-read-two-32bit-counters-as-a-64bit-integer-without-race-condition
*/
return ((int64_t)upperTimeNt << 32) | stamp;
}
/* //Alternative lock free implementation (probably actually slower!)
// this method is lock-free and thread-safe, that's because the 'update' method
// is atomic with a critical zone requirement.
//
// http://stackoverflow.com/questions/5162673/how-to-read-two-32bit-counters-as-a-64bit-integer-without-race-condition
etitick_t getTimeNowNt() {
efitime_t localH;
efitime_t localH2;
uint32_t localLow;
@ -131,14 +126,11 @@ efitick_t getTimeNowNt(void) {
localH = halTime.state.highBits;
localLow = halTime.state.lowBits;
localH2 = halTime.state.highBits;
#if EFI_PROD_CODE
if (counter++ == 10000)
chDbgPanic("lock-free frozen");
#endif /* EFI_PROD_CODE */
} while (localH != localH2);
/**
* We need to take current counter after making a local 64 bit snapshot
*/
// We need to take current counter after making a local 64 bit snapshot
uint32_t value = getTimeNowLowerNt();
if (value < localLow) {
@ -147,20 +139,8 @@ efitick_t getTimeNowNt(void) {
}
return localH + value;
#endif /* EFI_PROD_CODE */
}
void touchTimeCounter() {
/**
* We need to push current value into the 64 bit counter often enough so that we do not miss an overflow
*/
/* Entering a reentrant critical zone.*/
syssts_t sts = chSysGetStatusAndLockX();
updateAndSet(&halTime.state, getTimeNowLowerNt());
/* Leaving the critical zone.*/
chSysRestoreStatusX(sts);
}
*/
static void onStartStopButtonToggle(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
engine->startStopStateToggleCounter++;

View File

@ -9,19 +9,14 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <ch.h>
#include <hal.h>
#include "chprintf.h"
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "io_pins.h"
#ifdef __cplusplus
// ChibiOS c++ wrappers
#include "ch.hpp"
#endif /* __cplusplus */
#define HAS_OS_ACCESS

View File

@ -1,42 +0,0 @@
/*
* counter64.cpp
*
* Created on: Mar 31, 2019
* @author Andrey Belomutskiy, (c) 2012-2020
*/
#include "counter64.h"
/**
* The main use-case of this class is to keep track of a 64-bit global number of CPU ticks from reset.
*
* stm32f4 hardware has a 32-bit Cycle Count Register (CYCCNT), which is incremented with every CPU cycle.
* With 32 bits and 168MHz speed this counter overflows every 4B/168M = 23 seconds. The job of this class is to
* keep track of the current CYCCNT value, detect these overflows, and provide a nice,
* clean 64 bit global cycle counter.
*
* In order for this to function, it's your responsibility to invoke offer() method at least once a second.
*/
Overflow64Counter::Overflow64Counter() {
state.highBits = 0;
state.lowBits = 0;
}
/**
* in order to have atomic writes this should be invoked within a critical section
*/
void updateAndSet(State64 *state, uint32_t value) {
if (value < state->lowBits) {
// new value less than previous value means there was an overflow in that 32 bit counter
state->highBits += 0x100000000LL;
}
state->lowBits = value;
}
#if EFI_UNIT_TEST
efitime_t Overflow64Counter::update(uint32_t value) {
updateAndSet(&state, value);
return state.highBits + state.lowBits;
}
#endif

View File

@ -1,31 +0,0 @@
/*
* @file counter64.h
*
* Created on: Mar 31, 2019
* @author Andrey Belomutskiy, (c) 2012-2020
*/
#pragma once
#include "global.h"
typedef struct {
// todo: would probably be better to keep the high bits as 32 bit field to be sure
volatile efitime_t highBits;
volatile uint32_t lowBits;
} State64;
void updateAndSet(State64 *state, uint32_t value);
class Overflow64Counter
{
public:
Overflow64Counter();
efitime_t get();
#if EFI_UNIT_TEST
efitime_t update(uint32_t value);
#endif
State64 state;
};

View File

@ -8,7 +8,6 @@ UTILSRC = \
UTILSRC_CPP = \
$(UTIL_DIR)/containers/cyclic_buffer.cpp \
$(UTIL_DIR)/containers/listener_array.cpp \
$(UTIL_DIR)/containers/counter64.cpp \
$(UTIL_DIR)/containers/local_version_holder.cpp \
$(UTIL_DIR)/containers/table_helper.cpp \
$(UTIL_DIR)/math/biquad.cpp \

View File

@ -22,7 +22,6 @@
#include "crc.h"
#include "fl_stack.h"
#include "io_pins.h"
#include "counter64.h"
#include "efi_gpio.h"
#include "efilib.h"
@ -66,20 +65,6 @@ TEST(util, crc) {
assertEqualsM("crc32 line inc", 0x4775a7b1, c);
}
TEST(util, Overflow64Counter) {
print("*************************************** testOverflow64Counter\r\n");
Overflow64Counter o;
ASSERT_EQ(0, o.update(0));
ASSERT_EQ(10, o.update(10));
ASSERT_EQ(20, o.update(20));
// overflow
ASSERT_EQ(4294967296, o.update(0));
}
TEST(util, cyclicBufferContains) {
cyclic_buffer<int> sb;
sb.add(10);