2026-01-26 18:56:53 +09:00

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);
}
}
}