Skip to content

Commit

Permalink
[display] Add D-Bus method for obtaining display state statistics. Fi…
Browse files Browse the repository at this point in the history
…xes MER#1401

There is no way to get accurate display state statistics.

For each display state known to mce: Track the number of times the
state has been entered and how long it has been active in total.

Add D-Bus method call to allow any process to query this data.

Add mcetool option "--get-display-stats" to print out the data in
either human readable or machine friendly format.
  • Loading branch information
spiiroin committed Nov 3, 2015
1 parent 8b32d57 commit 0e34903
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 0 deletions.
3 changes: 3 additions & 0 deletions mce.conf
Expand Up @@ -149,6 +149,9 @@
<allow send_destination="com.nokia.mce"
send_interface="com.nokia.mce.request"
send_member="get_suspend_stats"/>
<allow send_destination="com.nokia.mce"
send_interface="com.nokia.mce.request"
send_member="get_display_stats"/>
</policy>

<!-- MCE expects some user process to provide compositor
Expand Down
150 changes: 150 additions & 0 deletions modules/display.c
Expand Up @@ -635,6 +635,12 @@ static void mdy_stm_cancel_rethink(void);
static void mdy_stm_schedule_rethink(void);
static void mdy_stm_force_rethink(void);

/* ------------------------------------------------------------------------- *
* DISPLAY_STATE_STATISTICS
* ------------------------------------------------------------------------- */

static void mdy_statistics_update(void);

/* ------------------------------------------------------------------------- *
* CPU_SCALING_GOVERNOR
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -675,6 +681,7 @@ static gboolean mdy_dbus_handle_cabc_mode_set_req(DBusMessage *const

static gboolean mdy_dbus_handle_blanking_pause_start_req(DBusMessage *const msg);
static gboolean mdy_dbus_handle_blanking_pause_cancel_req(DBusMessage *const msg);
static gboolean mdy_dbus_handle_display_stats_get_req(DBusMessage *const req);

static gboolean mdy_dbus_handle_desktop_started_sig(DBusMessage *const msg);

Expand Down Expand Up @@ -1338,6 +1345,7 @@ static void mdy_datapipe_display_state_cb(gconstpointer data)
if( display_state == prev )
goto EXIT;

mdy_statistics_update();
mdy_blanking_inhibit_schedule_broadcast();

EXIT:
Expand Down Expand Up @@ -6972,6 +6980,48 @@ static void mdy_stm_force_rethink(void)
return;
}

/* ========================================================================= *
* DISPLAY_STATE_STATISTICS
* ========================================================================= */

/** Statistics: Time spent in each display state */
static struct
{
int64_t entries;
int64_t time_ms;
}
mdy_statistics_data[MCE_DISPLAY_NUMSTATES] =
{
[MCE_DISPLAY_UNDEF] = { 0, 0 },
[MCE_DISPLAY_OFF] = { 0, 0 },
[MCE_DISPLAY_LPM_OFF] = { 0, 0 },
[MCE_DISPLAY_LPM_ON] = { 0, 0 },
[MCE_DISPLAY_DIM] = { 0, 0 },
[MCE_DISPLAY_ON] = { 0, 0 },
[MCE_DISPLAY_POWER_UP] = { 0, 0 },
[MCE_DISPLAY_POWER_DOWN] = { 0, 0 },
};

/** Update display state statistics
*/
static void mdy_statistics_update(void)
{
/* Uptime until mce display plugin determines initial
* display state gets accounted as UNDEF */
static display_state_t prev_state = MCE_DISPLAY_UNDEF;
static int64_t prev_update = 0;

int64_t now = mce_lib_get_boot_tick();

mdy_statistics_data[prev_state].time_ms += (now - prev_update);

if( prev_state != display_state )
mdy_statistics_data[display_state].entries += 1;

prev_state = display_state;
prev_update = now;
}

/* ========================================================================= *
* CPU_SCALING_GOVERNOR
* ========================================================================= */
Expand Down Expand Up @@ -8067,6 +8117,98 @@ static gboolean mdy_dbus_handle_blanking_pause_cancel_req(DBusMessage *const msg
return status;
}

/** D-Bus callback for the get display statistics method call
*
* @param req The D-Bus method call message to be replied
*
* @return TRUE
*/
static gboolean mdy_dbus_handle_display_stats_get_req(DBusMessage *const req)
{
DBusMessage *rsp = 0;
DBusMessageIter body;
DBusMessageIter array;
DBusMessageIter dict;
DBusMessageIter entry;

mce_log(LL_DEVEL, "display state statistics req from %s",
mce_dbus_get_message_sender_ident(req));

if( dbus_message_get_no_reply(req) )
goto EXIT;

rsp = dbus_new_method_reply(req);

dbus_message_iter_init_append(rsp, &body);

if( !dbus_message_iter_open_container(&body, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_STRUCT_BEGIN_CHAR_AS_STRING
DBUS_TYPE_INT64_AS_STRING
DBUS_TYPE_INT64_AS_STRING
DBUS_STRUCT_END_CHAR_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&array) )
goto EXIT;

/* Add data accumulated for the current display state
* before constructing the reply message */
mdy_statistics_update();

for( size_t i = 0; i < MCE_DISPLAY_NUMSTATES; ++i ) {
dbus_any_t dta;

if( !dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY,
0, &dict) )
goto ABANDON_ARRAY;

dta.s = display_state_repr(i);
if( !dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &dta) )
goto ABANDON_DICT;

if( !dbus_message_iter_open_container(&dict, DBUS_TYPE_STRUCT,
0, &entry) )
goto ABANDON_DICT;

