Merge pull request #87 from birarda/mixer-stats

stats refactoring via change to SimpleMovingAverage
This commit is contained in:
ZappoMan 2013-04-18 16:36:58 -07:00
commit ffe3f4995d
12 changed files with 188 additions and 256 deletions

View file

@ -93,24 +93,24 @@ long int VoxelSystem::getVoxelsCreated() {
return tree->voxelsCreated;
}
long int VoxelSystem::getVoxelsCreatedRunningAverage() {
return tree->voxelsCreatedStats.getRunningAverage();
float VoxelSystem::getVoxelsCreatedPerSecondAverage() {
return (1 / tree->voxelsCreatedStats.getEventDeltaAverage());
}
long int VoxelSystem::getVoxelsColored() {
return tree->voxelsColored;
}
long int VoxelSystem::getVoxelsColoredRunningAverage() {
return tree->voxelsColoredStats.getRunningAverage();
float VoxelSystem::getVoxelsColoredPerSecondAverage() {
return (1 / tree->voxelsColoredStats.getEventDeltaAverage());
}
long int VoxelSystem::getVoxelsBytesRead() {
return tree->voxelsBytesRead;
}
long int VoxelSystem::getVoxelsBytesReadRunningAverage() {
return tree->voxelsBytesReadStats.getRunningAverage();
float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
}

View file

@ -40,9 +40,9 @@ public:
long int getVoxelsCreated();
long int getVoxelsColored();
long int getVoxelsBytesRead();
long int getVoxelsCreatedRunningAverage();
long int getVoxelsColoredRunningAverage();
long int getVoxelsBytesReadRunningAverage();
float getVoxelsCreatedPerSecondAverage();
float getVoxelsColoredPerSecondAverage();
float getVoxelsBytesReadPerSecondAverage();
private:
int voxelsRendered;

View file

@ -74,10 +74,11 @@
#include "Oscilloscope.h"
#include "UDPSocket.h"
#include "SerialInterface.h"
#include <PerfStat.h>
#include <SharedUtil.h>
#include <PacketHeaders.h>
#include <AvatarData.h>
#include <PerfStat.h>
#include <SimpleMovingAverage.h>
#include "ViewFrustum.h"
@ -239,31 +240,29 @@ void displayStats(void)
std::stringstream voxelStats;
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedRunningAverage()
<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedPerSecondAverage()
<< "/sec) ";
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredRunningAverage()
<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredPerSecondAverage()
<< "/sec) ";
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead()
<< " (" << voxels.getVoxelsBytesReadRunningAverage() << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead()
<< " (" << voxels.getVoxelsBytesReadPerSecondAverage() << " Bps)";
drawtext(10, statsVerticalOffset + 290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
long int voxelsBytesPerColored = voxels.getVoxelsColored() ? voxels.getVoxelsBytesRead()/voxels.getVoxelsColored() : 0;
long int voxelsBytesPerColoredAvg = voxels.getVoxelsColoredRunningAverage() ?
voxels.getVoxelsBytesReadRunningAverage()/voxels.getVoxelsColoredRunningAverage() : 0;
voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored
<< " (" << voxelsBytesPerColoredAvg << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
float voxelsBytesPerColored = voxels.getVoxelsColored()
? ((float) voxels.getVoxelsBytesRead() / voxels.getVoxelsColored())
: 0;
voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored;
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
if (::perfStatsOn) {
// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups

View file

@ -37,6 +37,7 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent
activeSocket = NULL;
linkedData = NULL;
_bytesReceivedMovingAverage = NULL;
deleteMutex = new pthread_mutex_t;
pthread_mutex_init(deleteMutex, NULL);
@ -69,6 +70,13 @@ Agent::Agent(const Agent &otherAgent) {
linkedData = NULL;
}
if (otherAgent._bytesReceivedMovingAverage != NULL) {
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
memcpy(_bytesReceivedMovingAverage, otherAgent._bytesReceivedMovingAverage, sizeof(SimpleMovingAverage));
} else {
_bytesReceivedMovingAverage = NULL;
}
deleteMutex = new pthread_mutex_t;
pthread_mutex_init(deleteMutex, NULL);
}
@ -89,6 +97,7 @@ void Agent::swap(Agent &first, Agent &second) {
swap(first.agentId, second.agentId);
swap(first.firstRecvTimeUsecs, second.firstRecvTimeUsecs);
swap(first.lastRecvTimeUsecs, second.lastRecvTimeUsecs);
swap(first._bytesReceivedMovingAverage, second._bytesReceivedMovingAverage);
swap(first.deleteMutex, second.deleteMutex);
}
@ -99,6 +108,7 @@ Agent::~Agent() {
delete publicSocket;
delete localSocket;
delete linkedData;
delete _bytesReceivedMovingAverage;
}
char Agent::getType() const {
@ -199,7 +209,6 @@ void Agent::setLinkedData(AgentData *newData) {
linkedData = newData;
}
bool Agent::operator==(const Agent& otherAgent) {
return matches(otherAgent.publicSocket, otherAgent.localSocket, otherAgent.type);
}
@ -211,6 +220,31 @@ bool Agent::matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, cha
&& socketMatch(localSocket, otherLocalSocket);
}
void Agent::recordBytesReceived(int bytesReceived) {
if (_bytesReceivedMovingAverage == NULL) {
printf("Setting up the moving average for agent\n");
_bytesReceivedMovingAverage = new SimpleMovingAverage(100);
}
_bytesReceivedMovingAverage->updateAverage((float) bytesReceived);
}
float Agent::getAveragePacketsPerSecond() {
if (_bytesReceivedMovingAverage != NULL) {
return (1 / _bytesReceivedMovingAverage->getEventDeltaAverage());
} else {
return 0;
}
}
float Agent::getAverageKilobitsPerSecond() {
if (_bytesReceivedMovingAverage != NULL) {
return (_bytesReceivedMovingAverage->getAverageSampleValuePerSecond() * (8.0f / 1000));
} else {
return 0;
}
}
void Agent::printLog(Agent const& agent) {
sockaddr_in *agentPublicSocket = (sockaddr_in *) agent.publicSocket;

View file

@ -11,7 +11,6 @@
#include <stdint.h>
#include <ostream>
#include "AgentData.h"
#ifdef _WIN32
#include "Syssocket.h"
@ -19,6 +18,9 @@
#include <sys/socket.h>
#endif
#include "SimpleMovingAverage.h"
#include "AgentData.h"
class Agent {
public:
Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId);
@ -34,32 +36,45 @@ public:
char getType() const;
const char* getTypeName() const;
void setType(char newType);
uint16_t getAgentId();
void setAgentId(uint16_t thisAgentId);
double getFirstRecvTimeUsecs();
void setFirstRecvTimeUsecs(double newTimeUsecs);
double getLastRecvTimeUsecs();
void setLastRecvTimeUsecs(double newTimeUsecs);
sockaddr* getPublicSocket();
void setPublicSocket(sockaddr *newSocket);
sockaddr* getLocalSocket();
void setLocalSocket(sockaddr *newSocket);
sockaddr* getActiveSocket();
void activatePublicSocket();
void activateLocalSocket();
AgentData* getLinkedData();
void setLinkedData(AgentData *newData);
void recordBytesReceived(int bytesReceived);
float getAverageKilobitsPerSecond();
float getAveragePacketsPerSecond();
static void printLog(Agent const&);
friend std::ostream& operator<<(std::ostream& os, const Agent* agent);
private:
void swap(Agent &first, Agent &second);
sockaddr *publicSocket, *localSocket, *activeSocket;
char type;
uint16_t agentId;
double firstRecvTimeUsecs;
double lastRecvTimeUsecs;
AgentData *linkedData;
SimpleMovingAverage* _bytesReceivedMovingAverage;
AgentData* linkedData;
};
std::ostream& operator<<(std::ostream& os, const Agent* agent);

View file

@ -108,6 +108,7 @@ void AgentList::processBulkAgentData(sockaddr *senderAddress, unsigned char *pac
if (bulkSendAgentIndex >= 0) {
Agent *bulkSendAgent = &agents[bulkSendAgentIndex];
bulkSendAgent->setLastRecvTimeUsecs(usecTimestampNow());
bulkSendAgent->recordBytesReceived(numTotalBytes);
}
unsigned char *startPosition = packetData;
@ -144,6 +145,7 @@ void AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *pack
void AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) {
agent->setLastRecvTimeUsecs(usecTimestampNow());
agent->recordBytesReceived(dataBytes);
if (agent->getLinkedData() == NULL) {
if (linkedDataCreateCallback != NULL) {

View file

@ -1,142 +0,0 @@
//
// CounterStats.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 2013/04/08.
//
// Poor-man's counter stats collector class. Useful for collecting running averages
// and other stats for countable things.
//
//
#include "CounterStats.h"
#include <cstdio>
#ifdef _WIN32
#include "Systime.h"
#else
#include <sys/time.h>
#endif
#include <string>
#include <map>
#include "shared_Log.h"
//private:
// long int currentCount;
// long int currentDelta;
// double currentTime;
// double totalTime;
//
// long int countSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
// long int deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
// double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
// int sampleAt;
CounterStatHistory::CounterStatHistory() :
currentCount(0),
currentDelta(0),
currentTime(0.0),
lastCount(0),
lastTime(0.0),
totalTime(0.0),
sampleAt(-1),
sampleCount(0) {
}
CounterStatHistory::CounterStatHistory(std::string myName) :
name(myName),
currentCount(0),
currentDelta(0),
currentTime(0.0),
lastCount(0),
lastTime(0.0),
totalTime(0.0),
sampleAt(-1),
sampleCount(0) {
}
CounterStatHistory::CounterStatHistory(std::string myName, double initialTime, long initialCount) :
name(myName),
currentCount(initialCount),
currentDelta(0),
currentTime(initialTime),
lastCount(initialCount),
lastTime(initialTime),
totalTime(initialTime),
sampleAt(-1),
sampleCount(0) {
}
void CounterStatHistory::init() {
currentCount = 0;
currentDelta = 0;
currentTime = 0.0;
lastCount = 0;
lastTime = 0.0;
totalTime = 0.0;
sampleAt = -1;
sampleCount = 0;
}
void CounterStatHistory::recordSample(long thisCount) {
timeval now;
gettimeofday(&now,NULL);
double nowSeconds = (now.tv_usec/1000000.0)+(now.tv_sec);
this->recordSample(nowSeconds,thisCount);
}
void CounterStatHistory::recordSample(double thisTime, long thisCount) {
// how much did we change since last sample?
long thisDelta = thisCount - this->lastCount;
double elapsed = thisTime - this->lastTime;
// record the latest values
this->currentCount = thisCount;
this->currentTime = thisTime;
this->currentDelta = thisDelta;
//printLog("CounterStatHistory[%s]::recordSample(thisTime %lf, thisCount= %ld)\n",this->name.c_str(),thisTime,thisCount);
// if more than 1/10th of a second has passed, then record
// things in our rolling history
if (elapsed > 0.1) {
this->lastTime = thisTime;
this->lastCount = thisCount;
// record it in our history...
this->sampleAt = (this->sampleAt+1)%COUNTETSTATS_SAMPLES_TO_KEEP;
if (this->sampleCount<COUNTETSTATS_SAMPLES_TO_KEEP) {
this->sampleCount++;
}
this->countSamples[this->sampleAt]=thisCount;
this->timeSamples[this->sampleAt]=thisTime;
this->deltaSamples[this->sampleAt]=thisDelta;
//printLog("CounterStatHistory[%s]::recordSample() ACTUALLY RECORDING IT sampleAt=%d thisTime %lf, thisCount= %ld)\n",this->name.c_str(),this->sampleAt,thisTime,thisCount);
}
}
long CounterStatHistory::getRunningAverage() {
// before we calculate our running average, always "reset" the current count, with the current time
// this will flush out old data, if we haven't been adding any new data.
this->recordSample(this->currentCount);
long runningTotal = 0;
double minTime = this->timeSamples[0];
double maxTime = this->timeSamples[0];
for (int i =0; i < this->sampleCount; i++) {
minTime = std::min(minTime,this->timeSamples[i]);
maxTime = std::max(maxTime,this->timeSamples[i]);
runningTotal += this->deltaSamples[i];
}
double elapsedTime = maxTime-minTime;
long runningAverage = runningTotal/elapsedTime;
return runningAverage;
}

View file

@ -1,65 +0,0 @@
//
// CounterStats.h
// hifi
//
// Created by Brad Hefta-Gaub on 3/29/13.
//
// Poor-man's counter stats collector class. Useful for collecting running averages
// and other stats for countable things.
//
//
#ifndef __hifi__CounterStats__
#define __hifi__CounterStats__
#include <cstring>
#include <string>
#include <map>
// TIME_FRAME should be SAMPLES_TO_KEEP * TIME_BETWEEN_SAMPLES
#define COUNTETSTATS_SAMPLES_TO_KEEP 50
#define COUNTETSTATS_TIME_BETWEEN_SAMPLES 0.1
#define COUNTETSTATS_TIME_FRAME (COUNTETSTATS_SAMPLES_TO_KEEP*COUNTETSTATS_TIME_BETWEEN_SAMPLES)
class CounterStatHistory {
public:
std::string name;
CounterStatHistory();
CounterStatHistory(std::string myName);
CounterStatHistory(std::string myName, double initialTime, long initialCount);
void recordSample(long thisCount);
void recordSample(double thisTime, long thisCount);
long getRunningAverage();
long getAverage() {
return currentCount/totalTime;
};
double getTotalTime() {
return totalTime;
};
long getCount() {
return currentCount;
};
private:
void init();
long currentCount;
long currentDelta;
double currentTime;
long lastCount;
double lastTime;
double totalTime;
long countSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
long deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
int sampleAt;
int sampleCount;
};
#endif /* defined(__hifi__CounterStat__) */

View file

@ -0,0 +1,54 @@
//
// SimpleMovingAverage.cpp
// hifi
//
// Created by Stephen Birarda on 4/18/13.
//
//
#include "SharedUtil.h"
#include "SimpleMovingAverage.h"
SimpleMovingAverage::SimpleMovingAverage(int numSamplesToAverage) :
_numSamples(0),
_average(0),
_eventDeltaAverage(0),
WEIGHTING(1.0f / numSamplesToAverage),
ONE_MINUS_WEIGHTING(1 - WEIGHTING) {
}
int SimpleMovingAverage::updateAverage(float sample) {
if (_numSamples > 0) {
_average = (ONE_MINUS_WEIGHTING * _average) + (WEIGHTING * sample);
float eventDelta = (usecTimestampNow() - _lastEventTimestamp) / 1000000;
if (_numSamples > 1) {
_eventDeltaAverage = (ONE_MINUS_WEIGHTING * _eventDeltaAverage) +
(WEIGHTING * eventDelta);
} else {
_eventDeltaAverage = eventDelta;
}
} else {
_average = sample;
_eventDeltaAverage = 0;
}
_lastEventTimestamp = usecTimestampNow();
return ++_numSamples;
}
void SimpleMovingAverage::reset() {
_numSamples = 0;
}
float SimpleMovingAverage::getEventDeltaAverage() {
return (ONE_MINUS_WEIGHTING * _eventDeltaAverage) +
(WEIGHTING * ((usecTimestampNow() - _lastEventTimestamp) / 1000000));
}
float SimpleMovingAverage::getAverageSampleValuePerSecond() {
return _average * (1 / getEventDeltaAverage());
}

View file

@ -0,0 +1,36 @@
//
// SimpleMovingAverage.h
// hifi
//
// Created by Stephen Birarda on 4/18/13.
// Replaces Brad Hefta-Gaub's CounterStats class (RIP)
//
//
#ifndef __hifi__Stats__
#define __hifi__Stats__
#include <iostream>
class SimpleMovingAverage {
public:
SimpleMovingAverage(int numSamplesToAverage);
int updateAverage(float sample);
void reset();
int getSampleCount() { return _numSamples; };
float getAverage() { return _average; };
float getEventDeltaAverage();
float getAverageSampleValuePerSecond();
private:
int _numSamples;
double _lastEventTimestamp;
float _average;
float _eventDeltaAverage;
const float WEIGHTING;
const float ONE_MINUS_WEIGHTING;
};
#endif /* defined(__hifi__Stats__) */

View file

@ -15,7 +15,6 @@
#include "SharedUtil.h"
#include "voxels_Log.h"
#include "PacketHeaders.h"
#include "CounterStats.h"
#include "OctalCode.h"
#include "VoxelTree.h"
#include <fstream> // to load voxels from file
@ -46,19 +45,17 @@ int boundaryDistanceForRenderLevel(unsigned int renderLevel) {
}
}
VoxelTree::VoxelTree() {
VoxelTree::VoxelTree() :
voxelsCreated(0),
voxelsColored(0),
voxelsBytesRead(0),
voxelsCreatedStats(100),
voxelsColoredStats(100),
voxelsBytesReadStats(100) {
rootNode = new VoxelNode();
rootNode->octalCode = new unsigned char[1];
*rootNode->octalCode = 0;
// Some stats tracking
this->voxelsCreated = 0; // when a voxel is created in the tree (object new'd)
this->voxelsColored = 0; // when a voxel is colored/set in the tree (object may have already existed)
this->voxelsBytesRead = 0;
voxelsCreatedStats.name = "voxelsCreated";
voxelsColoredStats.name = "voxelsColored";
voxelsBytesReadStats.name = "voxelsBytesRead";
}
VoxelTree::~VoxelTree() {
@ -126,14 +123,14 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode,
if (destinationNode->children[i] == NULL) {
destinationNode->addChildAtIndex(i);
this->voxelsCreated++;
this->voxelsCreatedStats.recordSample(this->voxelsCreated);
this->voxelsCreatedStats.updateAverage(1);
}
// pull the color for this child
memcpy(destinationNode->children[i]->color, nodeData + bytesRead, 3);
destinationNode->children[i]->color[3] = 1;
this->voxelsColored++;
this->voxelsColoredStats.recordSample(this->voxelsColored);
this->voxelsColoredStats.updateAverage(1);
bytesRead += 3;
}
@ -156,7 +153,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode,
// add a child at that index, if it doesn't exist
destinationNode->addChildAtIndex(childIndex);
this->voxelsCreated++;
this->voxelsCreatedStats.recordSample(this->voxelsCreated);
this->voxelsCreatedStats.updateAverage(this->voxelsCreated);
}
// tell the child to read the subsequent data
@ -184,7 +181,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt
readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes);
this->voxelsBytesRead += bufferSizeBytes;
this->voxelsBytesReadStats.recordSample(this->voxelsBytesRead);
this->voxelsBytesReadStats.updateAverage(bufferSizeBytes);
}
// Note: uses the codeColorBuffer format, but the color's are ignored, because

View file

@ -9,7 +9,7 @@
#ifndef __hifi__VoxelTree__
#define __hifi__VoxelTree__
#include "CounterStats.h"
#include "SimpleMovingAverage.h"
#include "VoxelNode.h"
#include "MarkerNode.h"
@ -20,13 +20,15 @@ const int TREE_SCALE = 10;
class VoxelTree {
public:
// when a voxel is created in the tree (object new'd)
long voxelsCreated;
// when a voxel is colored/set in the tree (object may have already existed)
long voxelsColored;
long voxelsBytesRead;
CounterStatHistory voxelsCreatedStats;
CounterStatHistory voxelsColoredStats;
CounterStatHistory voxelsBytesReadStats;
SimpleMovingAverage voxelsCreatedStats;
SimpleMovingAverage voxelsColoredStats;
SimpleMovingAverage voxelsBytesReadStats;
VoxelTree();
~VoxelTree();