Time estimation work

This commit is contained in:
2017-02-07 12:02:22 -05:00
parent 223a1c996a
commit 5f0e9baf1d
7 changed files with 160 additions and 19 deletions
@@ -13,14 +13,21 @@ 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)
// select Mock.Of<ILeafInput>(li =>
// li.InputFiles.Count == i &&
// li.TimeInProgress == TimeSpan.FromMinutes(time));
var obervations =
from i in Enumerable.Range(1, 10)
let time = scaleFunc(i)
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());
@@ -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)
};
}
}
+10
View File
@@ -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);
+22 -7
View File
@@ -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
View File
@@ -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
+10 -2
View File
@@ -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}};
+6
View File
@@ -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 -1
View File
@@ -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>
}
}