dta.i64 = mdy_statistics_data[i].time_ms;
if( !dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT64, &dta) )
goto ABANDON_ENTRY;

dta.i64 = mdy_statistics_data[i].entries;
if( !dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT64, &dta) )
goto ABANDON_ENTRY;

if( !dbus_message_iter_close_container(&dict, &entry) )
goto ABANDON_DICT;

if( !dbus_message_iter_close_container(&array, &dict) )
goto ABANDON_ARRAY;
}

if( !dbus_message_iter_close_container(&body, &array) )
goto EXIT;

dbus_send_message(rsp), rsp = 0;

goto EXIT;

ABANDON_ENTRY:
dbus_message_iter_abandon_container(&dict, &entry);

ABANDON_DICT:
dbus_message_iter_abandon_container(&array, &dict);

ABANDON_ARRAY:
dbus_message_iter_abandon_container(&body, &array);

EXIT:
if( rsp )
dbus_message_unref(rsp);

return TRUE;
}

/**
* D-Bus callback for the desktop startup notification signal
*
Expand Down Expand Up @@ -8230,6 +8372,14 @@ static mce_dbus_handler_t mdy_dbus_handlers[] =
" <arg direction=\"in\" name=\"requested_cabc_mode\" type=\"s\"/>\n"
" <arg direction=\"out\" name=\"activated_cabc_mode\" type=\"s\"/>\n"
},
{
.interface = MCE_REQUEST_IF,
.name = "get_display_stats",
.type = DBUS_MESSAGE_TYPE_METHOD_CALL,
.callback = mdy_dbus_handle_display_stats_get_req,
.args =
" <arg direction=\"out\" name=\"display_state_statistics\" type=\"a{s(xx)}\"/>\n"
},
/* sentinel */
{
.interface = 0
Expand Down
120 changes: 120 additions & 0 deletions tools/mcetool.c
Expand Up @@ -33,6 +33,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Expand Down Expand Up @@ -4975,6 +4976,113 @@ static bool xmce_get_suspend_stats(const char *args)
return true;
}

/* ------------------------------------------------------------------------- *
* display state statistics
* ------------------------------------------------------------------------- */

/** Helper for turning 64 bit ms count to human readable elapsed time
*/
static char *elapsed_time_repr(char *buff, size_t size, int64_t t)
{
char days[32] = "";
const char *sgn = "";
if( t < 0 ) sgn="-", t = -t;

int ms = (int)t % 1000; t /= 1000;
int s = (int)t % 60; t /= 60;
int m = (int)t % 60; t /= 60;
int h = (int)t % 24; t /= 24;

if( t ) snprintf(days, sizeof days, "%"PRIi64"d ", t);

snprintf(buff, size, "%s%s%02d:%02d:%02d.%03d",
sgn, days, h, m, s, ms);

return buff;
}

/** Get display state statistics
*/
static bool xmce_get_display_stats(const char *args)
{
bool human_readable = true;

if( args ) {
if( !strcmp(args, "machine") )
human_readable = false;
else if( !strcmp(args, "human") )
human_readable = true;
else {
errorf("unkown output mode: %s\n", args);
return false;
}
}

DBusMessage *rsp = NULL;
DBusError err = DBUS_ERROR_INIT;
gchar *name = 0;

DBusMessageIter body, array, dict, entry;

if( !xmce_ipc_message_reply("get_display_stats", &rsp, DBUS_TYPE_INVALID) )
goto EXIT;

if( !dbushelper_init_read_iterator(rsp, &body) )
goto EXIT;

if( !dbushelper_require_array_type(&body, DBUS_TYPE_DICT_ENTRY) )
goto EXIT;

if( !dbushelper_read_array(&body, &array) )
goto EXIT;

while( !dbushelper_read_at_end(&array) ) {
g_free(name), name = 0;

if( !dbushelper_read_dict(&array, &dict) )
goto EXIT;

if( !dbushelper_read_string(&dict, &name) )
goto EXIT;

if( !dbushelper_read_struct(&dict, &entry) )
goto EXIT;

int64_t time_ms = 0;
int64_t entries = 0;

if( !dbushelper_read_int64(&entry, &time_ms) )
goto EXIT;

if( !dbushelper_read_int64(&entry, &entries) )
goto EXIT;

if( human_readable ) {
char tmp[64];
printf("%-10s %16s, %"PRIi64" times\n",
name,
elapsed_time_repr(tmp, sizeof tmp, time_ms),
entries);
}
else {
printf("%-10s %"PRIi64" %"PRIi64"\n",
name, time_ms, entries);
}

}
EXIT:
g_free(name);

if( dbus_error_is_set(&err) ) {
errorf("%s: %s: %s\n", "get_display_stats", err.name, err.message);
dbus_error_free(&err);
}

if( rsp ) dbus_message_unref(rsp);

return true;
}

/* ------------------------------------------------------------------------- *
* use mouse clicks to emulate touchscreen doubletap policy
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -5455,6 +5563,18 @@ static const mce_opt_t options[] =
.usage =
"send display low power mode request\n"
},
{
.name = "get-display-stats",
.without_arg = xmce_get_display_stats,
.with_arg = xmce_get_display_stats,
.values = "human|machine",
.usage =
"get time spent in various display states\n"
"\n"
"Note that uptime accumulated before the startup of\n"
"the currently running mce process gets accounted\n"
"as UNDEF.\n"
},
{
.name = "blank-prevent",
.flag = 'P',
Expand Down

0 comments on commit 0e34903

Please sign in to comment.