386 lines
14 KiB
C#
386 lines
14 KiB
C#
/*
|
|
* Copyright (c) 2022 LG Electronics Inc.
|
|
* SPDX-License-Identifier: LicenseRef-LGE-Proprietary
|
|
*/
|
|
// Copyright (c) 2020 LG Electronics Inc.
|
|
// SPDX-License-Identifier: LicenseRef-LGE-Proprietary
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using Aurora.Api;
|
|
|
|
namespace AuroraUIComponent.Views
|
|
{
|
|
internal class TactData
|
|
{
|
|
public TactData()
|
|
{
|
|
logger = new Logger("TactTimeView");
|
|
}
|
|
|
|
private Dictionary<string, LogItemCase> _dictLogItems = new Dictionary<string, LogItemCase>();
|
|
private Regex regex;
|
|
private readonly Logger logger;
|
|
private CaseType _caseType;
|
|
|
|
public DateTime StartTime1 => _dictLogItems.Count != 0 ? _dictLogItems.Min(item => item.Value.LogItem1.StartTime) : DateTime.Now;
|
|
public DateTime EndTime1 => _dictLogItems.Count != 0 ? _dictLogItems.Max(item => item.Value.LogItem1.EndTime) : DateTime.Now;
|
|
public DateTime StartTime2 => _dictLogItems.Count != 0 ? _dictLogItems.Min(item => item.Value.LogItem2.StartTime) : DateTime.Now;
|
|
public DateTime EndTime2 => _dictLogItems.Count != 0 ? _dictLogItems.Min(item => item.Value.LogItem2.EndTime) : DateTime.Now;
|
|
|
|
internal void Start(IList<string> files, string filePath, string searchKeyWord, double minFilter, CaseType caseType = CaseType.Case1, DateTime? st = null, DateTime? et = null)
|
|
{
|
|
//_dictLogItems.Clear();
|
|
_caseType = caseType;
|
|
regex = new Regex($"{searchKeyWord}(.*), tact\\[(.*)\\]");
|
|
for (int i = 0; i < files.Count; i++)
|
|
{
|
|
var path = Path.Combine(filePath, files[i]);
|
|
if (File.Exists(path) == false)
|
|
continue;
|
|
var lines = File.ReadAllLines(path, Encoding.Default);
|
|
for (int j = 0; j < lines.Length; j++)
|
|
{
|
|
GetTact(lines[j], minFilter);
|
|
}
|
|
}
|
|
List<string> remList;
|
|
if (caseType == CaseType.Case1)
|
|
{
|
|
remList = _dictLogItems.Where(item => item.Value.LogItem1.TactValues.Count < 2).Select(x => x.Key).ToList();
|
|
}
|
|
else
|
|
{
|
|
remList = _dictLogItems.Where(item => item.Value.LogItem2.TactValues.Count < 2).Select(x => x.Key).ToList();
|
|
}
|
|
|
|
foreach (var item in remList)
|
|
{
|
|
_dictLogItems.Remove(item);
|
|
}
|
|
CalcStat(st, et);
|
|
}
|
|
|
|
internal void ClearTable()
|
|
{
|
|
_dictLogItems.Clear();
|
|
}
|
|
|
|
internal void CalcStat(DateTime? st = null, DateTime? et = null)
|
|
{
|
|
if (_caseType == CaseType.Case1)
|
|
{
|
|
Parallel.ForEach(_dictLogItems, (logItem) => { logItem.Value.LogItem1.Calc(st, et); });
|
|
}
|
|
else
|
|
{
|
|
Parallel.ForEach(_dictLogItems, (logItem) => { logItem.Value.LogItem2.Calc(st, et); });
|
|
}
|
|
}
|
|
|
|
public List<LogItemCase> GetLogItems() => _dictLogItems.Values.ToList();
|
|
|
|
private void GetTact(string line, double minFilter)
|
|
{
|
|
try
|
|
{
|
|
var log = line.Split(new string[] { " " }, 2, StringSplitOptions.None);
|
|
if (log.Length < 2)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var match = regex.Match(log[1]);
|
|
if (match.Success)
|
|
{
|
|
//logger.Log(line);
|
|
var name = match.Groups[1].Value;
|
|
var tact = match.Groups[2].Value;
|
|
var tactVal = TimeSpan.Parse(tact);
|
|
if (tactVal.TotalMilliseconds < minFilter)
|
|
return;
|
|
|
|
if (_dictLogItems.TryGetValue(name, out LogItemCase item) == false)
|
|
{
|
|
item = new LogItemCase(name);
|
|
_dictLogItems[name] = item;
|
|
}
|
|
if (_caseType == CaseType.Case1)
|
|
{
|
|
item.LogItem1.TactValues.Add(new TimeValue<TimeSpan> { Time = Convert.ToDateTime(log[0]), Value = tactVal });
|
|
}
|
|
else
|
|
{
|
|
item.LogItem2.TactValues.Add(new TimeValue<TimeSpan> { Time = Convert.ToDateTime(log[0]), Value = tactVal });
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.E(ex.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum CaseType { Case1, Case2 }
|
|
public class LogItemCase
|
|
{
|
|
public LogItemCase(string name)
|
|
{
|
|
Name = name;
|
|
LogItem1 = new LogItem();
|
|
LogItem2 = new LogItem();
|
|
}
|
|
public string Name { get; set; }
|
|
public LogItem LogItem1 { get; set; }
|
|
public LogItem LogItem2 { get; set; }
|
|
public double DiffAve => LogItem2.Ave - LogItem1.Ave;
|
|
public double DiffStd => LogItem2.Std - LogItem1.Std;
|
|
public double DiffMin => LogItem2.Min - LogItem1.Min;
|
|
public double DiffMax => LogItem2.Max - LogItem1.Max;
|
|
public double DiffSum => LogItem2.Sum - LogItem1.Sum;
|
|
public double DiffRange => LogItem2.Range - LogItem1.Range;
|
|
public double DiffMaxAvg => LogItem2.Max_Avg - LogItem1.Max_Avg;
|
|
}
|
|
|
|
public class LogItem
|
|
{
|
|
public List<TimeValue<TimeSpan>> TactValues { get; set; } = new List<TimeValue<TimeSpan>>();
|
|
public DateTime StartTime { get => new DateTime(MinMs); }
|
|
public DateTime EndTime { get => new DateTime(MaxMs); }
|
|
public long MinMs { get; set; }
|
|
public long MaxMs { get; set; }
|
|
public double N { get; set; }
|
|
public double Ave { get; set; }
|
|
public double Std { get; set; }
|
|
public double Min { get; set; }
|
|
public double Max { get; set; }
|
|
public double Median { get; set; }
|
|
public double P25 { get; set; }
|
|
public double P75 { get; set; }
|
|
public double Skew { get; set; }
|
|
public double Kur { get; set; }
|
|
public double Sum { get; set; }
|
|
public double Range { get; set; }
|
|
public double Var { get; set; }
|
|
public double VarN { get; set; }
|
|
public double StdN { get; set; }
|
|
public double Mode { get; set; }
|
|
public double IQR { get; set; }
|
|
public double IQR_Max { get; set; }
|
|
public double IQR_Min { get; set; }
|
|
public double IQR_LowerLimit { get; set; }
|
|
public double IQR_UpperLimit { get; set; }
|
|
public List<double> Outlier { get; set; }
|
|
public double Max_Avg => Max - Ave;
|
|
|
|
public unsafe void Calc(DateTime? st = null, DateTime? et = null)
|
|
{
|
|
IEnumerable<TimeValue<TimeSpan>> temp = TactValues.ToList();
|
|
if (st != null)
|
|
{
|
|
temp = temp.Where(tv => tv.Time > st);
|
|
}
|
|
if (et != null)
|
|
{
|
|
temp = temp.Where(tv => tv.Time < et);
|
|
}
|
|
|
|
var time = temp.Select(tv => tv.Time.Ticks).ToArray();
|
|
var val = temp.Select(tv => tv.Value.TotalMilliseconds).ToArray();
|
|
BasicStat bs = new BasicStat();
|
|
|
|
fixed (double* p = val)
|
|
fixed (long* t = time)
|
|
{
|
|
bs.CalcBasicStat(val.Length, p, t);
|
|
bs.CalcStartEndTime(val.Length, t);
|
|
}
|
|
|
|
var fis = bs.GetType().GetFields();
|
|
foreach (var fi in fis)
|
|
{
|
|
var pi = this.GetType().GetProperty(fi.Name);
|
|
if (pi == null)
|
|
continue;
|
|
|
|
pi.SetValue(this, fi.GetValue(bs));
|
|
}
|
|
}
|
|
}
|
|
|
|
public class TimeValue<T>
|
|
{
|
|
public DateTime Time { get; set; }
|
|
public T Value { get; set; }
|
|
}
|
|
|
|
public class BasicStat
|
|
{
|
|
public double N;
|
|
public double Ave, Std, Min, Max, Median, P25, P75, Skew, Kur;
|
|
public double Sum, Range, Var, VarN, StdN, Mode;
|
|
public double IQR, IQR_Max, IQR_Min, IQR_LowerLimit, IQR_UpperLimit;
|
|
public List<double> Outlier;
|
|
public List<long> Time;
|
|
public long MinMs, MaxMs;
|
|
|
|
public BasicStat()
|
|
{
|
|
Outlier = new List<double>();
|
|
}
|
|
|
|
public unsafe void CalcBasicStat(int NumData, double* pDataBuf, long* pTimeBuf)
|
|
{
|
|
int i, N = NumData;
|
|
double dVal, dDiff, Sum, Sum2, Sum3, Sum4, Ave, Std, Min, Max, LLimit, ULimit;
|
|
double* pData;
|
|
long* pTime;
|
|
|
|
QuickSort2(pDataBuf, 0, N - 1, pTimeBuf);
|
|
|
|
Sum = Sum2 = Sum3 = Sum4 = 0.0;
|
|
pTime = pTimeBuf;
|
|
for (pData = pDataBuf, i = 0; i < N; i++, pData++)
|
|
{
|
|
dVal = *pData;
|
|
Sum += dVal; dVal *= dVal; Sum2 += dVal; dVal *= dVal;
|
|
Sum3 += dVal; dVal *= dVal; Sum4 += dVal;
|
|
}
|
|
|
|
this.Min = pDataBuf[0];
|
|
this.Max = pDataBuf[N - 1];
|
|
this.Range = this.Max - this.Min;
|
|
this.Sum = Sum;
|
|
this.Ave = Ave = (Sum / N);
|
|
this.Var = Math.Abs(Sum2 / N - Ave * Ave);
|
|
this.Std = Std = Math.Sqrt(this.Var);
|
|
this.Skew = ((Sum3 / N) - (3 * Ave * Std * Std) - (Ave * Ave * Ave)) / (Std * Std * Std);
|
|
|
|
this.P25 = pDataBuf[(int)(N * 0.25 + 0.5)];
|
|
this.Median = pDataBuf[(int)(N * 0.50 + 0.5)];
|
|
this.P75 = pDataBuf[(int)(N * 0.75 + 0.5)];
|
|
|
|
// Calc IQR for BoxPlot
|
|
this.IQR = this.P75 - this.P25;
|
|
this.IQR_UpperLimit = this.P75 + this.IQR * 1.5;
|
|
this.IQR_LowerLimit = this.P25 - this.IQR * 1.5;
|
|
|
|
Sum4 = Sum2 = dDiff = 0.0;
|
|
Min = this.P25; Max = this.P75;
|
|
LLimit = this.IQR_LowerLimit; ULimit = this.IQR_UpperLimit;
|
|
|
|
// dkdk.kim // Collect 15 outliers from the highest and lowest.
|
|
Outlier.Clear();
|
|
double?[] lowOutliers = new double?[15];
|
|
double?[] highOutliers = new double?[15];
|
|
|
|
long?[] lowOutliersTime = new long?[15];
|
|
long?[] highOutliersTime = new long?[15];
|
|
|
|
int numOfHalfOutliers = 15; int lowIdx = 0, highIdx = -1;
|
|
double lPrev = double.MaxValue, hPrev = double.MinValue;
|
|
|
|
for (pData = pDataBuf, i = 0; i < N; i++, pData++)
|
|
{
|
|
dVal = *pData;
|
|
dDiff = dVal - Ave; dDiff *= dDiff; // (X-Ave)^2
|
|
Sum2 += dDiff; dDiff *= dDiff; // (X-Ave)^4
|
|
Sum4 += dDiff;
|
|
if (dVal < Min && dVal > LLimit) Min = dVal;
|
|
if (dVal > Max && dVal < ULimit) Max = dVal;
|
|
if (lowIdx < numOfHalfOutliers && dVal < LLimit && dVal != lPrev)
|
|
{
|
|
//lowOutliersTime[lowIdx] =
|
|
lowOutliers[lowIdx++] = dVal;
|
|
|
|
lPrev = dVal;
|
|
}
|
|
else if (dVal > ULimit && dVal != hPrev)
|
|
{
|
|
highIdx = (highIdx + 1) % numOfHalfOutliers;
|
|
highOutliers[highIdx] = dVal;
|
|
hPrev = dVal;
|
|
}
|
|
//if (dVal < LLimit || dVal > ULimit)
|
|
//{
|
|
// if (nOut++ < 30)
|
|
// this.Outlier.Add(dVal);
|
|
// else
|
|
// break;
|
|
//}
|
|
}
|
|
this.Outlier.AddRange(lowOutliers.Where(x => x != null).Select(x => (double)x));
|
|
this.Outlier.AddRange(highOutliers.Where(x => x != null).Select(x => (double)x));
|
|
this.VarN = Sum2 / (N - 1);
|
|
this.StdN = Std = Math.Sqrt(this.VarN);
|
|
this.Kur = (Sum4 / N) / ((Sum2 / N) * (Sum2 / N)); // E[ (X-E[X])^4 ] / E[ (X-E[X])^2 ]^2
|
|
this.IQR_Min = Min;
|
|
this.IQR_Max = Max;
|
|
this.N = N;
|
|
}
|
|
|
|
public unsafe void CalcStartEndTime(int NumData, long* pTimeBuf)
|
|
{
|
|
QuickSort(pTimeBuf, 0, NumData - 1);
|
|
MinMs = pTimeBuf[0];
|
|
MaxMs = pTimeBuf[NumData - 1];
|
|
}
|
|
|
|
private unsafe static void QuickSort2<T1, T2>(T1* pValue, int left, int right, T2* pTime) where T1 : unmanaged where T2 : unmanaged
|
|
{
|
|
int i = left, j = right;
|
|
T1 pivot = pValue[(left + right) / 2];
|
|
T1 temp;
|
|
T2 tempTime;
|
|
do
|
|
{
|
|
while (Comparer<T1>.Default.Compare(pValue[i], pivot) < 0) i++; // pDouble[i] < pivot
|
|
while (Comparer<T1>.Default.Compare(pValue[j], pivot) > 0) j--; // pDouble[j] > pivot
|
|
if (i <= j)
|
|
{
|
|
temp = pValue[i]; pValue[i] = pValue[j]; pValue[j] = temp;
|
|
tempTime = pTime[i]; pTime[i] = pTime[j]; pTime[j] = tempTime;
|
|
i++; j--;
|
|
}
|
|
} while (i <= j);
|
|
|
|
/* recursion */
|
|
if (left < j)
|
|
QuickSort2(pValue, left, j, pTime);
|
|
|
|
if (i < right)
|
|
QuickSort2(pValue, i, right, pTime);
|
|
}
|
|
|
|
private unsafe static void QuickSort<T>(T* pValue, int left, int right) where T : unmanaged
|
|
{
|
|
int i = left, j = right;
|
|
T pivot = pValue[(left + right) / 2];
|
|
T temp;
|
|
do
|
|
{
|
|
while (Comparer<T>.Default.Compare(pValue[i], pivot) < 0 ) i++; // pDouble[i] < pivot
|
|
while (Comparer<T>.Default.Compare(pValue[j], pivot) > 0 ) j--; // pDouble[j] > pivot
|
|
if (i <= j)
|
|
{
|
|
temp = pValue[i]; pValue[i] = pValue[j]; pValue[j] = temp;
|
|
i++; j--;
|
|
}
|
|
} while (i <= j);
|
|
|
|
/* recursion */
|
|
if (left < j)
|
|
QuickSort(pValue, left, j);
|
|
|
|
if (i < right)
|
|
QuickSort(pValue, i, right);
|
|
}
|
|
}
|
|
}
|