From f9454f8859a4ef959eabc40adc3338bc274889bf Mon Sep 17 00:00:00 2001 From: Logan McKinley Date: Thu, 17 Jan 2019 17:09:10 -0500 Subject: [PATCH 1/4] worked on itnial implementation of the cpu utilization probe for #591 --- .../AndroidProcessorUtilizationProbe.cs | 142 ++++++++++++++++++ .../Sensus.Android.Shared.projitems | 1 + Sensus.Android/Sensus.Android.csproj | 6 +- .../Device/ProcessorUtilizationDatum.cs | 68 +++++++++ .../Device/ProcessorUtilizationProbe.cs | 105 +++++++++++++ Sensus.Shared/Sensus.Shared.projitems | 2 + 6 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs create mode 100644 Sensus.Shared/Probes/Device/ProcessorUtilizationDatum.cs create mode 100644 Sensus.Shared/Probes/Device/ProcessorUtilizationProbe.cs diff --git a/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs b/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs new file mode 100644 index 000000000..991254108 --- /dev/null +++ b/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs @@ -0,0 +1,142 @@ +// Copyright 2014 The Rector & Visitors of the University of Virginia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Sensus.Probes.Device; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Sensus.Android.Probes.Device +{ + public class AndroidProcessorUtilizationProbe : ProcessorUtilizationProbe + { + private bool _running = false; + private string _cmd; + protected override async Task InitializeAsync() + { + await base.InitializeAsync(); + + int pid = global::Android.OS.Process.MyPid(); + + //run the top terminal command -n 1 (only run 1 iteration) + //-b (use batch mode) + //-q (don't show the header info) + //-p {pid} (only return for the sensus) + //-o %CPU (only return the CPU% + //this is a different version of top than most of the documentation i found. The best thing to do is to run "top --help" on the device + _cmd = $"top -n 1 -b -q -p {pid} -o %CPU";//TODO: We could get mem% or process time from this command if we wanted using the follow in cmd $"top -n 1 -b -q -p {pid} -o %CPU,%MEM,TIME+" + } + + protected override async Task StartListeningAsync() + { + _running = true; + while (_running) + { + await RecordUtilization(); //remove the await + await Task.Delay(MinDataStoreDelay.HasValue ? MinDataStoreDelay.Value.Milliseconds : 1000); + } + } + + protected override Task StopListeningAsync() + { + _running = false; + return Task.CompletedTask; + } + + //https://stackoverflow.com/questions/2467579/how-to-get-cpu-usage-statistics-on-android This shows the basic idea i used but i had to modify the command quite a bit + private async Task RecordUtilization() + { + + try + { + Java.Lang.Process p = Java.Lang.Runtime.GetRuntime().Exec(_cmd); + + + var inputVal = await ReadStream(p.InputStream); + if(inputVal == null) + { + var errorOutput = await ReadStream(p.ErrorStream); + if(string.IsNullOrWhiteSpace(errorOutput) == false) + { + throw new NotSupportedException(errorOutput); + } + else + { + throw new NotSupportedException(); + } + } + + if(double.TryParse(inputVal.Trim(), out double cpuPercent) == false) + { + throw new InvalidDataException(inputVal + " cannot be converted into a double"); + } + + await StoreDatumAsync(new ProcessorUtilizationDatum(DateTimeOffset.UtcNow, cpuPercent)); + + } + catch (IOException) + { + + } + } + + private async Task ReadStream(Stream s) + { + string rVal = null; + try + { + using (var streamReader = new StreamReader(s)) + { + if (streamReader.EndOfStream == false) + { + rVal = await streamReader.ReadToEndAsync(); + System.Diagnostics.Trace.Write(rVal); + } + } + } + finally + { + s.Close(); + s.Dispose(); + } + return rVal; + } + + + //The link in the issue didn't show cpu utilization but just the cpu hardware info. I left the code here if that info would would useful for you. + //https://stackoverflow.com/questions/46714396/how-to-find-cpu-load-of-any-android-device-programmatically + //private async Task GetProcessorHardwareInfo() + //{ + // try + // { + // string holder = ""; + // string[] DATA = { "/system/bin/cat", "/proc/cpuinfo" }; + // Java.Lang.ProcessBuilder processBuilder = new Java.Lang.ProcessBuilder(DATA); + // Java.Lang.Process process = processBuilder.Start(); + // using (var inputStream = process.InputStream) + // { + // using (var streamReader = new StreamReader(inputStream)) + // { + // holder = await streamReader.ReadToEndAsync(); + // } + // } + // } + // catch (Exception) + // { + // } + //} + + } +} diff --git a/Sensus.Android.Shared/Sensus.Android.Shared.projitems b/Sensus.Android.Shared/Sensus.Android.Shared.projitems index db36551fa..c23c26ada 100644 --- a/Sensus.Android.Shared/Sensus.Android.Shared.projitems +++ b/Sensus.Android.Shared/Sensus.Android.Shared.projitems @@ -11,6 +11,7 @@ + diff --git a/Sensus.Android/Sensus.Android.csproj b/Sensus.Android/Sensus.Android.csproj index 33c76d0ba..a8b20c65d 100644 --- a/Sensus.Android/Sensus.Android.csproj +++ b/Sensus.Android/Sensus.Android.csproj @@ -44,7 +44,8 @@ Store. It is possible to run and debug this project on physical and virtual Andr 1591 - + + true bin\Release\ TRACE;RELEASE @@ -388,8 +389,7 @@ Store. It is possible to run and debug this project on physical and virtual Andr - - + diff --git a/Sensus.Shared/Probes/Device/ProcessorUtilizationDatum.cs b/Sensus.Shared/Probes/Device/ProcessorUtilizationDatum.cs new file mode 100644 index 000000000..2353ef95d --- /dev/null +++ b/Sensus.Shared/Probes/Device/ProcessorUtilizationDatum.cs @@ -0,0 +1,68 @@ +// Copyright 2014 The Rector & Visitors of the University of Virginia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using Sensus.Anonymization; +using Sensus.Anonymization.Anonymizers; +using Sensus.Probes.User.Scripts.ProbeTriggerProperties; + +namespace Sensus.Probes.Device +{ + public class ProcessorUtilizationDatum : Datum + { + private double _cpuPercent; + + [DoubleProbeTriggerProperty] + [Anonymizable(null, typeof(DoubleRoundingTensAnonymizer), false)] + public double CpuPercent + { + get { return _cpuPercent; } + set { _cpuPercent = value; } + } + + public override string DisplayDetail + { + get { return "Cpu Utilization: " + _cpuPercent +"%"; } + } + + /// + /// Gets the string placeholder value, which is the CPU Pervent. + /// + /// The string placeholder value. + public override object StringPlaceholderValue + { + get + { + return _cpuPercent+ "%"; + } + } + + /// + /// For JSON deserialization. + /// + private ProcessorUtilizationDatum() { } + + public ProcessorUtilizationDatum(DateTimeOffset timestamp, double cpuPercent) + : base(timestamp) + { + _cpuPercent = cpuPercent; + } + + public override string ToString() + { + return base.ToString() + Environment.NewLine + + DisplayDetail; + } + } +} diff --git a/Sensus.Shared/Probes/Device/ProcessorUtilizationProbe.cs b/Sensus.Shared/Probes/Device/ProcessorUtilizationProbe.cs new file mode 100644 index 000000000..396932aed --- /dev/null +++ b/Sensus.Shared/Probes/Device/ProcessorUtilizationProbe.cs @@ -0,0 +1,105 @@ +// Copyright 2014 The Rector & Visitors of the University of Virginia +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Syncfusion.SfChart.XForms; + +namespace Sensus.Probes.Device +{ + /// + /// Provides the readings. + /// + public abstract class ProcessorUtilizationProbe : ListeningProbe + { + + [JsonIgnore] + protected override bool DefaultKeepDeviceAwake + { + get + { + return true; + } + } + + [JsonIgnore] + protected override string DeviceAwakeWarning + { + get + { + return "This setting does not affect iOS. Android devices will use additional power to report all updates."; + } + } + + [JsonIgnore] + protected override string DeviceAsleepWarning + { + get + { + return "This setting does not affect iOS. Android devices will sleep and pause updates."; + } + } + + public sealed override string DisplayName + { + get { return "Processor Utilization"; } + } + + public sealed override Type DatumType + { + get { return typeof(ProcessorUtilizationDatum); } + } + + protected override async Task InitializeAsync() + { + await base.InitializeAsync(); + } + + + + + protected override ChartSeries GetChartSeries() + { + throw new NotImplementedException(); + } + + protected override ChartDataPoint GetChartDataPointFromDatum(Datum datum) + { + return new ChartDataPoint(datum.Timestamp.LocalDateTime, (datum as ProcessorUtilizationDatum).CpuPercent); + } + + protected override ChartAxis GetChartPrimaryAxis() + { + return new DateTimeAxis + { + Title = new ChartAxisTitle + { + Text = "Time" + } + }; + } + + protected override RangeAxisBase GetChartSecondaryAxis() + { + return new NumericalAxis + { + Title = new ChartAxisTitle + { + Text = "CPU Utilization (%)" + } + }; + } + } +} \ No newline at end of file diff --git a/Sensus.Shared/Sensus.Shared.projitems b/Sensus.Shared/Sensus.Shared.projitems index 044490ef8..933ef5afd 100644 --- a/Sensus.Shared/Sensus.Shared.projitems +++ b/Sensus.Shared/Sensus.Shared.projitems @@ -38,6 +38,8 @@ + + From b94d6c68c84c93ca60237a0fd06d5bef379b5a09 Mon Sep 17 00:00:00 2001 From: Logan McKinley Date: Thu, 17 Jan 2019 17:16:12 -0500 Subject: [PATCH 2/4] why must vs make random changes to project files. --- Sensus.Android/Sensus.Android.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sensus.Android/Sensus.Android.csproj b/Sensus.Android/Sensus.Android.csproj index a8b20c65d..33c76d0ba 100644 --- a/Sensus.Android/Sensus.Android.csproj +++ b/Sensus.Android/Sensus.Android.csproj @@ -44,8 +44,7 @@ Store. It is possible to run and debug this project on physical and virtual Andr 1591 - - + true bin\Release\ TRACE;RELEASE @@ -389,7 +388,8 @@ Store. It is possible to run and debug this project on physical and virtual Andr - + + From 5776915c97e44f1a602190612a0ffb326ac14d27 Mon Sep 17 00:00:00 2001 From: Logan McKinley Date: Fri, 18 Jan 2019 08:42:00 -0500 Subject: [PATCH 3/4] did some cleanup --- .../AndroidProcessorUtilizationProbe.cs | 9 ++-- .../Device/iOSProcessorUtilizationProbe.cs | 43 +++++++++++++++++++ Sensus.iOS.Shared/Sensus.iOS.Shared.projitems | 1 + 3 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs diff --git a/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs b/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs index 991254108..131e9a7fd 100644 --- a/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs +++ b/Sensus.Android.Shared/Probes/Device/AndroidProcessorUtilizationProbe.cs @@ -22,7 +22,6 @@ namespace Sensus.Android.Probes.Device { public class AndroidProcessorUtilizationProbe : ProcessorUtilizationProbe { - private bool _running = false; private string _cmd; protected override async Task InitializeAsync() { @@ -41,8 +40,7 @@ protected override async Task InitializeAsync() protected override async Task StartListeningAsync() { - _running = true; - while (_running) + while (Running) { await RecordUtilization(); //remove the await await Task.Delay(MinDataStoreDelay.HasValue ? MinDataStoreDelay.Value.Milliseconds : 1000); @@ -51,7 +49,6 @@ protected override async Task StartListeningAsync() protected override Task StopListeningAsync() { - _running = false; return Task.CompletedTask; } @@ -86,9 +83,9 @@ private async Task RecordUtilization() await StoreDatumAsync(new ProcessorUtilizationDatum(DateTimeOffset.UtcNow, cpuPercent)); } - catch (IOException) + catch (Exception exc) { - + SensusServiceHelper.Get().Logger.Log("Error getting CPU Utilization. msg:"+exc.Message, LoggingLevel.Normal, GetType()); } } diff --git a/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs b/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs new file mode 100644 index 000000000..6e583dc0f --- /dev/null +++ b/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs @@ -0,0 +1,43 @@ +using Sensus.Probes.Device; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace Sensus.iOS.Probes.Device +{ + public class iOSProcessorUtilizationProbe : ProcessorUtilizationProbe + { + private bool _running = false; + protected override async Task InitializeAsync() + { + await base.InitializeAsync(); + } + + protected override async Task StartListeningAsync() + { + while (Running) + { + await RecordUtilization(); //remove the await + await Task.Delay(MinDataStoreDelay.HasValue ? MinDataStoreDelay.Value.Milliseconds : 1000); + } + } + + protected override Task StopListeningAsync() + { + return Task.CompletedTask; + } + + private async Task RecordUtilization() + { + try + { + + } + catch(Exception exc) + { + SensusServiceHelper.Get().Logger.Log("Error getting CPU Utilization. msg:" + exc.Message, LoggingLevel.Normal, GetType()); + } + } + } +} diff --git a/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems b/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems index a47499363..9ba24eb70 100644 --- a/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems +++ b/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems @@ -13,6 +13,7 @@ + From c793189f3076d0cdd699d7d861ec62fa7aa8c6ae Mon Sep 17 00:00:00 2001 From: Ryan Dagostino Date: Mon, 25 Feb 2019 09:10:27 -0500 Subject: [PATCH 4/4] #591 removed iOS probe for CPU usage --- .../Device/iOSProcessorUtilizationProbe.cs | 43 ------------------- Sensus.iOS.Shared/Sensus.iOS.Shared.projitems | 1 - 2 files changed, 44 deletions(-) delete mode 100644 Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs diff --git a/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs b/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs deleted file mode 100644 index 6e583dc0f..000000000 --- a/Sensus.iOS.Shared/Probes/Device/iOSProcessorUtilizationProbe.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Sensus.Probes.Device; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace Sensus.iOS.Probes.Device -{ - public class iOSProcessorUtilizationProbe : ProcessorUtilizationProbe - { - private bool _running = false; - protected override async Task InitializeAsync() - { - await base.InitializeAsync(); - } - - protected override async Task StartListeningAsync() - { - while (Running) - { - await RecordUtilization(); //remove the await - await Task.Delay(MinDataStoreDelay.HasValue ? MinDataStoreDelay.Value.Milliseconds : 1000); - } - } - - protected override Task StopListeningAsync() - { - return Task.CompletedTask; - } - - private async Task RecordUtilization() - { - try - { - - } - catch(Exception exc) - { - SensusServiceHelper.Get().Logger.Log("Error getting CPU Utilization. msg:" + exc.Message, LoggingLevel.Normal, GetType()); - } - } - } -} diff --git a/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems b/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems index 9ba24eb70..a47499363 100644 --- a/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems +++ b/Sensus.iOS.Shared/Sensus.iOS.Shared.projitems @@ -13,7 +13,6 @@ -