mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-22 07:28:16 +01:00
include service delay stats for DEBUG builds
A start at determining of often there's a problem with Service not scheduling work quickly enough.
This commit is contained in:
parent
fb0d87781a
commit
c2c6312e91
5 changed files with 144 additions and 11 deletions
|
@ -88,7 +88,8 @@ public class BTService extends XWJIService {
|
||||||
|
|
||||||
private final static int sJobID = 218719979;
|
private final static int sJobID = 218719979;
|
||||||
static {
|
static {
|
||||||
XWJIService.register( BTService.class, sJobID );
|
XWJIService.register( BTService.class, sJobID,
|
||||||
|
CommsConnType.COMMS_CONN_BT );
|
||||||
}
|
}
|
||||||
|
|
||||||
// half minute for testing; maybe 15 on ship? Or make it a debug config.
|
// half minute for testing; maybe 15 on ship? Or make it a debug config.
|
||||||
|
|
|
@ -37,13 +37,16 @@ import org.eehouse.android.xw4.jni.CommsAddrRec;
|
||||||
import org.eehouse.android.xw4.jni.XwJNI;
|
import org.eehouse.android.xw4.jni.XwJNI;
|
||||||
import org.eehouse.android.xw4.loc.LocUtils;
|
import org.eehouse.android.xw4.loc.LocUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ConnStatusHandler {
|
public class ConnStatusHandler {
|
||||||
private static final String TAG = ConnStatusHandler.class.getSimpleName();
|
private static final String TAG = ConnStatusHandler.class.getSimpleName();
|
||||||
private static final String RECS_KEY = TAG + "/recs";
|
private static final String RECS_KEY = TAG + "/recs";
|
||||||
|
private static final String STALL_STATS_KEY = TAG + "/stall_stats";
|
||||||
|
|
||||||
public interface ConnStatusCBacks {
|
public interface ConnStatusCBacks {
|
||||||
public void invalidateParent();
|
public void invalidateParent();
|
||||||
|
@ -214,6 +217,13 @@ public class ConnStatusHandler {
|
||||||
} else {
|
} else {
|
||||||
sb.append( LocUtils.getString( context, R.string.connstat_noreceipt) );
|
sb.append( LocUtils.getString( context, R.string.connstat_noreceipt) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( BuildConfig.DEBUG ) {
|
||||||
|
String stallStats = stallStatsFor( context, typ );
|
||||||
|
if ( null != stallStats ) {
|
||||||
|
sb.append( stallStats );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msg = sb.toString();
|
msg = sb.toString();
|
||||||
|
@ -221,6 +231,95 @@ public class ConnStatusHandler {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class StallStats implements java.io.Serializable {
|
||||||
|
private static final int MAX_STALL_DATA_LEN = 100;
|
||||||
|
long[] mData = new long[MAX_STALL_DATA_LEN];
|
||||||
|
long[] mStamps = new long[MAX_STALL_DATA_LEN];
|
||||||
|
int mUsed = 0; // <= MAX_STALL_DATA_LEN
|
||||||
|
|
||||||
|
private static HashMap<CommsConnType, StallStats> sStallStatsMap;
|
||||||
|
|
||||||
|
static StallStats get( Context context, CommsConnType typ )
|
||||||
|
{
|
||||||
|
if ( null == sStallStatsMap ) {
|
||||||
|
sStallStatsMap = (HashMap<CommsConnType, StallStats>)DBUtils
|
||||||
|
.getSerializableFor( context, STALL_STATS_KEY );
|
||||||
|
if ( null == sStallStatsMap ) {
|
||||||
|
sStallStatsMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StallStats result = sStallStatsMap.get( typ );
|
||||||
|
if ( result == null ) {
|
||||||
|
result = new StallStats();
|
||||||
|
sStallStatsMap.put( typ, result );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void save( Context context )
|
||||||
|
{
|
||||||
|
DBUtils.setSerializableFor( context, STALL_STATS_KEY, sStallStatsMap );
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void append( Context context, long ageMS )
|
||||||
|
{
|
||||||
|
if ( MAX_STALL_DATA_LEN == mUsed ) {
|
||||||
|
--mUsed;
|
||||||
|
System.arraycopy( mData, 1, mData, 0, mUsed );
|
||||||
|
System.arraycopy( mStamps, 1, mStamps, 0, mUsed );
|
||||||
|
}
|
||||||
|
mData[mUsed] = ageMS;
|
||||||
|
mStamps[mUsed] = System.currentTimeMillis();
|
||||||
|
++mUsed;
|
||||||
|
|
||||||
|
save( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized String toString( Context context )
|
||||||
|
{
|
||||||
|
StringBuffer sb = new StringBuffer()
|
||||||
|
.append("\n\nService delay stats:\n");
|
||||||
|
if ( mUsed > 0 ) {
|
||||||
|
long dataSum10 = 0;
|
||||||
|
long dataSum100 = 0;
|
||||||
|
final int last10Indx = Math.max( 0, mUsed - 10 );
|
||||||
|
for ( int ii = 0; ii < mUsed; ++ii ) {
|
||||||
|
long datum = mData[ii];
|
||||||
|
dataSum100 += datum;
|
||||||
|
if ( ii >= last10Indx ) {
|
||||||
|
dataSum10 += datum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long firstStamp100 = mStamps[0];
|
||||||
|
long firstStamp10 = mStamps[last10Indx];
|
||||||
|
|
||||||
|
int num = Math.min(10, mUsed);
|
||||||
|
append( context, sb, num, dataSum10 / num, firstStamp10 );
|
||||||
|
append( context, sb, mUsed, dataSum100 / mUsed, firstStamp100 );
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void append( Context context, StringBuffer sb, int len, long avg, long stamp )
|
||||||
|
{
|
||||||
|
sb.append( String.format( "For last %d: %dms avg. (oldest: %s)\n", len, avg,
|
||||||
|
DateUtils.getRelativeDateTimeString( context, stamp,
|
||||||
|
DateUtils.SECOND_IN_MILLIS,
|
||||||
|
DateUtils.HOUR_IN_MILLIS,
|
||||||
|
0 ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String stallStatsFor( Context context, CommsConnType typ )
|
||||||
|
{
|
||||||
|
// long[] nums = StallStats.get( context, typ ).averages();
|
||||||
|
// return "Average for last 10 Intents (spanning %s): %dms";;
|
||||||
|
StallStats stats = StallStats.get( context, typ );
|
||||||
|
return stats == null ? null : stats.toString( context );
|
||||||
|
}
|
||||||
|
|
||||||
private static void invalidateParent()
|
private static void invalidateParent()
|
||||||
{
|
{
|
||||||
if ( null != s_cbacks ) {
|
if ( null != s_cbacks ) {
|
||||||
|
@ -286,6 +385,20 @@ public class ConnStatusHandler {
|
||||||
showSuccessOut( s_cbacks );
|
showSuccessOut( s_cbacks );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public static void noteStall( CommsConnType connType, long ageMS )
|
||||||
|
// {
|
||||||
|
// Log.d( TAG, "noteStall(%s, age=%s)", connType, age / 1000 );
|
||||||
|
|
||||||
|
// StallStats
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static void noteIntentHandled( Context context, CommsConnType connType,
|
||||||
|
long ageMS )
|
||||||
|
{
|
||||||
|
// Log.d( TAG, "noteIntentHandled(%s, ageMS=%d)", connType, ageMS );
|
||||||
|
StallStats.get( context, connType ).append( context, ageMS );
|
||||||
|
}
|
||||||
|
|
||||||
public static void draw( Context context, Canvas canvas, Resources res,
|
public static void draw( Context context, Canvas canvas, Resources res,
|
||||||
CommsConnTypeSet connTypes, boolean isSolo )
|
CommsConnTypeSet connTypes, boolean isSolo )
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,7 +80,8 @@ public class RelayService extends XWJIService
|
||||||
// and found older jobs in the JobIntentService's work queue.
|
// and found older jobs in the JobIntentService's work queue.
|
||||||
private final static int sJobID = 218719978;
|
private final static int sJobID = 218719978;
|
||||||
static {
|
static {
|
||||||
XWJIService.register( RelayService.class, sJobID );
|
XWJIService.register( RelayService.class, sJobID,
|
||||||
|
CommsConnType.COMMS_CONN_RELAY );
|
||||||
}
|
}
|
||||||
|
|
||||||
// One day, in seconds. Probably should be configurable.
|
// One day, in seconds. Probably should be configurable.
|
||||||
|
|
|
@ -320,6 +320,14 @@ public class Utils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the OS starts delivering Intents before the user notices the
|
||||||
|
// notification, remove it. PENDING: should I replace it with something
|
||||||
|
// that tells how long the stall was?
|
||||||
|
public static void clearStallNotification( Context context, long age )
|
||||||
|
{
|
||||||
|
cancelNotification( context, R.string.notify_stall_title );
|
||||||
|
}
|
||||||
|
|
||||||
public static void cancelNotification( Context context, int id )
|
public static void cancelNotification( Context context, int id )
|
||||||
{
|
{
|
||||||
NotificationManager nm = (NotificationManager)
|
NotificationManager nm = (NotificationManager)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
package org.eehouse.android.xw4;
|
package org.eehouse.android.xw4;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -34,6 +33,8 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||||
|
|
||||||
abstract class XWJIService extends JobIntentService {
|
abstract class XWJIService extends JobIntentService {
|
||||||
private static final String TAG = XWJIService.class.getSimpleName();
|
private static final String TAG = XWJIService.class.getSimpleName();
|
||||||
private static final boolean LOG_INTENT_COUNTS = false;
|
private static final boolean LOG_INTENT_COUNTS = false;
|
||||||
|
@ -50,22 +51,25 @@ abstract class XWJIService extends JobIntentService {
|
||||||
abstract XWJICmds[] getCmds();
|
abstract XWJICmds[] getCmds();
|
||||||
|
|
||||||
private static Map<Class, Integer> sJobIDs = new HashMap<>();
|
private static Map<Class, Integer> sJobIDs = new HashMap<>();
|
||||||
static void register( Class clazz, int jobID ) {
|
private static Map<Class, CommsConnType> sTypes = new HashMap<>();
|
||||||
|
static void register( Class clazz, int jobID, CommsConnType typ )
|
||||||
|
{
|
||||||
sJobIDs.put( clazz, jobID );
|
sJobIDs.put( clazz, jobID );
|
||||||
|
sTypes.put( clazz, typ );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onHandleWork( Intent intent )
|
public final void onHandleWork( Intent intent )
|
||||||
{
|
{
|
||||||
forget( this, getClass(), intent );
|
|
||||||
|
|
||||||
long timestamp = getTimestamp(intent);
|
long timestamp = getTimestamp(intent);
|
||||||
|
long ageMS = System.currentTimeMillis() - timestamp;
|
||||||
|
forget( this, getClass(), intent, ageMS );
|
||||||
|
|
||||||
XWJICmds cmd = cmdFrom( intent );
|
XWJICmds cmd = cmdFrom( intent );
|
||||||
if ( LOG_PACKETS ) {
|
if ( LOG_PACKETS ) {
|
||||||
Log.d( getClass().getSimpleName(),
|
Log.d( getClass().getSimpleName(),
|
||||||
"onHandleWork(): cmd=%s; age=%dms; threadCount: %d)",
|
"onHandleWork(): cmd=%s; age=%dms; threadCount: %d)",
|
||||||
cmd, System.currentTimeMillis() - timestamp,
|
cmd, ageMS, Thread.activeCount() );
|
||||||
Thread.activeCount() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHandleWorkImpl( intent, cmd, timestamp );
|
onHandleWorkImpl( intent, cmd, timestamp );
|
||||||
|
@ -75,7 +79,7 @@ abstract class XWJIService extends JobIntentService {
|
||||||
{
|
{
|
||||||
remember( context, clazz, intent );
|
remember( context, clazz, intent );
|
||||||
enqueueWork( context, clazz, sJobIDs.get(clazz), intent );
|
enqueueWork( context, clazz, sJobIDs.get(clazz), intent );
|
||||||
checkForStall( context );
|
checkForStall( context, clazz );
|
||||||
}
|
}
|
||||||
|
|
||||||
static XWJICmds cmdFrom( Intent intent, XWJICmds[] values )
|
static XWJICmds cmdFrom( Intent intent, XWJICmds[] values )
|
||||||
|
@ -123,7 +127,7 @@ abstract class XWJIService extends JobIntentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final long AGE_THRESHOLD_MS = 1000 * 60; // one minute to start
|
private static final long AGE_THRESHOLD_MS = 1000 * 60; // one minute to start
|
||||||
private static void checkForStall( Context context )
|
private static void checkForStall( Context context, Class clazz )
|
||||||
{
|
{
|
||||||
if ( stallCheckEnabled( context ) ) {
|
if ( stallCheckEnabled( context ) ) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
@ -143,12 +147,15 @@ abstract class XWJIService extends JobIntentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( maxAge > AGE_THRESHOLD_MS ) {
|
if ( maxAge > AGE_THRESHOLD_MS ) {
|
||||||
|
// ConnStatusHandler.noteStall( sTypes.get( clazz ), maxAge );
|
||||||
Utils.showStallNotification( context, maxAge );
|
Utils.showStallNotification( context, maxAge );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void forget( Context context, Class clazz, Intent intent )
|
// Called when an intent is successfully delivered
|
||||||
|
private static void forget( Context context, Class clazz,
|
||||||
|
Intent intent, long ageMS )
|
||||||
{
|
{
|
||||||
if ( stallCheckEnabled( context ) ) {
|
if ( stallCheckEnabled( context ) ) {
|
||||||
String name = clazz.getSimpleName();
|
String name = clazz.getSimpleName();
|
||||||
|
@ -177,6 +184,9 @@ abstract class XWJIService extends JobIntentService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnStatusHandler.noteIntentHandled( context, sTypes.get( clazz ), ageMS );
|
||||||
|
Utils.clearStallNotification( context, ageMS );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue