Update CPU Monitor to report CPU frequency and battery level.
R=wzh@webrtc.org Review URL: https://codereview.webrtc.org/1813053007 . Cr-Commit-Position: refs/heads/master@{#12081}
This commit is contained in:
@ -134,8 +134,10 @@ public class CallActivity extends Activity
|
|||||||
private long callStartedTimeMs = 0;
|
private long callStartedTimeMs = 0;
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
CallFragment callFragment;
|
private CallFragment callFragment;
|
||||||
HudFragment hudFragment;
|
private HudFragment hudFragment;
|
||||||
|
private CpuMonitor cpuMonitor;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -242,6 +244,10 @@ public class CallActivity extends Activity
|
|||||||
roomConnectionParameters = new RoomConnectionParameters(
|
roomConnectionParameters = new RoomConnectionParameters(
|
||||||
roomUri.toString(), roomId, loopback);
|
roomUri.toString(), roomId, loopback);
|
||||||
|
|
||||||
|
// Create CPU monitor
|
||||||
|
cpuMonitor = new CpuMonitor(this);
|
||||||
|
hudFragment.setCpuMonitor(cpuMonitor);
|
||||||
|
|
||||||
// Send intent arguments to fragments.
|
// Send intent arguments to fragments.
|
||||||
callFragment.setArguments(intent.getExtras());
|
callFragment.setArguments(intent.getExtras());
|
||||||
hudFragment.setArguments(intent.getExtras());
|
hudFragment.setArguments(intent.getExtras());
|
||||||
@ -280,6 +286,7 @@ public class CallActivity extends Activity
|
|||||||
if (peerConnectionClient != null) {
|
if (peerConnectionClient != null) {
|
||||||
peerConnectionClient.stopVideoSource();
|
peerConnectionClient.stopVideoSource();
|
||||||
}
|
}
|
||||||
|
cpuMonitor.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -289,6 +296,7 @@ public class CallActivity extends Activity
|
|||||||
if (peerConnectionClient != null) {
|
if (peerConnectionClient != null) {
|
||||||
peerConnectionClient.startVideoSource();
|
peerConnectionClient.startVideoSource();
|
||||||
}
|
}
|
||||||
|
cpuMonitor.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -299,6 +307,7 @@ public class CallActivity extends Activity
|
|||||||
}
|
}
|
||||||
activityRunning = false;
|
activityRunning = false;
|
||||||
rootEglBase.release();
|
rootEglBase.release();
|
||||||
|
cpuMonitor.release();
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,15 +10,27 @@
|
|||||||
|
|
||||||
package org.appspot.apprtc;
|
package org.appspot.apprtc;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.BatteryManager;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.InputMismatchException;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.appspot.apprtc.util.LooperExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple CPU monitor. The caller creates a CpuMonitor object which can then
|
* Simple CPU monitor. The caller creates a CpuMonitor object which can then
|
||||||
* be used via sampleCpuUtilization() to collect the percentual use of the
|
* be used via sampleCpuUtilization() to collect the percentual use of the
|
||||||
@ -62,29 +74,142 @@ import java.util.Scanner;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CpuMonitor {
|
class CpuMonitor {
|
||||||
private static final int SAMPLE_SAVE_NUMBER = 10; // Assumed to be >= 3.
|
|
||||||
private int[] percentVec = new int[SAMPLE_SAVE_NUMBER];
|
|
||||||
private int sum3 = 0;
|
|
||||||
private int sum10 = 0;
|
|
||||||
private static final String TAG = "CpuMonitor";
|
private static final String TAG = "CpuMonitor";
|
||||||
private long[] cpuFreq;
|
private static final String DUMP_FILE = "cpu_log.txt";
|
||||||
|
private static final int CPU_STAT_SAMPLE_PERIOD = 2000;
|
||||||
|
private static final int CPU_STAT_LOG_PERIOD = 6000;
|
||||||
|
|
||||||
|
private final Context appContext;
|
||||||
|
private LooperExecutor executor;
|
||||||
|
private long lastStatLogTimeMs;
|
||||||
|
private int iterations;
|
||||||
|
private double currentUserCpuUsage;
|
||||||
|
private double currentSystemCpuUsage;
|
||||||
|
private double currentTotalCpuUsage;
|
||||||
|
private double currentFrequencyScale = -1;
|
||||||
|
private double sumUserCpuUsage;
|
||||||
|
private double sumSystemCpuUsage;
|
||||||
|
private double sumFrequencyScale;
|
||||||
|
private double sumTotalCpuUsage;
|
||||||
|
private long[] cpuFreqMax;
|
||||||
private int cpusPresent;
|
private int cpusPresent;
|
||||||
private double lastPercentFreq = -1;
|
private int actualCpusPresent;
|
||||||
private int cpuCurrent;
|
|
||||||
private int cpuAvg3;
|
|
||||||
private int cpuAvgAll;
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
private String[] maxPath;
|
private String[] maxPath;
|
||||||
private String[] curPath;
|
private String[] curPath;
|
||||||
ProcStat lastProcStat;
|
private double[] curFreqScales;
|
||||||
|
private ProcStat lastProcStat;
|
||||||
|
|
||||||
|
private static boolean dumpEnabled = false;
|
||||||
|
private static FileOutputStream fileWriter;
|
||||||
|
|
||||||
private class ProcStat {
|
private class ProcStat {
|
||||||
final long runTime;
|
final long userTime;
|
||||||
|
final long systemTime;
|
||||||
final long idleTime;
|
final long idleTime;
|
||||||
|
|
||||||
ProcStat(long aRunTime, long aIdleTime) {
|
ProcStat(long userTime, long systemTime, long idleTime) {
|
||||||
runTime = aRunTime;
|
this.userTime = userTime;
|
||||||
idleTime = aIdleTime;
|
this.systemTime = systemTime;
|
||||||
|
this.idleTime = idleTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CpuMonitor(Context context) {
|
||||||
|
Log.d(TAG, "CpuMonitor ctor.");
|
||||||
|
appContext = context.getApplicationContext();
|
||||||
|
lastStatLogTimeMs = 0;
|
||||||
|
|
||||||
|
executor = new LooperExecutor();
|
||||||
|
executor.requestStart();
|
||||||
|
scheduleCpuUtilizationTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
if (executor != null) {
|
||||||
|
Log.d(TAG, "release");
|
||||||
|
executor.cancelScheduledTasks();
|
||||||
|
executor.requestStop();
|
||||||
|
executor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause() {
|
||||||
|
if (executor != null) {
|
||||||
|
Log.d(TAG, "pause");
|
||||||
|
executor.cancelScheduledTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume() {
|
||||||
|
if (executor != null) {
|
||||||
|
Log.d(TAG, "resume");
|
||||||
|
resetStat();
|
||||||
|
scheduleCpuUtilizationTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getCpuUsageCurrent() {
|
||||||
|
return doubleToPercent(currentTotalCpuUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getCpuUsageAverage() {
|
||||||
|
return sumDoubleToPercent(sumTotalCpuUsage, iterations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized int getCpuFrequencyScaleCurrent() {
|
||||||
|
return doubleToPercent(currentFrequencyScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleCpuUtilizationTask() {
|
||||||
|
executor.scheduleAtFixedRate(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logCpuUtilization();
|
||||||
|
}
|
||||||
|
}, CPU_STAT_SAMPLE_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDump(String statString) {
|
||||||
|
if (!dumpEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fileWriter == null) {
|
||||||
|
Log.d(TAG, "Start log dump");
|
||||||
|
String fileName = Environment.getExternalStorageDirectory().getAbsolutePath()
|
||||||
|
+ File.separator + DUMP_FILE;
|
||||||
|
try {
|
||||||
|
fileWriter = new FileOutputStream(fileName, false /* append */);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.e(TAG, "Can not open file.", e);
|
||||||
|
dumpEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Date date = Calendar.getInstance().getTime();
|
||||||
|
SimpleDateFormat df = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
|
||||||
|
String msg = df.format(date) + " " + TAG + ":" + statString + "\n";
|
||||||
|
try {
|
||||||
|
fileWriter.write(msg.getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Can not write to file.", e);
|
||||||
|
dumpEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logCpuUtilization() {
|
||||||
|
boolean logStatistics = false;
|
||||||
|
if (SystemClock.elapsedRealtime() - lastStatLogTimeMs >= CPU_STAT_LOG_PERIOD) {
|
||||||
|
lastStatLogTimeMs = SystemClock.elapsedRealtime();
|
||||||
|
logStatistics = true;
|
||||||
|
}
|
||||||
|
boolean cpuMonitorAvailable = sampleCpuUtilization();
|
||||||
|
if (logStatistics && cpuMonitorAvailable) {
|
||||||
|
String statString = getStatString();
|
||||||
|
checkDump(statString);
|
||||||
|
Log.d(TAG, statString);
|
||||||
|
resetStat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,8 +217,8 @@ class CpuMonitor {
|
|||||||
try {
|
try {
|
||||||
FileReader fin = new FileReader("/sys/devices/system/cpu/present");
|
FileReader fin = new FileReader("/sys/devices/system/cpu/present");
|
||||||
try {
|
try {
|
||||||
BufferedReader rdr = new BufferedReader(fin);
|
BufferedReader reader = new BufferedReader(fin);
|
||||||
Scanner scanner = new Scanner(rdr).useDelimiter("[-\n]");
|
Scanner scanner = new Scanner(reader).useDelimiter("[-\n]");
|
||||||
scanner.nextInt(); // Skip leading number 0.
|
scanner.nextInt(); // Skip leading number 0.
|
||||||
cpusPresent = 1 + scanner.nextInt();
|
cpusPresent = 1 + scanner.nextInt();
|
||||||
scanner.close();
|
scanner.close();
|
||||||
@ -108,20 +233,45 @@ class CpuMonitor {
|
|||||||
Log.e(TAG, "Error closing file");
|
Log.e(TAG, "Error closing file");
|
||||||
}
|
}
|
||||||
|
|
||||||
cpuFreq = new long [cpusPresent];
|
cpuFreqMax = new long[cpusPresent];
|
||||||
maxPath = new String[cpusPresent];
|
maxPath = new String[cpusPresent];
|
||||||
curPath = new String[cpusPresent];
|
curPath = new String[cpusPresent];
|
||||||
|
curFreqScales = new double[cpusPresent];
|
||||||
for (int i = 0; i < cpusPresent; i++) {
|
for (int i = 0; i < cpusPresent; i++) {
|
||||||
cpuFreq[i] = 0; // Frequency "not yet determined".
|
cpuFreqMax[i] = 0; // Frequency "not yet determined".
|
||||||
|
curFreqScales[i] = 0;
|
||||||
maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq";
|
maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq";
|
||||||
curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq";
|
curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq";
|
||||||
}
|
}
|
||||||
|
|
||||||
lastProcStat = new ProcStat(0, 0);
|
lastProcStat = new ProcStat(0, 0, 0);
|
||||||
|
resetStat();
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void resetStat() {
|
||||||
|
sumUserCpuUsage = 0;
|
||||||
|
sumSystemCpuUsage = 0;
|
||||||
|
sumFrequencyScale = 0;
|
||||||
|
sumTotalCpuUsage = 0;
|
||||||
|
iterations = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBatteryLevel() {
|
||||||
|
// Use sticky broadcast with null receiver to read battery level once only.
|
||||||
|
Intent intent = appContext.registerReceiver(
|
||||||
|
null /* receiver */, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||||
|
|
||||||
|
int batteryLevel = 0;
|
||||||
|
int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
|
||||||
|
if (batteryScale > 0) {
|
||||||
|
batteryLevel = (int) (
|
||||||
|
100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / batteryScale);
|
||||||
|
}
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-measure CPU use. Call this method at an interval of around 1/s.
|
* Re-measure CPU use. Call this method at an interval of around 1/s.
|
||||||
* This method returns true on success. The fields
|
* This method returns true on success. The fields
|
||||||
@ -130,36 +280,48 @@ class CpuMonitor {
|
|||||||
* cpuAvg3: The average CPU over the last 3 calls.
|
* cpuAvg3: The average CPU over the last 3 calls.
|
||||||
* cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls.
|
* cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls.
|
||||||
*/
|
*/
|
||||||
public boolean sampleCpuUtilization() {
|
private synchronized boolean sampleCpuUtilization() {
|
||||||
long lastSeenMaxFreq = 0;
|
long lastSeenMaxFreq = 0;
|
||||||
long cpufreqCurSum = 0;
|
long cpuFreqCurSum = 0;
|
||||||
long cpufreqMaxSum = 0;
|
long cpuFreqMaxSum = 0;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
if (cpusPresent == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
actualCpusPresent = 0;
|
||||||
for (int i = 0; i < cpusPresent; i++) {
|
for (int i = 0; i < cpusPresent; i++) {
|
||||||
/*
|
/*
|
||||||
* For each CPU, attempt to first read its max frequency, then its
|
* For each CPU, attempt to first read its max frequency, then its
|
||||||
* current frequency. Once as the max frequency for a CPU is found,
|
* current frequency. Once as the max frequency for a CPU is found,
|
||||||
* save it in cpuFreq[].
|
* save it in cpuFreqMax[].
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cpuFreq[i] == 0) {
|
curFreqScales[i] = 0;
|
||||||
|
if (cpuFreqMax[i] == 0) {
|
||||||
// We have never found this CPU's max frequency. Attempt to read it.
|
// We have never found this CPU's max frequency. Attempt to read it.
|
||||||
long cpufreqMax = readFreqFromFile(maxPath[i]);
|
long cpufreqMax = readFreqFromFile(maxPath[i]);
|
||||||
if (cpufreqMax > 0) {
|
if (cpufreqMax > 0) {
|
||||||
lastSeenMaxFreq = cpufreqMax;
|
lastSeenMaxFreq = cpufreqMax;
|
||||||
cpuFreq[i] = cpufreqMax;
|
cpuFreqMax[i] = cpufreqMax;
|
||||||
maxPath[i] = null; // Kill path to free its memory.
|
maxPath[i] = null; // Kill path to free its memory.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lastSeenMaxFreq = cpuFreq[i]; // A valid, previously read value.
|
lastSeenMaxFreq = cpuFreqMax[i]; // A valid, previously read value.
|
||||||
}
|
}
|
||||||
|
|
||||||
long cpufreqCur = readFreqFromFile(curPath[i]);
|
long cpuFreqCur = readFreqFromFile(curPath[i]);
|
||||||
cpufreqCurSum += cpufreqCur;
|
if (cpuFreqCur == 0 && lastSeenMaxFreq == 0) {
|
||||||
|
// No current frequency information for this CPU core - ignore it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cpuFreqCur > 0) {
|
||||||
|
actualCpusPresent++;
|
||||||
|
}
|
||||||
|
cpuFreqCurSum += cpuFreqCur;
|
||||||
|
|
||||||
/* Here, lastSeenMaxFreq might come from
|
/* Here, lastSeenMaxFreq might come from
|
||||||
* 1. cpuFreq[i], or
|
* 1. cpuFreq[i], or
|
||||||
@ -167,11 +329,14 @@ class CpuMonitor {
|
|||||||
* 3. a newly read value, or
|
* 3. a newly read value, or
|
||||||
* 4. hypothetically from the pre-loop dummy.
|
* 4. hypothetically from the pre-loop dummy.
|
||||||
*/
|
*/
|
||||||
cpufreqMaxSum += lastSeenMaxFreq;
|
cpuFreqMaxSum += lastSeenMaxFreq;
|
||||||
|
if (lastSeenMaxFreq > 0) {
|
||||||
|
curFreqScales[i] = (double) cpuFreqCur / lastSeenMaxFreq;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpufreqMaxSum == 0) {
|
if (cpuFreqCurSum == 0 || cpuFreqMaxSum == 0) {
|
||||||
Log.e(TAG, "Could not read max frequency for any CPU");
|
Log.e(TAG, "Could not read max or current frequency for any CPU");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,58 +347,85 @@ class CpuMonitor {
|
|||||||
* incorrect only if the frequencies have peeked or dropped in between the
|
* incorrect only if the frequencies have peeked or dropped in between the
|
||||||
* invocations.
|
* invocations.
|
||||||
*/
|
*/
|
||||||
double newPercentFreq = 100.0 * cpufreqCurSum / cpufreqMaxSum;
|
double newFrequencyScale = (double) cpuFreqCurSum / cpuFreqMaxSum;
|
||||||
double percentFreq;
|
double frequencyScale;
|
||||||
if (lastPercentFreq > 0) {
|
if (currentFrequencyScale > 0) {
|
||||||
percentFreq = (lastPercentFreq + newPercentFreq) * 0.5;
|
frequencyScale = (currentFrequencyScale + newFrequencyScale) * 0.5;
|
||||||
} else {
|
} else {
|
||||||
percentFreq = newPercentFreq;
|
frequencyScale = newFrequencyScale;
|
||||||
}
|
}
|
||||||
lastPercentFreq = newPercentFreq;
|
|
||||||
|
|
||||||
ProcStat procStat = readIdleAndRunTime();
|
ProcStat procStat = readProcStat();
|
||||||
if (procStat == null) {
|
if (procStat == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long diffRunTime = procStat.runTime - lastProcStat.runTime;
|
long diffUserTime = procStat.userTime - lastProcStat.userTime;
|
||||||
|
long diffSystemTime = procStat.systemTime - lastProcStat.systemTime;
|
||||||
long diffIdleTime = procStat.idleTime - lastProcStat.idleTime;
|
long diffIdleTime = procStat.idleTime - lastProcStat.idleTime;
|
||||||
|
long allTime = diffUserTime + diffSystemTime + diffIdleTime;
|
||||||
|
|
||||||
|
if (frequencyScale == 0 || allTime == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update statistics.
|
||||||
|
currentFrequencyScale = frequencyScale;
|
||||||
|
sumFrequencyScale += frequencyScale;
|
||||||
|
|
||||||
|
currentUserCpuUsage = (double) diffUserTime / allTime;
|
||||||
|
sumUserCpuUsage += currentUserCpuUsage;
|
||||||
|
|
||||||
|
currentSystemCpuUsage = (double) diffSystemTime / allTime;
|
||||||
|
sumSystemCpuUsage += currentSystemCpuUsage;
|
||||||
|
|
||||||
|
currentTotalCpuUsage = (currentUserCpuUsage + currentSystemCpuUsage) * currentFrequencyScale;
|
||||||
|
sumTotalCpuUsage += currentTotalCpuUsage;
|
||||||
|
|
||||||
|
iterations++;
|
||||||
// Save new measurements for next round's deltas.
|
// Save new measurements for next round's deltas.
|
||||||
lastProcStat = procStat;
|
lastProcStat = procStat;
|
||||||
|
|
||||||
long allTime = diffRunTime + diffIdleTime;
|
|
||||||
int percent = allTime == 0 ? 0 : (int) Math.round(percentFreq * diffRunTime / allTime);
|
|
||||||
percent = Math.max(0, Math.min(percent, 100));
|
|
||||||
|
|
||||||
// Subtract old relevant measurement, add newest.
|
|
||||||
sum3 += percent - percentVec[2];
|
|
||||||
// Subtract oldest measurement, add newest.
|
|
||||||
sum10 += percent - percentVec[SAMPLE_SAVE_NUMBER - 1];
|
|
||||||
|
|
||||||
// Rotate saved percent values, save new measurement in vacated spot.
|
|
||||||
for (int i = SAMPLE_SAVE_NUMBER - 1; i > 0; i--) {
|
|
||||||
percentVec[i] = percentVec[i - 1];
|
|
||||||
}
|
|
||||||
percentVec[0] = percent;
|
|
||||||
|
|
||||||
cpuCurrent = percent;
|
|
||||||
cpuAvg3 = sum3 / 3;
|
|
||||||
cpuAvgAll = sum10 / SAMPLE_SAVE_NUMBER;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCpuCurrent() {
|
private int doubleToPercent(double d) {
|
||||||
return cpuCurrent;
|
return (int) (d * 100 + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCpuAvg3() {
|
private int sumDoubleToPercent(double d, int iterations) {
|
||||||
return cpuAvg3;
|
if (iterations > 0) {
|
||||||
|
return (int) (d * 100.0 / (double) iterations + 0.5);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCpuAvgAll() {
|
private String getStatString() {
|
||||||
return cpuAvgAll;
|
StringBuilder stat = new StringBuilder();
|
||||||
|
stat.append("CPU User: ")
|
||||||
|
.append(doubleToPercent(currentUserCpuUsage)).append("/")
|
||||||
|
.append(sumDoubleToPercent(sumUserCpuUsage, iterations)).append(" (")
|
||||||
|
.append(doubleToPercent(currentUserCpuUsage * currentFrequencyScale)).append(")")
|
||||||
|
.append(". System: ")
|
||||||
|
.append(doubleToPercent(currentSystemCpuUsage)).append("/")
|
||||||
|
.append(sumDoubleToPercent(sumSystemCpuUsage, iterations)).append(" (")
|
||||||
|
.append(doubleToPercent(currentSystemCpuUsage * currentFrequencyScale)).append(")")
|
||||||
|
.append(". CPU freq %: ")
|
||||||
|
.append(doubleToPercent(currentFrequencyScale)).append("/")
|
||||||
|
.append(sumDoubleToPercent(sumFrequencyScale, iterations))
|
||||||
|
.append(". Total CPU usage: ")
|
||||||
|
.append(doubleToPercent(currentTotalCpuUsage)).append("/")
|
||||||
|
.append(sumDoubleToPercent(sumTotalCpuUsage, iterations))
|
||||||
|
.append(". Cores: ")
|
||||||
|
.append(actualCpusPresent);
|
||||||
|
stat.append("( ");
|
||||||
|
for (int i = 0; i < cpusPresent; i++) {
|
||||||
|
stat.append(doubleToPercent(curFreqScales[i])).append(" ");
|
||||||
|
}
|
||||||
|
stat.append("). Battery %: ")
|
||||||
|
.append(getBatteryLevel());
|
||||||
|
return stat.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,8 +458,9 @@ class CpuMonitor {
|
|||||||
* Read the current utilization of all CPUs using the cumulative first line
|
* Read the current utilization of all CPUs using the cumulative first line
|
||||||
* of /proc/stat.
|
* of /proc/stat.
|
||||||
*/
|
*/
|
||||||
private ProcStat readIdleAndRunTime() {
|
private ProcStat readProcStat() {
|
||||||
long runTime = 0;
|
long userTime = 0;
|
||||||
|
long systemTime = 0;
|
||||||
long idleTime = 0;
|
long idleTime = 0;
|
||||||
try {
|
try {
|
||||||
FileReader fin = new FileReader("/proc/stat");
|
FileReader fin = new FileReader("/proc/stat");
|
||||||
@ -275,11 +468,13 @@ class CpuMonitor {
|
|||||||
BufferedReader rdr = new BufferedReader(fin);
|
BufferedReader rdr = new BufferedReader(fin);
|
||||||
Scanner scanner = new Scanner(rdr);
|
Scanner scanner = new Scanner(rdr);
|
||||||
scanner.next();
|
scanner.next();
|
||||||
long user = scanner.nextLong();
|
userTime = scanner.nextLong();
|
||||||
long nice = scanner.nextLong();
|
long nice = scanner.nextLong();
|
||||||
long sys = scanner.nextLong();
|
userTime += nice;
|
||||||
runTime = user + nice + sys;
|
systemTime = scanner.nextLong();
|
||||||
idleTime = scanner.nextLong();
|
idleTime = scanner.nextLong();
|
||||||
|
long ioWaitTime = scanner.nextLong();
|
||||||
|
userTime += ioWaitTime;
|
||||||
scanner.close();
|
scanner.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Problems parsing /proc/stat");
|
Log.e(TAG, "Problems parsing /proc/stat");
|
||||||
@ -294,6 +489,6 @@ class CpuMonitor {
|
|||||||
Log.e(TAG, "Problems reading /proc/stat");
|
Log.e(TAG, "Problems reading /proc/stat");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new ProcStat(runTime, idleTime);
|
return new ProcStat(userTime, systemTime, idleTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,7 @@ public class HudFragment extends Fragment {
|
|||||||
private boolean videoCallEnabled;
|
private boolean videoCallEnabled;
|
||||||
private boolean displayHud;
|
private boolean displayHud;
|
||||||
private volatile boolean isRunning;
|
private volatile boolean isRunning;
|
||||||
private final CpuMonitor cpuMonitor = new CpuMonitor();
|
private CpuMonitor cpuMonitor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
@ -89,6 +89,10 @@ public class HudFragment extends Fragment {
|
|||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCpuMonitor(CpuMonitor cpuMonitor) {
|
||||||
|
this.cpuMonitor = cpuMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
private void hudViewsSetProperties(int visibility) {
|
private void hudViewsSetProperties(int visibility) {
|
||||||
hudViewBwe.setVisibility(visibility);
|
hudViewBwe.setVisibility(visibility);
|
||||||
hudViewConnection.setVisibility(visibility);
|
hudViewConnection.setVisibility(visibility);
|
||||||
@ -189,11 +193,9 @@ public class HudFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpuMonitor.sampleCpuUtilization()) {
|
if (cpuMonitor != null) {
|
||||||
encoderStat.append("CPU%: ")
|
encoderStat.append("CPU%: ").append(cpuMonitor.getCpuUsageCurrent())
|
||||||
.append(cpuMonitor.getCpuCurrent()).append("/")
|
.append(". Freq: ").append(cpuMonitor.getCpuFrequencyScaleCurrent());
|
||||||
.append(cpuMonitor.getCpuAvg3()).append("/")
|
|
||||||
.append(cpuMonitor.getCpuAvgAll());
|
|
||||||
}
|
}
|
||||||
encoderStatView.setText(encoderStat.toString());
|
encoderStatView.setText(encoderStat.toString());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -929,6 +929,7 @@ public class PeerConnectionClient {
|
|||||||
+ isError);
|
+ isError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "changeCaptureFormat: " + width + "x" + height + "@" + framerate);
|
||||||
videoCapturer.onOutputFormatRequest(width, height, framerate);
|
videoCapturer.onOutputFormatRequest(width, height, framerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,8 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,6 +26,7 @@ public class LooperExecutor extends Thread implements Executor {
|
|||||||
// Object used to signal that looper thread has started and Handler instance
|
// Object used to signal that looper thread has started and Handler instance
|
||||||
// associated with looper thread has been allocated.
|
// associated with looper thread has been allocated.
|
||||||
private final Object looperStartedEvent = new Object();
|
private final Object looperStartedEvent = new Object();
|
||||||
|
private final List<Runnable> scheduledPeriodicRunnables = new LinkedList<Runnable>();
|
||||||
private Handler handler = null;
|
private Handler handler = null;
|
||||||
private boolean running = false;
|
private boolean running = false;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
@ -79,6 +82,41 @@ public class LooperExecutor extends Thread implements Executor {
|
|||||||
return (Thread.currentThread().getId() == threadId);
|
return (Thread.currentThread().getId() == threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void scheduleAtFixedRate(final Runnable command, final long periodMillis) {
|
||||||
|
if (!running) {
|
||||||
|
Log.w(TAG, "Trying to schedule task for non running executor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Runnable runnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (running) {
|
||||||
|
command.run();
|
||||||
|
if (!handler.postDelayed(this, periodMillis)) {
|
||||||
|
Log.e(TAG, "Failed to post a delayed runnable in the chain.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scheduledPeriodicRunnables.add(runnable);
|
||||||
|
if (!handler.postDelayed(runnable, periodMillis)) {
|
||||||
|
Log.e(TAG, "Failed to post a delayed runnable.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void cancelScheduledTasks() {
|
||||||
|
if (!running) {
|
||||||
|
Log.w(TAG, "Trying to cancel schedule tasks for non running executor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop scheduled periodic tasks.
|
||||||
|
for (Runnable r : scheduledPeriodicRunnables) {
|
||||||
|
handler.removeCallbacks(r);
|
||||||
|
}
|
||||||
|
scheduledPeriodicRunnables.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void execute(final Runnable runnable) {
|
public synchronized void execute(final Runnable runnable) {
|
||||||
if (!running) {
|
if (!running) {
|
||||||
|
|||||||
Reference in New Issue
Block a user