Skip to content

Commit

Permalink
os/pm: Add PM Thread Metrics
Browse files Browse the repository at this point in the history
This commit extends the functionality of pm_metrics. Now PM Metrics show the thread specific pm metrics. It shows which process causes minimum actual sleep time (in ms) and how frequently the thread wakes up the board.
  • Loading branch information
gSahitya-samsung committed Jul 10, 2024
1 parent 0a5c41f commit 61ae141
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 6 deletions.
17 changes: 17 additions & 0 deletions os/include/tinyara/pm/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,22 @@ int pm_changestate(enum pm_state_e newstate);

enum pm_state_e pm_querystate(void);

/****************************************************************************
* Name: pm_recover
*
* Description:
* This function is called from task_recover() when a task is deleted via
* task_delete() or via pthread_cancel(). It do pm post cleaning.
*
* Inputs:
* tcb - The TCB of the terminated task or thread
*
* Return Value:
* None.
*
****************************************************************************/
void pm_recover(FAR struct tcb_s *tcb);

#ifdef CONFIG_PM_DVFS
/****************************************************************************
* Name: pm_dvfs
Expand Down Expand Up @@ -656,6 +672,7 @@ int pm_metrics(int milliseconds);
#define pm_checkstate() (0)
#define pm_changestate(state) (0)
#define pm_querystate() (0)
#define pm_recover(tcb) (0)

#endif /* CONFIG_PM */

Expand Down
3 changes: 3 additions & 0 deletions os/kernel/task/task_recover.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <tinyara/arch.h>
#include <tinyara/wdog.h>
#include <tinyara/sched.h>
#include <tinyara/pm/pm.h>

#include "semaphore/semaphore.h"
#include "wdog/wdog.h"
Expand Down Expand Up @@ -114,6 +115,8 @@

