/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.server.shared;
import java.util.Map;
import java.util.Map.Entry;
import com.servoy.j2db.dataprocessing.IDataServer;
/**
* Timing of actions like queries in the server.
*
* @author jblok
*/
public class PerformanceTimingAggregate extends PerformanceAggregator
{
private final String action;
private long min_ms;
private long max_ms;
private long s2; // used for running calculation of standard deviation
private int count;
private final int type;
private long xtotal_ms;
private long total_interval_ms;
private PerformanceTimingAggregate totalSubActionTimes;
public PerformanceTimingAggregate(String action, int type, int maxEntriesToKeep)
{
super(maxEntriesToKeep);
this.action = action;
this.type = type;
}
public PerformanceTimingAggregate(PerformanceTimingAggregate copy)
{
super(copy);
this.action = copy.getAction();
this.type = copy.getType();
this.min_ms = copy.getMinTimeMS();
this.max_ms = copy.getMaxTimeMS();
this.s2 = copy.getS2();
this.count = copy.getCount();
this.xtotal_ms = copy.getTotalTimeMS();
this.total_interval_ms = copy.getTotalIntervalTimeMS();
}
public void updateTime(long interval_ms, long running_ms)
{
total_interval_ms += interval_ms;
xtotal_ms += running_ms;
min_ms = count == 0 ? running_ms : Math.min(min_ms, running_ms);
max_ms = count == 0 ? running_ms : Math.max(max_ms, running_ms);
s2 += (running_ms * running_ms);
count++;
}
public void updateSubActionTimes(Map<String, PerformanceTimingAggregate> newSubActionTimings)
{
long it = 0, rt = 0;
if (newSubActionTimings != null)
{
for (Entry<String, PerformanceTimingAggregate> newE : newSubActionTimings.entrySet())
{
PerformanceTimingAggregate newSubTime = newE.getValue();
addTiming(newE.getKey(), newSubTime.getTotalIntervalTimeMS(), newSubTime.getTotalTimeMS(), newSubTime.getType(), newSubTime.toMap());
if (newSubTime.getType() != IDataServer.METHOD_CALL_WAITING_FOR_USER_INPUT)
{
if (totalSubActionTimes == null)
{
// done here so that methods that don't call API will not create this unneeded instance
totalSubActionTimes = new PerformanceTimingAggregate(action + " - subactions", IDataServer.METHOD_CALL, getSubActionMaxEntries());
totalSubActionTimes.count = count - 1; // if only some of the calls (not first ones) call client side APIs, we still must average on all calls
}
it += newSubTime.getTotalIntervalTimeMS();
rt += newSubTime.getTotalTimeMS();
}
}
}
if (totalSubActionTimes != null)
{
totalSubActionTimes.updateTime(it, rt); // it can happen that if in one parent method execution there are no child API calls, min will become 0 - that is normal
}
}
public PerformanceTimingAggregate getTotalSubActionTimes()
{
return totalSubActionTimes;
}
public void updateTime(long total_interval_ms, long running_ms, long min_ms, long max_ms, long s2, int count)
{
this.total_interval_ms += total_interval_ms;
this.xtotal_ms += running_ms;
this.min_ms = Math.min(this.min_ms, min_ms);
this.max_ms = Math.max(this.max_ms, max_ms);
this.s2 += s2;
this.count += count;
}
public String getAction()
{
return action;
}
public int getType()
{
return type;
}
public String getTypeString()
{
return PerformanceTiming.getTypeString(type);
}
public long getAverageIntervalTimeMS()
{
if (count == 0) return total_interval_ms;
return (total_interval_ms / count);
}
public long getAverageTimeMS()
{
if (count == 0) return xtotal_ms;
return (xtotal_ms / count);
}
public long getTotalIntervalTimeMS()
{
return total_interval_ms;
}
public long getTotalTimeMS()
{
return xtotal_ms;
}
public long getMinTimeMS()
{
return min_ms;
}
public long getMaxTimeMS()
{
return max_ms;
}
public double getStandardDeviation()
{
if (count <= 1) return 0;
// see http://en.wikipedia.org/wiki/Standard_deviation for calculating standard deviation
// see http://easycalculation.com/statistics/standard-deviation.php for calculating stdev
// Population Standard deviation
// return Math.sqrt((count * s2) - (total_ms * total_ms)) / count;
// Standard deviation
return Math.sqrt((((double)((count * s2) - (xtotal_ms * xtotal_ms)))) / (count * (count - 1)));
}
public int getCount()
{
return count;
}
public long getS2()
{
return s2;
}
}