]> granicus.if.org Git - esp-idf/commitdiff
freertos: Inline vPortCPUAcquireMutex/vPortCPUReleaseMutex into implementations
authorAngus Gratton <angus@espressif.com>
Thu, 16 Feb 2017 05:56:06 +0000 (16:56 +1100)
committerAngus Gratton <gus@projectgus.com>
Mon, 4 Sep 2017 09:11:51 +0000 (19:11 +1000)
Further improves performance:
No contention -> 134 cycles
Recursion -> 117 cycles
Contention -> 323 cycles

components/freertos/include/freertos/portmacro.h
components/freertos/port.c
components/freertos/portmux_impl.h [new file with mode: 0644]
components/freertos/tasks.c

index f55eeefe0c7a20d4fff358cd729577c9ac3d54f5..336737de94ecde0577dabf84a493253563141d65 100644 (file)
@@ -199,8 +199,6 @@ void vPortCPUInitializeMutex(portMUX_TYPE *mux);
 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
 void vPortCPUAcquireMutex(portMUX_TYPE *mux, const char *function, int line);
 portBASE_TYPE vPortCPUReleaseMutex(portMUX_TYPE *mux, const char *function, int line);
-void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *function, int line);
-portBASE_TYPE vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *function, int line);
 void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line );
 void vTaskExitCritical( portMUX_TYPE *mux, const char *function, int line );
 #define portENTER_CRITICAL(mux)        vTaskEnterCritical(mux, __FUNCTION__, __LINE__)
@@ -212,8 +210,6 @@ void vTaskExitCritical( portMUX_TYPE *mux );
 void vTaskEnterCritical( portMUX_TYPE *mux );
 void vPortCPUAcquireMutex(portMUX_TYPE *mux);
 void vPortCPUReleaseMutex(portMUX_TYPE *mux);
-void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux);
-void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux);
 
 #define portENTER_CRITICAL(mux)        vTaskEnterCritical(mux)
 #define portEXIT_CRITICAL(mux)         vTaskExitCritical(mux)
index fda5ed6cfd22eb950af32551c6f07500195b5b90..3d0fd192e6515e22eaf6347eb53bfed4c9b0fe5f 100644 (file)
@@ -307,6 +307,7 @@ void vPortCPUInitializeMutex(portMUX_TYPE *mux) {
        mux->count=0;
 }
 
