Official eMule-Board: Accurate Upload Datarate Measurement - Official eMule-Board

Jump to content


Page 1 of 1

Accurate Upload Datarate Measurement From Ottavio84 idea

#1 User is offline   BadWolf63 

  • Premium Member
  • PipPipPipPipPip
  • Group: Members
  • Posts: 261
  • Joined: 11-November 02

Posted 16 February 2003 - 10:29 AM

in Otherstructs.h add
// enkeyDEV(Ottavio84) - Accurate speed measurement-
struct TransferredData {
	uint32	datalen;
	uint32	timestamp;


then change in uploadqueue.h
	CList<int,int> avarage_dr_list;

in
	CList<TransferredData,TransferredData> avarage_dr_list;


in updownclient.h
CList<TransferredData,TransferredData>    m_AvarageUDR_list;
	uint32	sendtimestamp;


in UploadQueue.cpp
add to CUploadQueue::CUploadQueue(CPreferences* in_prefs)
	//patch by BadWolf
	TransferredData newitem = {0,::GetTickCount()};
	for (int i = 0;i != 400;i++)
  avarage_dr_list.AddHead(newitem);

and
void CUploadQueue::Process(){
	// Patch by BadWolf (on an EnkeyDEV(Ottavio84) idea)
	TransferredData newitem = {theApp.stat_sessionSentBytes, ::GetTickCount()};
	avarage_dr_list.RemoveHead();
	avarage_dr_list.AddTail(newitem);
	float deltat = (float)(avarage_dr_list.GetTail().timestamp - avarage_dr_list.GetHead().timestamp) / 1000.0;
	if (deltat > 0.0) 
        datarate = (uint32)((float)(avarage_dr_list.GetTail().datalen - avarage_dr_list.GetHead().datalen) / deltat);
	else
  datarate = 0;

	dataratems = 0;
	if (AcceptNewClient() && waitinglist.GetCount())
  AddUpNextClient();
	if (!uploadinglist.GetCount())
  return;

	int16 clientsrdy = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
  CUpDownClient* cur_client = uploadinglist.GetAt(pos);
  if ( (cur_client->socket) && (!cur_client->socket->IsBusy()) && cur_client->HasBlocks())
  	clientsrdy++;
	}
	if (!clientsrdy){
  estadatarate -= 200;
  if (estadatarate < 100)
  	estadatarate = 100;
  clientsrdy++;
	}
	else{

  int timediff = GetTickCount() - sendtimestamp;
  sendtimestamp = GetTickCount();
  estadatarate += 200;
  int maxrate = app_prefs->GetMaxUpload()*112; // why 112?? experimental 
  if (estadatarate > maxrate)
  	estadatarate = maxrate;
	}
	uint32 sendperclient = estadatarate/clientsrdy;
	for (POSITION pos = uploadinglist.GetHeadPosition(); pos; )
  dataratems += uploadinglist.GetNext(pos)->SendBlockData(sendperclient);
};


in Uploadclient.cpp substitute

