-
Notifications
You must be signed in to change notification settings - Fork 573
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os/pm: Add PM Thread Metrics #6286
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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> | ||
|
@@ -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 */ | ||
|
@@ -80,6 +91,17 @@ static void pm_print_metrics(double total_time, int n_domains) | |
for (index = 0; index < PM_WAKEUP_SRC_COUNT; index++) { | ||
pmdbg(" %14s | %6d \n", wakeup_src_name[index], g_pm_metrics->wakeup_src_counts[index]); | ||
} | ||
if (g_pm_metrics->wakeup_src_counts[PM_WAKEUP_HW_TIMER]) { | ||
pmdbg("\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about adding new definition for pmdbg_noarg (based on dbg_noarg) and use that to print these mertrics? When we are printing a table, then we dont need the api name at the beginning of each line of the table. |
||
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"); | ||
|
@@ -117,7 +139,6 @@ void pm_metrics_update_domain(int domain_id) | |
{ | ||
if (g_pm_metrics_running) { | ||
g_pm_metrics->domain_metrics.stime[domain_id] = clock_systimer(); | ||
g_pm_metrics->domain_metrics.suspend_ticks[domain_id] = 0; | ||
} | ||
} | ||
|
||
|
@@ -230,14 +251,68 @@ 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 because of given thread. | ||
* | ||
* Input parameters: | ||
* pid - the ID of thread | ||
* | ||
* Returned value: | ||
* None | ||
* | ||
****************************************************************************/ | ||
void pm_metrics_update_sleep(pid_t pid) | ||
{ | ||
int hash_pid; | ||
if (g_pm_metrics_running && (g_pm_metrics->thread_metrics.wakeup_src == PM_WAKEUP_HW_TIMER)) { | ||
hash_pid = PIDHASH(pid); | ||
if (g_pm_metrics->thread_metrics.delay < g_pm_metrics->thread_metrics.min_sleep_ticks[hash_pid]) { | ||
g_pm_metrics->thread_metrics.min_sleep_ticks[hash_pid] = g_pm_metrics->thread_metrics.delay; | ||
} | ||
g_pm_metrics->thread_metrics.wakeup_counts[hash_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(pid_t pid) | ||
{ | ||
int hash_pid; | ||
if (g_pm_metrics_running) { | ||
hash_pid = PIDHASH(pid); | ||
g_pm_metrics->thread_metrics.min_sleep_ticks[hash_pid] = UINT32_MAX; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can modify this data when the next pid comes in. |
||
g_pm_metrics->thread_metrics.wakeup_counts[hash_pid] = 0; | ||
} | ||
} | ||
|
||
/**************************************************************************** | ||
* Name: pm_metrics | ||
* | ||
|
@@ -280,16 +355,15 @@ int pm_metrics(int milliseconds) | |
return ERROR; | ||
} | ||
/* PM Metrics Initialization */ | ||
for (index = 0; index < PM_COUNT; index++) { | ||
g_pm_metrics->state_metrics.state_accum_ticks[index] = 0; | ||
} | ||
flags = enter_critical_section(); | ||
start_time = clock_systimer(); | ||
g_pm_metrics->state_metrics.stime = start_time; | ||
for (index = 0; (index < CONFIG_PM_NDOMAINS) && pm_domain_map[index]; index++) { | ||
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; | ||
} | ||
gSahitya-samsung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
g_pm_metrics_running = true; | ||
leave_critical_section(flags); | ||
/* Resume Board Sleep */ | ||
|
@@ -319,10 +393,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 */ | ||
|
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 does pm cleanup. | ||
* | ||
* 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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can task exited using PIDHASH is same For only pm_metrics, do we need to add operation in task exit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but in future we can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think, when add new future, add this also is better. for pm_metrics side, It seems better to keep the data until the next thread is created. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we do this way, then we may need to keep |
||
#endif | ||
} | ||
|
||
#endif /* CONFIG_PM */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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_t)pid); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please find wd_setwakeupsource() we can use timer as wakeup source using api rather than pm_sleep. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently whole |
||
#endif | ||
/* As the timer is expired, give back the semaphore to unlock the thread */ | ||
sem_post((sem_t*)sem); | ||
} | ||
|
@@ -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); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do missing_tick is typecased to uint32_t? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to organize the type in pm_metrics. please check and let me know the maximum time supported by pm_metrics. You can limit all actions to the maximum time and change the data type correctly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ewoodev We can scale There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean, currently our pm_metrics use pm_sleep. This is the maximum int max of delay. is it necessary for the count and ticks of pm_metrics to maintain int max tick? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but it is highly unlikely board will sleep continuously for |
||
#endif | ||
pmllvdbg("wakeup source code = %d\n", wakeup_src); | ||
pmllvdbg("missing_tick: %llu\n", missing_tick); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gSahitya-samsung use code-i feature to generate the doxzgen documentation for the interfaces and update the description if it not suiting better.(/docstring) which is very productive.