+#include "portmux_impl.h"
 
 /*
  * For kernel use: Acquire a per-CPU mux. Spinlocks, so don't hold on to these muxes for too long.
@@ -325,72 +326,6 @@ void vPortCPUAcquireMutex(portMUX_TYPE *mux) {
 }
 #endif
 
-/* XOR one core ID with this value to get the other core ID */
-#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
-
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
-#else
-void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux) {
-#endif
-#if !CONFIG_FREERTOS_UNICORE
-       uint32_t res;
-       portBASE_TYPE coreID, otherCoreID;
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-       uint32_t timeout=(1<<16);
-       uint32_t owner = mux->owner;
-       if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
-               ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
-               mux->owner=portMUX_FREE_VAL;
-       }
-#endif
-
-       /* Spin until we own the core */
-
-       RSR(PRID, coreID);
-       /* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
-          not the 0/1 value returned by xPortGetCoreID()
-       */
-       otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
-       do {
-               /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
-                  CORE_ID_APP:
-
-                  - If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
-                  - If "our" coreID, we can drop through immediately.
-                  - If "otherCoreID", we spin here.
-                */
-               res = coreID;
-               uxPortCompareSet(&mux->owner, portMUX_FREE_VAL, &res);
-
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-               timeout--;
-               if (timeout == 0) {
-                       ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
-                       ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count);
-               }
-#endif
-       } while (res == otherCoreID);
-
-       assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */
-       assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */
-    assert(mux->count < 0xFF); /* Bad count value implies memory corruption */
-
-       /* now we own it, we can increment the refcount */
-       mux->count++;
-
-
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-       if (res==portMUX_FREE_VAL) { //initial lock
-               mux->lastLockedFn=fnName;
-               mux->lastLockedLine=line;
-       } else {
-               ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1,
-                                  mux->lastLockedFn, mux->lastLockedLine, fnName, line);
-       }
-#endif
-#endif
-}
 
 /*
  * For kernel use: Release a per-CPU mux
@@ -411,58 +346,12 @@ void vPortCPUReleaseMutex(portMUX_TYPE *mux) {
 }
 #endif
 
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
-#else
-void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux) {
-#endif
-#if !CONFIG_FREERTOS_UNICORE
-       portBASE_TYPE coreID;
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-       const char *lastLockedFn=mux->lastLockedFn;
-       int lastLockedLine=mux->lastLockedLine;
-       mux->lastLockedFn=fnName;
-       mux->lastLockedLine=line;
-       uint32_t owner = mux->owner;
-       if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
-               ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
-       }
-#endif
-
-#if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
-       RSR(PRID, coreID);
-#endif
-
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
-       if (coreID != mux->owner) {
-               ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
-               ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
-       }
-#endif
-
-    assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
-    assert(mux->count > 0); // Indicates memory corruption
-    assert(mux->count < 0x100); // Indicates memory corruption
-
-       mux->count--;
-       if(mux->count == 0) {
-               mux->owner = portMUX_FREE_VAL;
-       }
-#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
-       else {
-               ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
-       }
-#endif
-#endif //!CONFIG_FREERTOS_UNICORE
-}
-
 #if CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
 void vPortFirstTaskHook(TaskFunction_t function) {
        esp_set_breakpoint_if_jtag(function);
 }
 #endif
 
-
 void vPortSetStackWatchpoint( void* pxStackStart ) {
        //Set watchpoint 1 to watch the last 32 bytes of the stack.
        //Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
diff --git a/components/freertos/portmux_impl.h b/components/freertos/portmux_impl.h
new file mode 100644 (file)
index 0000000..fece3aa
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+    Copyright (C) 2016-2017 Espressif Shanghai PTE LTD
+    Copyright (C) 2015 Real Time Engineers Ltd.
+
+    All rights reserved
+
+    FreeRTOS is free software; you can redistribute it and/or modify it under
+    the terms of the GNU General Public License (version 2) as published by the
+    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+       ***************************************************************************
+    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
+    >>!   distribute a combined work that includes FreeRTOS without being   !<<
+    >>!   obliged to provide the source code for proprietary components     !<<
+    >>!   outside of the FreeRTOS kernel.                                   !<<
+       ***************************************************************************
+
+    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
+    link: http://www.freertos.org/a00114.html
+*/
+
+/* This header exists for performance reasons, in order to inline the
+   implementation of vPortCPUAcquireMutexIntsDisabled and
+   vPortCPUReleaseMutexIntsDisabled into the
+   vTaskEnterCritical/vTaskExitCritical functions as well as the
+   vPortCPUAcquireMutex/vPortCPUReleaseMutex implementations.
+
+   Normally this kind of performance hack is over the top, but these
+   functions get used a great deal by FreeRTOS internals.
+
+   It should be #included by freertos port.c or tasks.c, in esp-idf.
+*/
+#include "soc/cpu.h"
+
+/* XOR one core ID with this value to get the other core ID */
+#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
+
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+static inline void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
+#else
+static inline void vPortCPUAcquireMutexIntsDisabled(portMUX_TYPE *mux) {
+#endif
+#if !CONFIG_FREERTOS_UNICORE
+       uint32_t res;
+       portBASE_TYPE coreID, otherCoreID;
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+       uint32_t timeout=(1<<16);
+       uint32_t owner = mux->owner;
+       if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
+               ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
+               mux->owner=portMUX_FREE_VAL;
+       }
+#endif
+
+       /* Spin until we own the core */
+
+       RSR(PRID, coreID);
+       /* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
+          not the 0/1 value returned by xPortGetCoreID()
+       */
+       otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
+       do {
+               /* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
+                  CORE_ID_APP:
+
+                  - If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
+                  - If "our" coreID, we can drop through immediately.
+                  - If "otherCoreID", we spin here.
+                */
+               res = coreID;
+               uxPortCompareSet(&mux->owner, portMUX_FREE_VAL, &res);
+
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+               timeout--;
+               if (timeout == 0) {
+                       ets_printf("Timeout on mux! last non-recursive lock %s line %d, curr %s line %d\n", mux->lastLockedFn, mux->lastLockedLine, fnName, line);
+                       ets_printf("Owner 0x%x count %d\n", mux->owner, mux->count);
+               }
+#endif
+       } while (res == otherCoreID);
+
+       assert(res == coreID || res == portMUX_FREE_VAL); /* any other value implies memory corruption or uninitialized mux */
+       assert((res == portMUX_FREE_VAL) == (mux->count == 0)); /* we're first to lock iff count is zero */
+    assert(mux->count < 0xFF); /* Bad count value implies memory corruption */
+
+       /* now we own it, we can increment the refcount */
+       mux->count++;
+
+
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+       if (res==portMUX_FREE_VAL) { //initial lock
+               mux->lastLockedFn=fnName;
+               mux->lastLockedLine=line;
+       } else {
+               ets_printf("Recursive lock: count=%d last non-recursive lock %s line %d, curr %s line %d\n", mux->count-1,
+                                  mux->lastLockedFn, mux->lastLockedLine, fnName, line);
+       }
+#endif
+#endif
+}
+
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+static inline void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux, const char *fnName, int line) {
+#else
+static inline void vPortCPUReleaseMutexIntsDisabled(portMUX_TYPE *mux) {
+#endif
+#if !CONFIG_FREERTOS_UNICORE
+       portBASE_TYPE coreID;
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+       const char *lastLockedFn=mux->lastLockedFn;
+       int lastLockedLine=mux->lastLockedLine;
+       mux->lastLockedFn=fnName;
+       mux->lastLockedLine=line;
+       uint32_t owner = mux->owner;
+       if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
+               ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
+       }
+#endif
+
+#if CONFIG_FREERTOS_PORTMUX_DEBUG || !defined(NDEBUG)
+       RSR(PRID, coreID);
+#endif
+
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
+       if (coreID != mux->owner) {
+               ets_printf("ERROR: vPortCPUReleaseMutex: mux %p was already unlocked!\n", mux);
+               ets_printf("Last non-recursive unlock %s line %d, curr unlock %s line %d\n", lastLockedFn, lastLockedLine, fnName, line);
+       }
+#endif
+
+    assert(coreID == mux->owner); // This is a mutex we didn't lock, or it's corrupt
+    assert(mux->count > 0); // Indicates memory corruption
+    assert(mux->count < 0x100); // Indicates memory corruption
+
+       mux->count--;
+       if(mux->count == 0) {
+               mux->owner = portMUX_FREE_VAL;
+       }
+#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG_RECURSIVE
+       else {
+               ets_printf("Recursive unlock: count=%d last locked %s line %d, curr %s line %d\n", mux->count, lastLockedFn, lastLockedLine, fnName, line);
+       }
+#endif
+#endif //!CONFIG_FREERTOS_UNICORE
+}
index 74dec7fbde485287541fa23f9bb0d25bd90b83f6..7101c5a18ff5c85b9d7361ef8c8c4d60e7def235 100644 (file)
@@ -4103,6 +4103,7 @@ For ESP32 FreeRTOS, vTaskEnterCritical implements both portENTER_CRITICAL and po
 
 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
 
+#include "portmux_impl.h"
 
 #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
        void vTaskEnterCritical( portMUX_TYPE *mux, const char *function, int line )