uint32 CUpDownClient::SendBlockData(uint32 nMaxAmmount){ // By Maella
	TransferredData newitem = {dataratems,::GetTickCount()};
	m_AvarageUDR_list.AddTail(newitem);
	sumavguprate += dataratems;
	if (m_AvarageUDR_list.GetCount() > 500)
  sumavguprate -= m_AvarageUDR_list.RemoveHead().datalen;
	if(m_AvarageUDR_list.GetCount() > 10)
  m_nUpDatarate = sumavguprate /((m_AvarageUDR_list.GetTail().timestamp - m_AvarageUDR_list.GetHead().timestamp)/1000);
	else
  m_nUpDatarate = 0;

	// Refresh GUI
	m_cSendblock++;
	if (m_cSendblock == 30){
  m_cSendblock = 0;
  theApp.emuledlg->transferwnd.uploadlistctrl.RefreshClient(this);
	}

	dataratems = 0;
	uint32 timesend = ::GetTickCount();
	// Send Block
	if (socket && !socket->IsBusy()){  
  if (m_BlockSend_queue.IsEmpty()){
  	if (!CreateNextBlockPackage())
    return 0;
  }
  
  // Splitting packets if necessary
  // Remark: - don't use 2*MAXFRAGSIZE (see CEMSocket::Send()), otherwise the 
  //           counter m_nMaxSendAllowed will trigged the sending of two TCP packets
  //           of 1300 (2*1300) at the same time => increase the ping of the application.
  //         - should be moved to CreateNextBlockPackage()
  if (m_BlockSend_queue.GetHead()->GetRealPacketSize() > 0 &&
  m_BlockSend_queue.GetHead()->GetRealPacketSize() > MAXFRAGSIZE){ 
   
  	uint32 nSize = m_BlockSend_queue.GetHead()->GetRealPacketSize();
  	const char* pBuffer = m_BlockSend_queue.GetHead()->DetachPacket();
  	delete m_BlockSend_queue.RemoveHead();
     
  	uint32 nPos = nSize;
  	bool bLast = true;
  	while (nPos){
    uint32 nNewSize = (nPos < MAXFRAGSIZE) ? nPos : MAXFRAGSIZE;
    nPos -= nNewSize;
    char* pBuffer2 = new char[nNewSize];
    memcpy(pBuffer2,pBuffer+nPos,nNewSize);
    m_BlockSend_queue.AddHead(new Packet(pBuffer2,nNewSize,bLast));
    bLast = false;
  	}
  	delete[] pBuffer;
  }
  
  // Send packet(s)
  m_nMaxSendAllowed += nMaxAmmount;
  while (!socket->IsBusy() &&
   !m_BlockSend_queue.IsEmpty() &&
   m_BlockSend_queue.GetHead()->GetRealPacketSize() <= m_nMaxSendAllowed){
   
  	Packet* tosend = m_BlockSend_queue.RemoveHead();
  	uint32 nBlockSize = tosend->GetRealPacketSize();
  	m_nMaxSendAllowed -= nBlockSize;
  	dataratems += nBlockSize;
  	// theApp.uploadqueue->AddUpDataOverheadOther(0, 24);
  	socket->SendPacket(tosend, true, false);
     
  	if (m_BlockSend_queue.IsEmpty())
    CreateNextBlockPackage();
  }

  // Update credits
  m_nTransferedUp += dataratems;
  theApp.UpdateSentBytes(dataratems);
  credits->AddUploaded(dataratems);
  // Return the real size of sent packet(s) => true bandwidth (it means less wrong here)
  return dataratems;
	}
	return 0;
}


then to fix the stats:
in statisticsDlg.h
	list<TransferredData> uprateHistory;


in statisticsdlg.cpp
void CStatisticsDlg::RecordRate() {
	
	if (theApp.stat_transferStarttime==0) return;

	// every second
	TransferredData newitem = {theApp.stat_sessionSentBytes, ::GetTickCount()};
	downrateHistory.push_front(theApp.stat_sessionReceivedBytes);
	uprateHistory.push_front(newitem);
	
	// limit to maxmins 
	while ((int)downrateHistory.size()>(int)( theApp.glob_prefs->GetStatsAverageMinutes()*60)) downrateHistory.pop_back();
	while ((float)(uprateHistory.front().timestamp - uprateHistory.back().timestamp) / 1000.0>(int)( theApp.glob_prefs->GetStatsAverageMinutes()*60)) uprateHistory.pop_back();
}


and
float CStatisticsDlg::GetAvgUploadRate(int averageType) {
	if (averageType==AVG_SESSION) {
  if (theApp.stat_transferStarttime==0) return 0;

  float running=(GetTickCount()-theApp.stat_transferStarttime)/1000;
  if (running<5) return 0;

  return (float)(theApp.stat_sessionSentBytes/1024) / running;
	} else  {
  if (uprateHistory.size()==0) return 0;
  float deltat = (float)(uprateHistory.front().timestamp - uprateHistory.back().timestamp) / 1000.0;
  if (deltat > 0.0) 
  	return (float)((float)(uprateHistory.front().datalen-uprateHistory.back().datalen) / deltat)/1024;
  else
  	return 0;
	}

}


