Performance improvement: Idle loop should not take MM semaphore if there is not garbage to be collected. This can cause loss of performance and thrashing in tasking

This commit is contained in:
Gregory Nutt
2016-02-16 19:33:22 -06:00
parent 6dfa72d038
commit 6aeb4a52e8
6 changed files with 103 additions and 13 deletions
+15 -3
View File
@@ -1,7 +1,7 @@
/****************************************************************************
* include/nuttx/kmalloc.h
*
* Copyright (C) 2007-2008, 2011, 2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2008, 2011, 2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -177,7 +177,7 @@ void group_free(FAR struct task_group_s *group, FAR void *mem);
/* Handles memory freed from an interrupt handler. In that context, kmm_free()
* (or kumm_free()) cannot be called. Instead, the allocations are saved in a
* list of delayed allocations that will be periodically cleaned up by
* sched_garbagecollection().
* sched_garbage_collection().
*/
void sched_ufree(FAR void *address);
@@ -196,7 +196,19 @@ void sched_kfree(FAR void *address);
* the system for memory in some context.
*/
void sched_garbagecollection(void);
void sched_garbage_collection(void);
/* Is is not a good idea for the IDLE threads to take the KMM semaphore.
* That can cause the IDLE thread to take processing time from higher
* priority tasks. The IDLE threads will only take the KMM semaphore if
* there is garbage to be collected.
*
* Certainly there is a race condition involved in sampling the garbage
* state. The looping nature of the IDLE loops should catch any missed
* garbage from the test on the next time arround.
*/
bool sched_have_garbage(void);
#undef KMALLOC_EXTERN
#if defined(__cplusplus)
+3 -2
View File
@@ -97,6 +97,7 @@ int os_idletask(int argc, FAR char *argv[])
/* Enter the IDLE loop */
sdbg("CPU%d: Beginning Idle Loop\n", this_cpu());
for (; ; )
{
/* Perform garbage collection (if it is not being done by the worker
@@ -118,9 +119,9 @@ int os_idletask(int argc, FAR char *argv[])
* queue so that is done in a safer context.
*/
if (kmm_trysemaphore() == 0)
if (sched_have_garbage() && kmm_trysemaphore() == 0)
{
sched_garbagecollection();
sched_garbage_collection();
kmm_givesemaphore();
}
#endif
+6 -4
View File
@@ -415,11 +415,13 @@ void os_start(void)
#endif
{
FAR dq_queue_t *tasklist;
int hashndx;
/* Assign the process ID(s) of ZERO to the idle task(s) */
g_pidhash[PIDHASH(g_lastpid)].tcb = &g_idletcb[cpu].cmn;
g_pidhash[PIDHASH(g_lastpid)].pid = g_lastpid;
hashndx = PIDHASH(g_lastpid);
g_pidhash[hashndx].tcb = &g_idletcb[cpu].cmn;
g_pidhash[hashndx].pid = g_lastpid;
/* Initialize a TCB for this thread of execution. NOTE: The default
* value for most components of the g_idletcb are zero. The entire
@@ -783,9 +785,9 @@ void os_start(void)
* queue so that is done in a safer context.
*/
if (kmm_trysemaphore() == 0)
if (sched_have_garbage() && kmm_trysemaphore() == 0)
{
sched_garbagecollection();
sched_garbage_collection();
kmm_givesemaphore();
}
#endif
+77 -2
View File
@@ -104,6 +104,29 @@ static inline void sched_kucleanup(void)
#endif
}
/****************************************************************************
* Name: sched_have_kugarbage
*
* Description:
* Return TRUE if there is user heap garbage to be collected.
*
* Input parameters:
* None
*
* Returned Value:
* TRUE if there is kernel heap garbage to be collected.
*
****************************************************************************/
#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \
defined(CONFIG_MM_KERNEL_HEAP)
static inline bool sched_have_kugarbage(void)
{
return (g_delayed_kufree.head != NULL);
#else
# define sched_have_kugarbage() false
#endif
/****************************************************************************
* Name: sched_kcleanup
*
@@ -155,11 +178,35 @@ static inline void sched_kcleanup(void)
# define sched_kcleanup()
#endif
/****************************************************************************
* Name: sched_have_kgarbage
*
* Description:
* Return TRUE if there is kernal heap garbage to be collected.
*
* Input parameters:
* None
*
* Returned Value:
* TRUE if there is kernel heap garbage to be collected.
*
****************************************************************************/
#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \
defined(CONFIG_MM_KERNEL_HEAP)
static inline bool sched_have_kgarbage(void)
{
return (g_delayed_kfree.head != NULL);
#else
# define sched_have_kgarbage() false
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sched_garbagecollection
* Name: sched_garbage_collection
*
* Description:
* Clean-up memory de-allocations that we queued because they could not
@@ -180,7 +227,7 @@ static inline void sched_kcleanup(void)
*
****************************************************************************/
void sched_garbagecollection(void)
void sched_garbage_collection(void)
{
/* Handle deferred deallocations for the kernel heap */
@@ -190,3 +237,31 @@ void sched_garbagecollection(void)
sched_kucleanup();
}
/****************************************************************************
* Name: sched_have_garbage
*
* Description:
* Return TRUE if there is garbage to be collected.
*
* Is is not a good idea for the IDLE threads to take the KMM semaphore.
* That can cause the IDLE thread to take processing time from higher
* priority tasks. The IDLE threads will only take the KMM semaphore if
* there is garbage to be collected.
*
* Certainly there is a race condition involved in sampling the garbage
* state. The looping nature of the IDLE loops should catch any missed
* garbage from the test on the next time arround.
*
* Input parameters:
* None
*
* Returned Value:
* TRUE if there is garbage to be collected.
*
****************************************************************************/
bool sched_have_garbage(void)
{
return (sched_have_kgarbage() || sched_have_kugarbage());
}
+1 -1
View File
@@ -120,7 +120,7 @@ static int work_hpthread(int argc, char *argv[])
* thread instead.
*/
sched_garbagecollection();
sched_garbage_collection();
#endif
/* Then process queued work. work_process will not return until: (1)
+1 -1
View File
@@ -156,7 +156,7 @@ static int work_lpthread(int argc, char *argv[])
* the garbage collection.
*/
sched_garbagecollection();
sched_garbage_collection();
/* Then process queued work. work_process will not return until:
* (1) there is no further work in the work queue, and (2) the polling