pm: procfs add pm prepare fail stats

Signed-off-by: dulibo1 <dulibo1@xiaomi.com>
Signed-off-by: buxiasen <buxiasen@xiaomi.com>
This commit is contained in:
dulibo1 2024-05-16 22:19:54 +08:00 committed by Xiang Xiao
parent fb31f06a2f
commit 3762bda5e2
4 changed files with 233 additions and 43 deletions

View file

@ -39,6 +39,92 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pm_stats
*
* Description:
* Statistic when domain on state change events.
*
* Input Parameters:
* dom - Identifies the target domain for Statistic
* curstate - Identifies the current PM state
* newstate - Identifies the new PM state
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_PM_PROCFS
static void pm_stats(FAR struct pm_domain_s *dom, int curstate, int newstate)
{
struct timespec ts;
clock_systime_timespec(&ts);
clock_timespec_subtract(&ts, &dom->start, &ts);
if (newstate == PM_RESTORE)
{
/* Wakeup from WFI */
clock_timespec_add(&ts, &dom->sleep[curstate], &dom->sleep[curstate]);
}
else
{
/* Sleep to WFI */
clock_timespec_add(&ts, &dom->wake[curstate], &dom->wake[curstate]);
}
/* Update start */
clock_systime_timespec(&dom->start);
}
/****************************************************************************
* Name: pm_stats_preparefail
*
* Description:
* Statistic the domain on drivers prepare failed.
*
* Input Parameters:
* domain - Identifies the target domain for Statistic
* callback - The prepare failed callback
* newstate - The target new state to prepare
* ret - The driver prepare failed returned value
*
* Returned Value:
* None.
*
****************************************************************************/
static void pm_stats_preparefail(int domain,
FAR struct pm_callback_s *callback,
int newstate, int ret)
{
struct timespec ts;
FAR struct pm_preparefail_s *pf = &callback->preparefail[domain];
if (pf->state != PM_RESTORE)
{
clock_systime_timespec(&ts);
clock_timespec_subtract(&ts, &pf->start, &ts);
clock_timespec_add(&ts, &pf->duration[pf->state],
&pf->duration[pf->state]);
pf->state = PM_RESTORE;
}
if (ret < 0)
{
clock_systime_timespec(&pf->start);
pf->state = newstate;
}
}
#else
# define pm_stats(dom, curstate, newstate)
# define pm_stats_preparefail(domain, callback, newstate, ret)
#endif
/****************************************************************************
* Name: pm_prepall
*
@ -48,6 +134,7 @@
* Input Parameters:
* domain - Identifies the domain of the new PM state
* newstate - Identifies the new PM state
* restore - Indicate currently in revert the preceding prepare stage.
*
* Returned Value:
* 0 (OK) means that the callback function for all registered drivers
@ -60,7 +147,7 @@
*
****************************************************************************/
static int pm_prepall(int domain, enum pm_state_e newstate)
static int pm_prepall(int domain, enum pm_state_e newstate, bool restore)
{
FAR dq_entry_t *entry;
int ret = OK;
@ -81,6 +168,10 @@ static int pm_prepall(int domain, enum pm_state_e newstate)
/* Yes.. prepare the driver */
ret = cb->prepare(cb, domain, newstate);
if (!restore)
{
pm_stats_preparefail(domain, cb, newstate, ret);
}
}
}
}
@ -100,6 +191,10 @@ static int pm_prepall(int domain, enum pm_state_e newstate)
/* Yes.. prepare the driver */
ret = cb->prepare(cb, domain, newstate);
if (!restore)
{
pm_stats_preparefail(domain, cb, newstate, ret);
}
}
}
}
@ -168,35 +263,6 @@ static inline void pm_changeall(int domain, enum pm_state_e newstate)
}
}
#ifdef CONFIG_PM_PROCFS
static void pm_stats(FAR struct pm_domain_s *dom, int curstate, int newstate)
{
struct timespec ts;
clock_systime_timespec(&ts);
clock_timespec_subtract(&ts, &dom->start, &ts);
if (newstate == PM_RESTORE)
{
/* Wakeup from WFI */
clock_timespec_add(&ts, &dom->sleep[curstate], &dom->sleep[curstate]);
}
else
{
/* Sleep to WFI */
clock_timespec_add(&ts, &dom->wake[curstate], &dom->wake[curstate]);
}
/* Update start */
clock_systime_timespec(&dom->start);
}
#else
# define pm_stats(dom, curstate, newstate)
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -250,7 +316,7 @@ int pm_changestate(int domain, enum pm_state_e newstate)
* drivers may refuse the state state change.
*/
ret = pm_prepall(domain, newstate);
ret = pm_prepall(domain, newstate, false);
if (ret != OK)
{
/* One or more drivers is not ready for this state change.
@ -258,7 +324,7 @@ int pm_changestate(int domain, enum pm_state_e newstate)
*/
newstate = g_pmglobals.domain[domain].state;
pm_prepall(domain, newstate);
pm_prepall(domain, newstate, true);
}
}