void task_recover(FAR struct tcb_s *tcb)
{
/* This task is being deleted. Do PM post cleaning required for this thread */
pm_recover(tcb);
/* The task is being deleted. Cancel in pending timeout events. */

wd_recover(tcb);
Expand Down
1 change: 1 addition & 0 deletions os/pm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ CSRCS += pm_changestate.c pm_checkstate.c pm_initialize.c pm_idle.c
CSRCS += pm_register.c pm_domain_register.c pm_unregister.c pm_procfs.c
CSRCS += pm_suspend.c pm_resume.c pm_timedsuspend.c
CSRCS += pm_suspendcount.c
CSRCS += pm_recover.c

ifeq ($(CONFIG_PM_TIMEDWAKEUP),y)
CSRCS += pm_sleep.c
Expand Down
35 changes: 34 additions & 1 deletion os/pm/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,40 @@ void pm_metrics_update_idle(void);
* None
*
****************************************************************************/
void pm_metrics_update_wakehandler(clock_t missing_tick, pm_wakeup_reason_code_t wakeup_src);
void pm_metrics_update_wakehandler(uint32_t missing_tick, pm_wakeup_reason_code_t wakeup_src);

/****************************************************************************
* Name: pm_metrics_update_sleep
*
* Description:
* This function is called inside pm_sleep's callback. It counts the frequency of
* thread which wakeup the board. It also checks the minimum amount of time board
* was in sleep cause of given thread.
*
* Input parameters:
* pid - the ID of thread
*
* Returned value:
* None
*
****************************************************************************/
void pm_metrics_update_sleep(uint32_t pid);

/****************************************************************************
* Name: pm_metrics_update_recover
*
* Description:
* This function is called inside pm_recover. It resets the wakeup_counts and
* sleep_ticks of given thread for consistent PM Metrics result.
*
* Input parameters:
* pid - the ID of thread
*
* Returned value:
* None
*
****************************************************************************/
void pm_metrics_update_recover(uint32_t pid);
#endif

#undef EXTERN
Expand Down
77 changes: 75 additions & 2 deletions os/pm/pm_metrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <tinyara/config.h>
#include <tinyara/pm/pm.h>
#include <tinyara/sched.h>
#include <time.h>
#include <queue.h>
#include <debug.h>
Expand All @@ -39,9 +40,19 @@ struct pm_metric_state_s {

typedef struct pm_metric_state_s pm_metric_state_t;

struct pm_metric_thread_s {
pm_wakeup_reason_code_t wakeup_src; /* The wakeup source */
uint32_t wakeup_counts[CONFIG_MAX_TASKS]; /* Wakeup timer counts for each thread */
uint32_t min_sleep_ticks[CONFIG_MAX_TASKS]; /* Minimum actual sleep time allowed by each thread */
uint32_t delay; /* Wakeup timer delay (in ticks) */
};

typedef struct pm_metric_thread_s pm_metric_thread_t;

struct pm_metric_s {
pm_metric_domain_t domain_metrics; /* The domain metrics */
pm_metric_state_t state_metrics; /* The power management state metrics */
pm_metric_thread_t thread_metrics; /* The power management thread metrics */
uint32_t board_sleep_ticks; /* The amount of time (in ticks) board was in sleep */
uint32_t wakeup_src_counts[PM_WAKEUP_SRC_COUNT]; /* It counts the frequency of wakeup sources */
uint32_t total_try_ticks; /* Total duration of time pm tries to make board sleep */
Expand Down Expand Up @@ -82,6 +93,15 @@ static void pm_print_metrics(double total_time, int n_domains)
}
pmdbg("\n");
pmdbg("\n");
pmdbg(" PROCESS NAME | WAKEUP COUNTS | MIN SLEEP TIME \n");
pmdbg("--------------|---------------|----------------\n");
for (index = 0; index < CONFIG_MAX_TASKS; index++) {
if (g_pm_metrics->thread_metrics.wakeup_counts[index]) {
pmdbg(" %12s | %13d | %12dms \n", sched_gettcb(index)->name, g_pm_metrics->thread_metrics.wakeup_counts[index], TICK2MSEC(g_pm_metrics->thread_metrics.min_sleep_ticks[index]));
}
}
pmdbg("\n");
pmdbg("\n");
pmdbg(" BOARD STATE | PM STATE | TIME \n");
pmdbg("-------------|----------|------------------------\n");
pmdbg(" %11s | %8s | %10dms (%6.2f%%) \n", "WAKEUP", "NORMAL", TICK2MSEC(g_pm_metrics->state_metrics.state_accum_ticks[0]),\
Expand Down Expand Up @@ -230,14 +250,64 @@ void pm_metrics_update_changestate(void)
* None
*
****************************************************************************/
void pm_metrics_update_wakehandler(clock_t missing_tick, pm_wakeup_reason_code_t wakeup_src)
void pm_metrics_update_wakehandler(uint32_t missing_tick, pm_wakeup_reason_code_t wakeup_src)
{
if (g_pm_metrics_running) {
g_pm_metrics->thread_metrics.wakeup_src = wakeup_src;
g_pm_metrics->thread_metrics.delay = missing_tick;
g_pm_metrics->wakeup_src_counts[wakeup_src]++;
g_pm_metrics->board_sleep_ticks += missing_tick;
}
}

/****************************************************************************
* Name: pm_metrics_update_sleep
*
* Description:
* This function is called inside pm_sleep's callback. It counts the frequency of
* thread which wakeup the board. It also checks the minimum amount of time board
* was in sleep cause of given thread.
*
* Input parameters:
* pid - the ID of thread
*
* Returned value:
* None
*
****************************************************************************/
void pm_metrics_update_sleep(uint32_t pid)
{
if (g_pm_metrics_running && (g_pm_metrics->thread_metrics.wakeup_src == PM_WAKEUP_HW_TIMER)) {
if (g_pm_metrics->thread_metrics.delay < g_pm_metrics->thread_metrics.min_sleep_ticks[pid]) {
g_pm_metrics->thread_metrics.min_sleep_ticks[pid] = g_pm_metrics->thread_metrics.delay;
}
g_pm_metrics->thread_metrics.wakeup_counts[pid]++;
g_pm_metrics->thread_metrics.wakeup_src = PM_WAKEUP_UNKNOWN;
}
}

/****************************************************************************
* Name: pm_metrics_update_recover
*
* Description:
* This function is called inside pm_recover. It resets the wakeup_counts and
* sleep_ticks of given thread for consistent PM Metrics result.
*
* Input parameters:
* pid - the ID of thread
*
* Returned value:
* None
*
****************************************************************************/
void pm_metrics_update_recover(uint32_t pid)
{
if (g_pm_metrics_running) {
g_pm_metrics->thread_metrics.min_sleep_ticks[pid] = UINT32_MAX;
g_pm_metrics->thread_metrics.wakeup_counts[pid] = 0;
}
}

/****************************************************************************
* Name: pm_metrics
*
Expand Down Expand Up @@ -290,6 +360,9 @@ int pm_metrics(int milliseconds)
pm_metrics_update_domain(index);
g_pm_metrics->domain_metrics.stime[index] = start_time;
}
for (index = 0; index < CONFIG_MAX_TASKS; index++) {
g_pm_metrics->thread_metrics.min_sleep_ticks[index] = UINT32_MAX;
}
g_pm_metrics_running = true;
leave_critical_section(flags);
/* Resume Board Sleep */
Expand Down Expand Up @@ -319,10 +392,10 @@ int pm_metrics(int milliseconds)
}
n_domains = index;
g_pm_metrics->state_metrics.state_accum_ticks[g_pmglobals.state] += end_time - g_pm_metrics->state_metrics.stime;
leave_critical_section(flags);
/* Show PM Metrics Results */
pm_print_metrics((double)(end_time - start_time), n_domains);
/* Free allocated memory */
leave_critical_section(flags);
free(g_pm_metrics);
g_pm_metrics = NULL;
/* Resume Board Sleep */
Expand Down
54 changes: 54 additions & 0 deletions os/pm/pm_recover.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/****************************************************************************
*
* Copyright 2024 Samsung Electronics All Rights Reserved.
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/

#include <tinyara/config.h>
#include <tinyara/pm/pm.h>

#include "pm.h"

#ifdef CONFIG_PM

/****************************************************************************
* Public Functions
****************************************************************************/

/****************************************************************************
* Name: pm_recover
*
* Description:
* This function is called from task_recover() when a task is deleted via
* task_delete() or via pthread_cancel(). It do pm post cleaning.
*
* Inputs:
* tcb - The TCB of the terminated task or thread
*
* Return Value:
* None.
*
****************************************************************************/
void pm_recover(FAR struct tcb_s *tcb)
{
#ifdef CONFIG_PM_METRICS
pm_metrics_update_recover(tcb->pid);
#endif
}

#endif /* CONFIG_PM */
7 changes: 5 additions & 2 deletions os/pm/pm_sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@
* Public Functions
************************************************************************/

static void pm_timer_callback(int argc, uint32_t sem)
static void pm_timer_callback(int argc, uint32_t sem, uint32_t pid)
{
#ifdef CONFIG_PM_METRICS
pm_metrics_update_sleep(pid);
#endif
/* As the timer is expired, give back the semaphore to unlock the thread */
sem_post((sem_t*)sem);
}
Expand Down Expand Up @@ -121,7 +124,7 @@ int pm_sleep(int milliseconds)
return ERROR;
}

ret = wd_start(wdog, MSEC2TICK(milliseconds), (wdentry_t)pm_timer_callback, 1, (uint32_t)&pm_sem);
ret = wd_start(wdog, MSEC2TICK(milliseconds), (wdentry_t)pm_timer_callback, 2, (uint32_t)&pm_sem, (uint32_t) getpid());
if (ret != OK) {
pmdbg("pm_sleep: wd_start failed\n");
wd_delete(wdog);
Expand Down
2 changes: 1 addition & 1 deletion os/pm/pm_wakehandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void pm_wakehandler(clock_t missing_tick, pm_wakeup_reason_code_t wakeup_src)
{
irqstate_t flags = enter_critical_section();
#ifdef CONFIG_PM_METRICS
pm_metrics_update_wakehandler(missing_tick, wakeup_src);
pm_metrics_update_wakehandler((uint32_t)missing_tick, wakeup_src);
#endif
pmllvdbg("wakeup source code = %d\n", wakeup_src);
pmllvdbg("missing_tick: %llu\n", missing_tick);
Expand Down

0 comments on commit 61ae141

Please sign in to comment.