Time estimation work
This commit is contained in:
@@ -13,15 +13,22 @@ namespace LeafWeb.Core.Tests.Utility
|
||||
[Test]
|
||||
public void EstimateTest()
|
||||
{
|
||||
Func<int, int> scaleFunc = i => i*i;
|
||||
Func<int, int> scaleFunc = i => i*60*10;
|
||||
|
||||
var obervations =
|
||||
from i in Enumerable.Range(1, 10)
|
||||
let time = scaleFunc(i)
|
||||
//var obervations =
|
||||
// from i in Enumerable.Range(1, 10)
|
||||
// let time = scaleFunc(i)
|
||||
// select Mock.Of<ILeafInput>(li =>
|
||||
// li.InputFiles.Count == i &&
|
||||
// li.TimeInProgress == TimeSpan.FromMinutes(time));
|
||||
|
||||
var obervations =
|
||||
from d in data
|
||||
select Mock.Of<ILeafInput>(li =>
|
||||
li.InputFiles.Count == i &&
|
||||
li.TimeInProgress == TimeSpan.FromMinutes(time));
|
||||
|
||||
li.InputFiles.Count == d.Item1 &&
|
||||
li.TimeInProgress == TimeSpan.FromSeconds(d.Item2)
|
||||
);
|
||||
|
||||
var estimater = new TimeInProgressEstimater(obervations.ToArray());
|
||||
|
||||
Action<int> est = i =>
|
||||
@@ -31,8 +38,94 @@ namespace LeafWeb.Core.Tests.Utility
|
||||
Console.WriteLine($"{i} => {estimate}. {TimeSpan.FromMinutes(scaleFunc(i))}");
|
||||
};
|
||||
|
||||
for (var i = 1; i < 30; i++)
|
||||
for (var i = 1; i < 100; i++)
|
||||
est(i);
|
||||
}
|
||||
|
||||
private Tuple<int,double>[] data =
|
||||
{
|
||||
Tuple.Create(3, 990.347),
|
||||
Tuple.Create(11, 5688.136),
|
||||
Tuple.Create(166, 243433.25),
|
||||
Tuple.Create(156, 96585.35),
|
||||
Tuple.Create(23, 205828.927),
|
||||
Tuple.Create(10, 4679.583),
|
||||
Tuple.Create(20, 28568.39),
|
||||
Tuple.Create(3, 1456.104),
|
||||
Tuple.Create(3, 1144.78),
|
||||
Tuple.Create(23, 12356.24),
|
||||
Tuple.Create(5, 10149.49),
|
||||
Tuple.Create(10, 4832.93),
|
||||
Tuple.Create(4, 1770.086),
|
||||
Tuple.Create(8, 4727.98),
|
||||
Tuple.Create(20, 35137.31),
|
||||
Tuple.Create(20, 38265.414),
|
||||
Tuple.Create(20, 23023.103),
|
||||
Tuple.Create(20, 28994.213),
|
||||
Tuple.Create(8, 6755.817),
|
||||
Tuple.Create(20, 11458.047),
|
||||
Tuple.Create(20, 13239.973),
|
||||
Tuple.Create(1, 155.907),
|
||||
Tuple.Create(1, 198.236),
|
||||
Tuple.Create(4, 6171.793),
|
||||
Tuple.Create(13, 6036.343),
|
||||
Tuple.Create(13, 6287.683),
|
||||
Tuple.Create(1, 230.48),
|
||||
Tuple.Create(2, 3134.58),
|
||||
Tuple.Create(15, 26254.85),
|
||||
Tuple.Create(17, 10140.037),
|
||||
Tuple.Create(10, 7622.307),
|
||||
Tuple.Create(8, 9016.327),
|
||||
Tuple.Create(9, 8037.403),
|
||||
Tuple.Create(18, 14819.907),
|
||||
Tuple.Create(4, 2744.767),
|
||||
Tuple.Create(30, 26198.996),
|
||||
Tuple.Create(27, 25819.637),
|
||||
Tuple.Create(30, 17456.014),
|
||||
Tuple.Create(28, 17611.16),
|
||||
Tuple.Create(24, 8778.873),
|
||||
Tuple.Create(1, 343.343),
|
||||
Tuple.Create(2, 797.004),
|
||||
Tuple.Create(1, 199.92),
|
||||
Tuple.Create(24, 13000.967),
|
||||
Tuple.Create(18, 15778.11),
|
||||
Tuple.Create(5, 3511.834),
|
||||
Tuple.Create(5, 1211.593),
|
||||
Tuple.Create(5, 8895.523),
|
||||
Tuple.Create(5, 3537.074),
|
||||
Tuple.Create(5, 2411.197),
|
||||
Tuple.Create(5, 11243.546),
|
||||
Tuple.Create(6, 3967.287),
|
||||
Tuple.Create(6, 3912.07),
|
||||
Tuple.Create(5, 2406.013),
|
||||
Tuple.Create(5, 11237.71),
|
||||
Tuple.Create(35, 16774.884),
|
||||
Tuple.Create(31, 12828.044),
|
||||
Tuple.Create(30, 15379.2),
|
||||
Tuple.Create(30, 15139.8),
|
||||
Tuple.Create(36, 59509.324),
|
||||
Tuple.Create(33, 36650.247),
|
||||
Tuple.Create(35, 17443.134),
|
||||
Tuple.Create(32, 17103.803),
|
||||
Tuple.Create(32, 23901.747),
|
||||
Tuple.Create(31, 17996.223),
|
||||
Tuple.Create(36, 35667.134),
|
||||
Tuple.Create(33, 25839.96),
|
||||
Tuple.Create(30, 30598.057),
|
||||
Tuple.Create(1, 559.94),
|
||||
Tuple.Create(30, 37881.45),
|
||||
Tuple.Create(1, 1536.64),
|
||||
Tuple.Create(1, 1635.797),
|
||||
Tuple.Create(6, 5198.684),
|
||||
Tuple.Create(30, 33436.844),
|
||||
Tuple.Create(30, 46370.277),
|
||||
Tuple.Create(29, 2054.907),
|
||||
Tuple.Create(24, 1898.857),
|
||||
Tuple.Create(24, 2658.23),
|
||||
Tuple.Create(40, 3984.13),
|
||||
Tuple.Create(29, 4258.67),
|
||||
Tuple.Create(24, 3210.917),
|
||||
Tuple.Create(24, 2931.43)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,16 @@ namespace LeafWeb.Core.DAL
|
||||
select s).Max(s => s.DateTime));
|
||||
}
|
||||
|
||||
public IEnumerable<LeafInput> GetLeafInputRecentlyCompleted(int count)
|
||||
{
|
||||
return
|
||||
_db.LeafInputs
|
||||
.Where(li => li.CurrentStatus == LeafInputStatusType.Complete)
|
||||
.Take(count)
|
||||
.ToList()
|
||||
.Where(li => li.OutputErrorMessage == null);
|
||||
}
|
||||
|
||||
public LeafInput GetLeafInput(int id)
|
||||
{
|
||||
return _db.LeafInputs.FirstOrDefault(li => li.Id == id);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LeafWeb.Core.Entities;
|
||||
using MathNet.Numerics;
|
||||
|
||||
@@ -23,7 +24,15 @@ namespace LeafWeb.Core.Utility
|
||||
_yData = yData.ToArray();
|
||||
}
|
||||
|
||||
private Func<double, double> FitFunc => Fit.PolynomialFunc(_xData, _yData, 3);
|
||||
private static Func<double, double> Positivize => i => i <= 0 ? 1 : i;
|
||||
|
||||
private IEnumerable<double> Div => _xData.Zip(_yData, (x, y) => y/x);
|
||||
|
||||
private Func<double, double> AverageFitFunc => i => Div.Average()*i;
|
||||
|
||||
private Func<double, double> LineFitFunc => Fit.LineFunc(_xData, _yData);
|
||||
|
||||
private Func<double, double> FitFunc => i => (Positivize(LineFitFunc(i)) + AverageFitFunc(i))/2;
|
||||
|
||||
public TimeSpan EstimateTimeInProgress(ILeafInput leafInput)
|
||||
{
|
||||
@@ -32,7 +41,10 @@ namespace LeafWeb.Core.Utility
|
||||
|
||||
public TimeSpan EstimateTimeInProgress(int inputFileCount)
|
||||
{
|
||||
return ConvertToTimeSpan(FitFunc(inputFileCount));
|
||||
var estimate = FitFunc(inputFileCount);
|
||||
if (estimate <= 0)
|
||||
estimate = 1;
|
||||
return ConvertToTimeSpan(estimate);
|
||||
}
|
||||
|
||||
private static double ConvertFromTimeSpan(TimeSpan timeSpan)
|
||||
@@ -42,16 +54,19 @@ namespace LeafWeb.Core.Utility
|
||||
|
||||
private static TimeSpan ConvertToTimeSpan(double estimate)
|
||||
{
|
||||
int int32;
|
||||
return TimeSpan.FromSeconds(ConvertToInt32Guarded(estimate));
|
||||
}
|
||||
|
||||
private static Func<double, int> ConvertToInt32Guarded => d =>
|
||||
{
|
||||
try
|
||||
{
|
||||
int32 = Convert.ToInt32(estimate);
|
||||
return Convert.ToInt32(d);
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
int32 = int.MaxValue;
|
||||
return int.MaxValue;
|
||||
}
|
||||
return TimeSpan.FromSeconds(int32);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.g_xi0dfe.dll
|
||||
C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.re2ngwmg.dll
|
||||
@@ -35,8 +35,8 @@ namespace LeafWeb.WebCms.Controllers
|
||||
}
|
||||
|
||||
// completed leaf input for computing runtime statistics
|
||||
var completedLeafInput = DataService.GetLeafInputsOrdered().Where(li => li.CurrentStatus == LeafInputStatusType.Complete);
|
||||
var timeInProgressEstimater = new TimeInProgressEstimater(completedLeafInput.Take(20));
|
||||
var completedLeafInput = DataService.GetLeafInputRecentlyCompleted(100);
|
||||
var timeInProgressEstimater = new TimeInProgressEstimater(completedLeafInput);
|
||||
|
||||
var serviceDescription = ServiceDescription();
|
||||
|
||||
@@ -49,6 +49,14 @@ namespace LeafWeb.WebCms.Controllers
|
||||
return View(queueViewModel);
|
||||
}
|
||||
|
||||
public ActionResult LeafInputStatistics()
|
||||
{
|
||||
var data =
|
||||
from li in DataService.GetLeafInputRecentlyCompleted(100)
|
||||
select $"{li.InputFiles.Count}, {li.TimeInProgress.TotalSeconds}";
|
||||
return Content(string.Join("<br />", data));
|
||||
}
|
||||
|
||||
public ActionResult Search(string query)
|
||||
{
|
||||
var nameValueCollection = new NameValueCollection {{"query", query}};
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
<span class="glyphicon glyphicon-download"></span> Download ToUser
|
||||
</a>
|
||||
|
||||
<a href="@Url.Action("DownloadOutputNotToUser", "Queue", new {id = Model.LeafInputId})"
|
||||
class="btn btn-default@{if (!Model.HasOutputFiles)
|
||||
{<text> disabled</text>}}" role="button">
|
||||
<span class="glyphicon glyphicon-download"></span> Download NotToUser
|
||||
</a>
|
||||
|
||||
@using (Html.BeginUmbracoForm<QueueController>(
|
||||
"SendUserDownloadLink", null, new { @class = "confirm", confirm_msg = "Confirm sending email to user" }))
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="col-lg-8">
|
||||
Service description: @Model.ServerDescription<br/>
|
||||
Est. processing time by LeafInput size -
|
||||
<i class="fa fa-file-o"></i> < 1: <strong>@Model.TimeInProgressEstimater.EstimateTimeInProgress(1).ToRoundedReadableString()</strong>
|
||||
<i class="fa fa-file-o"></i> 1: <strong>@Model.TimeInProgressEstimater.EstimateTimeInProgress(1).ToRoundedReadableString()</strong>
|
||||
<i class="fa fa-file-o"></i> 10: <strong>@Model.TimeInProgressEstimater.EstimateTimeInProgress(10).ToRoundedReadableString()</strong>
|
||||
<i class="fa fa-file-o"></i> 100: <strong>@Model.TimeInProgressEstimater.EstimateTimeInProgress(100).ToRoundedReadableString()</strong>
|
||||
</div>
|
||||
@@ -59,7 +59,16 @@ if (leafInput.IsPending)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-nowrap">
|
||||
@Html.Partial("DisplayTemplates/_LeafInputStatus", leafInput.CurrentStatus.ToString())
|
||||
@if (leafInput.OutputErrorMessage != null)
|
||||
{
|
||||
<i class="fa fa-warning text-danger"></i>
|
||||
} else if (leafInput.OutputWarningMessage != null)
|
||||
{
|
||||
<i class="fa fa-warning text-info"></i>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user