View file

@ -44,17 +44,22 @@
* Pre-processor Definitions
****************************************************************************/
#define STHDR "DOMAIN%d WAKE SLEEP TOTAL\n"
#define WAHDR "DOMAIN%d STATE COUNT TIME\n"
#define STHDR "DOMAIN%-2d WAKE SLEEP TOTAL\n"
#define PFHDR "CALLBACKS IDLE STANDBY SLEEP\n"
#define WAHDR "DOMAIN%-2d STATE COUNT TIME\n"
#ifdef CONFIG_SYSTEM_TIME64
# define STFMT "%-8s %8" PRIu64 "s %02" PRIu64 "%% %8" PRIu64 "s %02" \
PRIu64 "%% %8" PRIu64 "s %02" PRIu64 "%%\n"
# define WAFMT "%-12s %-10s %4" PRIu32 " %8" PRIu64 "s\n"
# define STFMT "%-18s %8" PRIu64 "s %3" PRIu64 "%% %8" PRIu64 "s %3" \
PRIu64 "%% %8" PRIu64 "s %3" PRIu64 "%%\n"
# define PFFMT "%-18p %8" PRIu64 "s %3" PRIu64 "%% %8" PRIu64 "s %3" \
PRIu64 "%% %8" PRIu64 "s %3" PRIu64 "%%\n"
# define WAFMT "%-25s %-14s %-14" PRIu32 " %" PRIu64 "s\n"
#else
# define STFMT "%-8s %8" PRIu32 "s %02" PRIu32 "%% %8" PRIu32 "s %02" \
PRIu32 "%% %8" PRIu32 "s %02" PRIu32 "%%\n"
# define WAFMT "%-12s %-10s %4" PRIu32 " %8" PRIu32 "s\n"
# define STFMT "%-18s %8" PRIu32 "s %3" PRIu32 "%% %8" PRIu32 "s %3" \
PRIu32 "%% %8" PRIu32 "s %3" PRIu32 "%%\n"
# define PFFMT "%-18p %8" PRIu32 "s %3" PRIu32 "%% %8" PRIu32 "s %3" \
PRIu32 "%% %8" PRIu32 "s %3" PRIu32 "%%\n"
# define WAFMT "%-25s %-14s %-14" PRIu32 " %" PRIu32 "s\n"
#endif
/* Determines the size of an intermediate buffer that must be large enough
@ -100,6 +105,8 @@ static ssize_t pm_read_state(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t pm_read_wakelock(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t pm_read_preparefail(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t pm_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static int pm_dup(FAR const struct file *oldp,
@ -149,8 +156,9 @@ const struct procfs_operations g_pm_operations =
static const struct pm_file_ops_s g_pm_files[] =
{
{"state", pm_read_state},
{"wakelock", pm_read_wakelock},
{"state", pm_read_state},
{"wakelock", pm_read_wakelock},
{"preparefail", pm_read_preparefail},
};
static FAR const char *g_pm_state[PM_COUNT] =
@ -262,7 +270,7 @@ static ssize_t pm_read_state(FAR struct file *filep, FAR char *buffer,
size_t linesize;
size_t copysize;
off_t offset;
uint32_t sum = 0;
time_t sum = 0;
uint32_t state;
finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
@ -398,6 +406,101 @@ static ssize_t pm_read_wakelock(FAR struct file *filep, FAR char *buffer,
return totalsize;
}
/****************************************************************************
* Name: pm_read_preparefail
*
* Description:
* The statistic values about prepare callback failed.
*
****************************************************************************/
static ssize_t pm_read_preparefail(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
FAR struct pm_preparefail_s *pf;
FAR struct pm_file_s *pmfile;
FAR struct pm_callback_s *cb;
FAR struct pm_domain_s *dom;
FAR dq_entry_t *entry;
irqstate_t flags;
size_t totalsize = 0;
size_t linesize;
size_t copysize;
off_t offset;
time_t sum = 0;
uint32_t state;
finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
/* Recover our private data from the struct file instance */
pmfile = (FAR struct pm_file_s *)filep->f_priv;
dom = &g_pmglobals.domain[pmfile->domain];
DEBUGASSERT(pmfile);
DEBUGASSERT(dom);
/* Save the file offset and the user buffer information */
offset = filep->f_pos;
/* Then list the power state */
linesize = snprintf(pmfile->line, PM_LINELEN, PFHDR);
copysize = procfs_memcpy(pmfile->line, linesize, buffer,
buflen, &offset);
totalsize += copysize;
flags = pm_domain_lock(pmfile->domain);
for (entry = dq_peek(&g_pmglobals.registry);
entry; entry = dq_next(entry))
{
cb = (FAR struct pm_callback_s *)entry;
pf = &cb->preparefail[pmfile->domain];
for (state = 0; state < PM_COUNT; state++)
{
sum += pf->duration[state].tv_sec;
}
}
sum = sum ? sum : 1;
for (entry = dq_peek(&g_pmglobals.registry);
entry; entry = dq_next(entry))
{
time_t total = 0;
cb = (FAR struct pm_callback_s *)entry;
pf = &cb->preparefail[pmfile->domain];
for (state = 0; state < PM_COUNT; state++)
{
total += pf->duration[state].tv_sec;
}
if (total == 0)
{
continue;
}
linesize = snprintf(pmfile->line, PM_LINELEN, PFFMT,
cb->prepare,
pf->duration[PM_IDLE].tv_sec,
100 * pf->duration[PM_IDLE].tv_sec / sum,
pf->duration[PM_STANDBY].tv_sec,
100 * pf->duration[PM_STANDBY].tv_sec / sum,
pf->duration[PM_SLEEP].tv_sec,
100 * pf->duration[PM_SLEEP].tv_sec / sum
);
buffer += copysize;
buflen -= copysize;
copysize = procfs_memcpy(pmfile->line, linesize, buffer,
buflen, &offset);
totalsize += copysize;
}
pm_domain_unlock(pmfile->domain, flags);
filep->f_pos += totalsize;
return totalsize;
}
/****************************************************************************
* Name: pm_read
****************************************************************************/

View file

@ -64,6 +64,14 @@ int pm_register(FAR struct pm_callback_s *callbacks)
flags = pm_lock(&g_pmglobals.reglock);
dq_addlast(&callbacks->entry, &g_pmglobals.registry);
#ifdef CONFIG_PM_PROCFS
for (int domain = 0; domain < CONFIG_PM_NDOMAINS; domain++)
{
callbacks->preparefail[domain].state = PM_RESTORE;
}
#endif
pm_unlock(&g_pmglobals.reglock, flags);
return 0;

View file

@ -145,6 +145,15 @@ enum pm_state_e
PM_COUNT,
};
#ifdef CONFIG_PM_PROCFS
struct pm_preparefail_s
{
enum pm_state_e state;
struct timespec start;
struct timespec duration[PM_COUNT];
};
#endif
/* This structure contain pointers callback functions in the driver. These
* callback functions can be used to provide power management information
* to the driver.
@ -211,6 +220,10 @@ struct pm_callback_s
CODE void (*notify)(FAR struct pm_callback_s *cb, int domain,
enum pm_state_e pmstate);
#ifdef CONFIG_PM_PROCFS
struct pm_preparefail_s preparefail[CONFIG_PM_NDOMAINS];
#endif
};
/* An instance of a given PM governor */