BadWolf

This post has been edited by BadWolf63: 16 February 2003 - 11:55 AM

0

#2 User is offline   zz 

  • -
  • PipPipPipPipPipPipPip
  • Group: Debugger
  • Posts: 2014
  • Joined: 30-November 02

Posted 21 February 2003 - 11:40 PM

I calculated the average speed like below instead. I think it is more precise, due to less rounding errors. There might be potential for overflow if the transfer rate is very high, though:

transferRate = ((transferedAmountTail-transferedAmountHead)*1000)/(timestamptail-timestamphead)


Would this be a better method?

As for the list with values, there should be no need to fill it with 400 empty values at start. Just let it be empty.

To keep it in size it would be better to do a loop, where the head-value is removed if it is older than a certain time (40 seconds to be the same as official eMule, 400/10 = 40):

while(currentTime-timestampTail > 40*1000) {
  remove tailValue;
}


This also has the advantage that you don't have to call it ten times a second. I have optimized it so that it is only calculated when it is actually displayed on screen (about once a second).

What do you think?

There's more places where transferrates are calculated. For each download and upload slot, overhead ul/dl, session ul/dl. Have I forgotten any?

For my take on this kind of more accurate measuring, you can check out my ZZUL patch at:

http://www.lava.se/emule/dynamicul/

I'd really like to have this kind of measuring included in the official eMule. Is anyone working on it?

/zz B)
ZZUL - get control of your uploads: ZZUL Forum
0

#3 User is offline   BadWolf63 

  • Premium Member
  • PipPipPipPipPip
  • Group: Members
  • Posts: 261
  • Joined: 11-November 02

Posted 22 February 2003 - 01:25 AM

you're right... i've optimized the routine after the post now it is:

void CUploadQueue::Process()
{
  // Patch by BadWolf (on an EnkeyDEV(Ottavio84) idea)

  TransferredData newitem = {theApp.stat_sessionSentBytes, ::GetTickCount()};
	avarage_dr_list.AddTail(newitem);
	if (avarage_dr_list.GetCount() > 400)
  avarage_dr_list.RemoveHead();
	float deltat = (float)(avarage_dr_list.GetTail().timestamp - avarage_dr_list.GetHead().timestamp) / 1000.0;
	if (deltat > 0.0) 
  datarate = (uint32)((float)(avarage_dr_list.GetTail().datalen - avarage_dr_list.GetHead().datalen) / deltat);
	else
  datarate = 0;
	// END Patch by BadWolf (on an EnkeyDEV(Ottavio84) idea)


with no filling at the start.

other places where transfer rates are calculated are:

CUpDownClient::SendBlockData, upload and download overhead calculation and both upload and download 5mins statistics in StatisticDlg.

i'm trying a little trick for calling SendBlockData in UploadQueue:Process that could keep low the upload slot number:

  //By BadWolf
  estadatarate += 200;
  int maxrate = app_prefs->GetMaxUpload() * 112; // 112??? Don't ask me why! Experimental 
  bDataRateMaxed = false; // Added by Tarod [LoneStar]
  if (theApp.glob_prefs->GetMaxUpload() != UNLIMITED){
  	estadatarate = maxrate;
  	if ((int)datarate > theApp.glob_prefs->GetMaxUpload()*1024)
    sendperclient = 10;
  	else
    sendperclient = estadatarate;

  }
	}
	for (POSITION pos = uploadinglist.GetHeadPosition(); pos; ) // By Ichi
  dataratems += uploadinglist.GetNext(pos)->SendBlockData(sendperclient);

Trying to send the whole bandwidth to every slot filling their download limit

my first idea was different:
estadatarate = app_prefs->GetMaxUpload() * 1024;
for (POSITION pos = uploadinglist.GetHeadPosition(); pos; ) // By Ichi
 dataratems += uploadinglist.GetNext(pos)->SendBlockData((estadatarate - dataratems)/10);

but it doesn't work.

BadWolf

This post has been edited by BadWolf63: 22 February 2003 - 01:35 AM

0

#4 User is offline   zz 

  • -
  • PipPipPipPipPipPipPip
  • Group: Debugger
  • Posts: 2014
  • Joined: 30-November 02

Posted 22 February 2003 - 02:15 AM

Good. :)

But what about the calc without floats and the change of the list limiter to being time based instead of size based?

/zz B)
ZZUL - get control of your uploads: ZZUL Forum
0

#5 User is offline   Maella 

  • Magnificent Member
  • PipPipPipPipPipPip
  • Group: Members
  • Posts: 410
  • Joined: 27-December 02

Posted 22 February 2003 - 09:35 AM

Hi,

Two ideas:

The computing of the datarate could me moved out from the xyz::Process() methods and called only 1 time per second. It's enough because these values are only used for the GUI.

For the history lists for the statistic, both upload/download rate could be merged in one unique structure.

struct blablabla{
uint32 dataSent,
uint32 dataReceived,
DWORD timeStamp};

Maella
0

#6 User is offline   BadWolf63 

  • Premium Member
  • PipPipPipPipPip
  • Group: Members
  • Posts: 261
  • Joined: 11-November 02

Posted 22 February 2003 - 09:56 AM

@Maella

Well... the computing of output datarate is needed for the acceptnewclient... don't know if only 1 time a sec could be sufficent.

for the second one i'll let it to the C coders... i've been coding with VB for 10 years, but all i know about C is what i learned reading eMule code in the last 4 months' spare time

BadWolf
0

#7 User is offline   Maella 

  • Magnificent Member
  • PipPipPipPipPipPip
  • Group: Members
  • Posts: 410
  • Joined: 27-December 02

Posted 22 February 2003 - 10:08 AM

@BadWolf63

Since v0.27b the acceptnewclient() includes a internal 'timing' guad of one second. A new client can not be added more than each second.

The purpose of the second point is only to spare the management of a second 'history list'. It's not a big change.

Maella
0

#8 User is offline   Sub7 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 84
  • Joined: 12-December 02

Posted 22 February 2003 - 01:17 PM

zz, on Feb 21 2003, 11:40 PM, said:

transferRate = ((transferedAmountTail-transferedAmountHead)*[B]1000[/B])/(timestamptail-timestamphead)


while(currentTime-timestampTail > 40*[B]1000[/B]) {
  remove tailValue;
}

hmmm...
*1000

i am no coder so i don't know what you want to do (but i like reading this forum *g*)...

is this 1000 because 1000 bytes are 1kb?
than i have to tell you that you are wrong! 1kb is 1024b....
1024b = 1kb
1024kb = 1mb
1024mb = 1gb
...

This post has been edited by Sub7: 22 February 2003 - 01:18 PM

0

#9 User is offline   BadWolf63 

  • Premium Member
  • PipPipPipPipPip
  • Group: Members
  • Posts: 261
  • Joined: 11-November 02

Posted 22 February 2003 - 05:25 PM

Sub7, on Feb 22 2003, 02:17 PM, said:

i am no coder so i don't know what you want to do (but i like reading this forum *g*)...

nope... it's time in 1/1000 of seconds. So if you want seconds you've to divide per 1000
for a better comprehention it should be:

transferRate = ((transferedAmountTail-transferedAmountHead) / ((timestamptail-timestamphead)/1000)


BadWolf

This post has been edited by BadWolf63: 22 February 2003 - 05:43 PM

0

#10 User is offline   zz 

  • -
  • PipPipPipPipPipPipPip
  • Group: Debugger
  • Posts: 2014
  • Joined: 30-November 02

Posted 22 February 2003 - 07:38 PM

BadWolf63, on Feb 22 2003, 06:25 PM, said:

it's time in 1/1000 of seconds. So if you want seconds you've to divide per 1000
for a better comprehention it should be:

transferRate = ((transferedAmountTail-transferedAmountHead) / ((timestamptail-timestamphead)/1000)

But that would of course give severe rounding errors. It's an integer calculation.

/zz B)
ZZUL - get control of your uploads: ZZUL Forum
0

  • Member Options

Page 1 of 1

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users