freertos spinlock/portmux: Reduce spinlocking overhead

Ref TW7117

Microbenchmarks in unit tests:

(All numbers in cycles per benchmarked operation):

Release mode
No lock contention lock/unlock -       301 -> 167 (-45%)
Recursive no contention lock/unlock -  289 -> 148 (-49%)
Lock contention two CPUs (lock/unlock) 699 -> 400 (-43%)

Debug mode
No lock contention lock/unlock -       355 -> 203 (-43%)
Recursive no contention lock/unlock -  345 -> 188 (-46%)
Lock contention two CPUs (lock/unlock) 761 -> 483 (-36%)
This commit is contained in:
Angus Gratton
2017-02-13 14:46:37 +11:00
committed by Angus Gratton
parent f2952de3a5
commit 4d42b2d100
6 changed files with 152 additions and 110 deletions

View File

@@ -4111,7 +4111,8 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
#endif
{
BaseType_t oldInterruptLevel=0;
if( xSchedulerRunning != pdFALSE )
BaseType_t schedulerRunning = xSchedulerRunning;
if( schedulerRunning != pdFALSE )
{
//Interrupts may already be disabled (because we're doing this recursively) but we can't get the interrupt level after
//vPortCPUAquireMutex, because it also may mess with interrupts. Get it here first, then later figure out if we're nesting
@@ -4119,26 +4120,27 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
oldInterruptLevel=portENTER_CRITICAL_NESTED();
}
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUAcquireMutex( mux, function, line );
vPortCPUAcquireMutexIntsDisabled( mux, function, line );
#else
vPortCPUAcquireMutex( mux );
vPortCPUAcquireMutexIntsDisabled( mux );
#endif
if( xSchedulerRunning != pdFALSE )
if( schedulerRunning != pdFALSE )
{
( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting )++;
if( xSchedulerRunning != pdFALSE && pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 1 )
TCB_t *tcb = pxCurrentTCB[xPortGetCoreID()];
BaseType_t newNesting = tcb->uxCriticalNesting + 1;
tcb->uxCriticalNesting = newNesting;
if( newNesting == 1 )
{
//This is the first time we get called. Save original interrupt level.
pxCurrentTCB[ xPortGetCoreID() ]->uxOldInterruptState=oldInterruptLevel;
tcb->uxOldInterruptState = oldInterruptLevel;
}
/* Original FreeRTOS comment, saved for reference:
This is not the interrupt safe version of the enter critical
function so assert() if it is being called from an interrupt
context. Only API functions that end in "FromISR" can be used in an
interrupt. Only assert if the critical nesting count is 1 to
interrupt. Only assert if the critical nesting count is 1 to
protect against recursive calls if the assert function also uses a
critical section. */
@@ -4149,7 +4151,7 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
both from ISR as well as non-ISR code, thus we re-organized
vTaskEnterCritical to also work in ISRs. */
#if 0
if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 1 )
if( newNesting == 1 )
{
portASSERT_IF_IN_ISR();
}
@@ -4178,19 +4180,22 @@ For ESP32 FreeRTOS, vTaskExitCritical implements both portEXIT_CRITICAL and port
#endif
{
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUReleaseMutex( mux, function, line );
vPortCPUReleaseMutexIntsDisabled( mux, function, line );
#else
vPortCPUReleaseMutex( mux );
vPortCPUReleaseMutexIntsDisabled( mux );
#endif
if( xSchedulerRunning != pdFALSE )
{
if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting > 0U )
TCB_t *tcb = pxCurrentTCB[xPortGetCoreID()];
BaseType_t nesting = tcb->uxCriticalNesting;
if( nesting > 0U )
{
( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting )--;
nesting--;
tcb->uxCriticalNesting = nesting;
if( pxCurrentTCB[ xPortGetCoreID() ]->uxCriticalNesting == 0U )
if( nesting == 0U )
{
portEXIT_CRITICAL_NESTED(pxCurrentTCB[ xPortGetCoreID() ]->uxOldInterruptState);
portEXIT_CRITICAL_NESTED(tcb->uxOldInterruptState);
}
else
{