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:
parent
fb31f06a2f
commit
3762bda5e2
4 changed files with 233 additions and 43 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue