diff --git a/libretroshare/src/retroshare/rsturtle.h b/libretroshare/src/retroshare/rsturtle.h index ebe3a9b1f..aaec76851 100644 --- a/libretroshare/src/retroshare/rsturtle.h +++ b/libretroshare/src/retroshare/rsturtle.h @@ -58,6 +58,18 @@ struct TurtleRequestDisplayInfo uint32_t depth ; // Depth of the request. Might be altered. }; +class TurtleTrafficStatisticsInfo +{ + public: + float unknown_updn_Bps ; // unknown data transit bitrate (in Bytes per sec.) + float data_up_Bps ; // upload (in Bytes per sec.) + float data_dn_Bps ; // download (in Bytes per sec.) + float tr_up_Bps ; // tunnel requests upload bitrate (in Bytes per sec.) + float tr_dn_Bps ; // tunnel requests dnload bitrate (in Bytes per sec.) + float total_up_Bps ; // turtle network management bitrate (in Bytes per sec.) + float total_dn_Bps ; // turtle network management bitrate (in Bytes per sec.) +}; + // Interface class for turtle hopping. // // This class mainly interacts with the turtle router, that is responsible @@ -100,9 +112,14 @@ class RsTurtle virtual void stopMonitoringFileTunnels(const std::string& file_hash) = 0 ; // Get info from the turtle router. I use std strings to hide the internal structs. + // virtual void getInfo(std::vector >&,std::vector >&, std::vector&,std::vector&) const = 0; + // Get info about turtle traffic. See TurtleTrafficStatisticsInfo members for details. + // + virtual void getTrafficStatistics(TurtleTrafficStatisticsInfo& info) const = 0; + // Convenience function. virtual bool isTurtlePeer(const std::string& peer_id) const = 0 ; diff --git a/libretroshare/src/turtle/p3turtle.cc b/libretroshare/src/turtle/p3turtle.cc index 159ba3fda..ec7210724 100644 --- a/libretroshare/src/turtle/p3turtle.cc +++ b/libretroshare/src/turtle/p3turtle.cc @@ -102,6 +102,8 @@ p3turtle::p3turtle(p3ConnectMgr *cm,ftServer *fs) _last_tunnel_management_time = 0 ; _last_tunnel_campaign_time = 0 ; _last_tunnel_speed_estimate_time = 0 ; + + _traffic_info.reset() ; } int p3turtle::tick() @@ -139,8 +141,15 @@ int p3turtle::tick() #endif manageTunnels() ; - RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ - _last_tunnel_management_time = now ; + { + RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + _last_tunnel_management_time = now ; + + // update traffic statistics + + _traffic_info = _traffic_info*0.75 + _traffic_info_buffer*0.25 ; + _traffic_info_buffer.reset() ; + } } // Clean every 10 sec. @@ -880,7 +889,7 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) if(item->shouldStampTunnel()) tunnel.time_stamp = time(NULL) ; - tunnel.transfered_bytes += item->serial_size() ; + tunnel.transfered_bytes += static_cast(item)->serial_size() ; // Let's figure out whether this packet is for us or not. @@ -891,6 +900,8 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) #endif item->PeerId(tunnel.local_src) ; + _traffic_info_buffer.unknown_updn_Bps += static_cast(item)->serial_size() ; + sendItem(item) ; return ; } @@ -902,6 +913,8 @@ void p3turtle::routeGenericTunnelItem(RsTurtleGenericTunnelItem *item) #endif item->PeerId(tunnel.local_dst) ; + _traffic_info_buffer.unknown_updn_Bps += static_cast(item)->serial_size() ; + sendItem(item) ; return ; } @@ -1000,6 +1013,8 @@ void p3turtle::handleRecvFileData(RsTurtleFileDataItem *item) { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + _traffic_info_buffer.data_dn_Bps += static_cast(item)->serial_size() ; + std::map::iterator it2(_local_tunnels.find(item->tunnel_id)) ; if(it2 == _local_tunnels.end()) @@ -1251,7 +1266,7 @@ void p3turtle::sendFileData(const std::string& peerId, const std::string& , uint item->chunk_size = chunksize ; item->chunk_data = malloc(chunksize) ; - tunnel.transfered_bytes += item->serial_size(); + tunnel.transfered_bytes += static_cast(item)->serial_size(); if(item->chunk_data == NULL) { @@ -1265,6 +1280,8 @@ void p3turtle::sendFileData(const std::string& peerId, const std::string& , uint #ifdef P3TURTLE_DEBUG std::cerr << "p3turtle: sending file data (chunksize=" << item->chunk_size << ", offset=" << item->chunk_offset << ", hash=0x" << hash << ") through tunnel " << (void*)item->tunnel_id << ", next peer=" << tunnel.local_src << std::endl ; #endif + _traffic_info_buffer.data_up_Bps += static_cast(item)->serial_size() ; + sendItem(item) ; } @@ -1524,6 +1541,8 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item) { RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + _traffic_info_buffer.tr_dn_Bps += static_cast(item)->serial_size() ; + std::map::iterator it = _tunnel_requests_origins.find(item->request_id) ; if(it != _tunnel_requests_origins.end()) @@ -1606,6 +1625,8 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item) res_item->tunnel_id = item->partial_tunnel_id ^ generatePersonalFilePrint(item->file_hash,false) ; res_item->PeerId(item->PeerId()) ; + _traffic_info_buffer.tr_up_Bps += static_cast(res_item)->serial_size() ; + sendItem(res_item) ; // Note in the tunnels list that we have an ending tunnel here. @@ -1660,6 +1681,11 @@ void p3turtle::handleTunnelRequest(RsTurtleOpenTunnelItem *item) ++(fwd_item->depth) ; // increase tunnel depth fwd_item->PeerId(*it) ; + { + RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + _traffic_info_buffer.tr_up_Bps += static_cast(fwd_item)->serial_size() ; + } + sendItem(fwd_item) ; } } @@ -2038,6 +2064,12 @@ static std::string printNumber(uint64_t num,bool hex=false) } } +void p3turtle::getTrafficStatistics(TurtleTrafficStatisticsInfo& info) const +{ + RsStackMutex stack(mTurtleMtx); /********** STACK LOCKED MTX ******/ + info = _traffic_info ; +} + void p3turtle::getInfo( std::vector >& hashes_info, std::vector >& tunnels_info, std::vector& search_reqs_info, diff --git a/libretroshare/src/turtle/p3turtle.h b/libretroshare/src/turtle/p3turtle.h index e31e561fe..f814e6150 100644 --- a/libretroshare/src/turtle/p3turtle.h +++ b/libretroshare/src/turtle/p3turtle.h @@ -148,6 +148,7 @@ #include "ft/ftsearch.h" #include "retroshare/rsturtle.h" #include "rsturtleitem.h" +#include "turtlestatistics.h" //#define TUNNEL_STATISTICS @@ -247,6 +248,8 @@ class p3turtle: public p3Service, /*public pqiMonitor,*/ public RsTurtle,/* publ std::vector&, std::vector&) const ; + virtual void getTrafficStatistics(TurtleTrafficStatisticsInfo& info) const ; + #ifdef TO_REMOVE /************* from pqiMonitor *******************/ /// Informs the turtle router that some peers are (dis)connected. This should initiate digging new tunnels, @@ -410,6 +413,11 @@ class p3turtle: public p3Service, /*public pqiMonitor,*/ public RsTurtle,/* publ /// uint32_t _random_bias ; + // Used to collect statistics on turtle traffic. + // + TurtleTrafficStatisticsInfoOp _traffic_info ; // used for recording speed + TurtleTrafficStatisticsInfoOp _traffic_info_buffer ; // used as a buffer to collect bytes + #ifdef P3TURTLE_DEBUG // debug function void dumpState() ; diff --git a/libretroshare/src/turtle/turtlestatistics.h b/libretroshare/src/turtle/turtlestatistics.h new file mode 100644 index 000000000..5aaeda676 --- /dev/null +++ b/libretroshare/src/turtle/turtlestatistics.h @@ -0,0 +1,51 @@ +#include + +class TurtleTrafficStatisticsInfoOp: public TurtleTrafficStatisticsInfo +{ + public: + TurtleTrafficStatisticsInfoOp() + { + reset() ; + } + + void reset() + { + unknown_updn_Bps = 0.0f ; + data_up_Bps = 0.0f ; + data_dn_Bps = 0.0f ; + tr_up_Bps = 0.0f ; + tr_dn_Bps = 0.0f ; + total_up_Bps = 0.0f ; + total_dn_Bps = 0.0f ; + } + + TurtleTrafficStatisticsInfoOp operator*(float f) const + { + TurtleTrafficStatisticsInfoOp i(*this) ; + + i.unknown_updn_Bps *= f ; + i.data_up_Bps *= f ; + i.data_dn_Bps *= f ; + i.tr_up_Bps *= f ; + i.tr_dn_Bps *= f ; + i.total_up_Bps *= f ; + i.total_dn_Bps *= f ; + + return i ; + } + TurtleTrafficStatisticsInfoOp operator+(const TurtleTrafficStatisticsInfoOp& j) const + { + TurtleTrafficStatisticsInfoOp i(*this) ; + + i.unknown_updn_Bps += j.unknown_updn_Bps ; + i.data_up_Bps += j.data_up_Bps ; + i.data_dn_Bps += j.data_dn_Bps ; + i.tr_up_Bps += j.tr_up_Bps ; + i.tr_dn_Bps += j.tr_dn_Bps ; + i.total_up_Bps += j.total_up_Bps ; + i.total_dn_Bps += j.total_dn_Bps ; + + return i ; + } +}; + diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.cpp b/retroshare-gui/src/gui/TurtleRouterDialog.cpp index 1c542d103..d93c40513 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.cpp +++ b/retroshare-gui/src/gui/TurtleRouterDialog.cpp @@ -22,8 +22,9 @@ class TRHistogram virtual void draw(QPainter *painter,int& ox,int& oy,const QString& title) { static const int MaxTime = 61 ; - static const int cellx = 6 ; - static const int celly = 10 ; + static const int MaxDepth = 8 ; + static const int cellx = 7 ; + static const int celly = 12 ; int save_ox = ox ; painter->setPen(QColor::fromRgb(0,0,0)) ; @@ -35,26 +36,51 @@ class TRHistogram ox += 10 ; std::map > hits ; + std::map > depths ; std::map >::iterator it ; int max_hits = 1; + int max_depth = 1; + for(uint32_t i=0;i<_infos.size();++i) { std::vector& h(hits[_infos[i].source_peer_id]) ; + std::vector& g(depths[_infos[i].source_peer_id]) ; if(h.size() <= _infos[i].age) h.resize(MaxTime,0) ; + if(g.empty()) + g.resize(MaxDepth,0) ; + if(_infos[i].age < h.size()) { h[_infos[i].age]++ ; if(h[_infos[i].age] > max_hits) max_hits = h[_infos[i].age] ; } + if(_infos[i].depth < g.size()) + { + g[_infos[i].depth]++ ; + + if(g[_infos[i].depth] > max_depth) + max_depth = g[_infos[i].depth] ; + } } int p=0 ; + for(it=depths.begin();it!=depths.end();++it,++p) + for(int i=0;ifillRect(ox+MaxTime*cellx+20+i*cellx,oy+p*celly,cellx,celly,colorScale(it->second[i]/(float)max_depth)) ; + + painter->setPen(QColor::fromRgb(0,0,0)) ; + painter->drawRect(ox+MaxTime*cellx+20,oy,MaxDepth*cellx,p*celly) ; + + for(int i=0;idrawText(ox+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ; + + p=0 ; for(it=hits.begin();it!=hits.end();++it,++p) { int total = 0 ; @@ -66,28 +92,31 @@ class TRHistogram } painter->setPen(QColor::fromRgb(0,0,0)) ; - painter->drawText(ox+(MaxTime+1)*cellx,oy+(p+1)*celly,TurtleRouterDialog::getPeerName(it->first)) ; - painter->drawText(ox+(MaxTime+1)*cellx+80,oy+(p+1)*celly,"("+QString::number(total)+")") ; + painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx,oy+(p+1)*celly,TurtleRouterDialog::getPeerName(it->first)) ; + painter->drawText(ox+MaxDepth*cellx+30+(MaxTime+1)*cellx+80,oy+(p+1)*celly,"("+QString::number(total)+")") ; } painter->drawRect(ox,oy,MaxTime*cellx,p*celly) ; for(int i=0;idrawText(ox+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ; + for(int i=0;idrawText(ox+MaxTime*cellx+20+i*cellx,oy+(p+1)*celly+4,QString::number(i)) ; oy += (p+1)*celly+4 ; painter->drawText(ox,oy+celly,QObject::tr("(Age in seconds)")); + painter->drawText(ox+MaxTime*cellx+20,oy+celly,QObject::tr("(Depth)")); oy += 3*celly ; // now, draw a scale for(int i=0;i<=10;++i) { - painter->fillRect(ox+i*(cellx+40),oy,cellx,celly,colorScale(i/10.0f)) ; + painter->fillRect(ox+i*(cellx+20),oy,cellx,celly,colorScale(i/10.0f)) ; painter->setPen(QColor::fromRgb(0,0,0)) ; - painter->drawRect(ox+i*(cellx+40),oy,cellx,celly) ; - painter->drawText(ox+i*(cellx+40)+cellx+4,oy+celly,QString::number((int)(max_hits*i/10.0))) ; + painter->drawRect(ox+i*(cellx+20),oy,cellx,celly) ; + painter->drawText(ox+i*(cellx+20)+cellx+4,oy+celly,QString::number((int)(max_hits*i/10.0))) ; } oy += celly*2 ; @@ -295,10 +324,36 @@ void TurtleRouterStatisticsWidget::updateTunnelStatistics(const std::vectorgetTrafficStatistics(info) ; + + static const int cellx = 6 ; + static const int celly = 10+4 ; + + painter.drawText(ox,oy+celly,tr("Turtle router traffic:")) ; oy += celly*2 ; + painter.drawText(ox+2*cellx,oy+celly,tr("Tunnel requests Up")+"\t: " + speedString(info.tr_up_Bps) ) ; oy += celly ; + painter.drawText(ox+2*cellx,oy+celly,tr("Tunnel requests Dn")+"\t: " + speedString(info.tr_dn_Bps) ) ; oy += celly ; + painter.drawText(ox+2*cellx,oy+celly,tr("Incoming file data")+"\t: " + speedString(info.data_dn_Bps) ) ; oy += celly ; + painter.drawText(ox+2*cellx,oy+celly,tr("Outgoing file data")+"\t: " + speedString(info.data_up_Bps) ) ; oy += celly ; + painter.drawText(ox+2*cellx,oy+celly,tr("Forwarded data ")+"\t: " + speedString(info.unknown_updn_Bps) ) ; oy += celly ; + // update the pixmap + // pixmap = tmppixmap; } +QString TurtleRouterStatisticsWidget::speedString(float f) +{ + if(f < 1.0f) + return QString("0 B/s") ; + if(f < 1024.0f) + return QString::number((int)f)+" B/s" ; + + return QString::number(f/1024.0,'f',2) + " KB/s"; +} + void TurtleRouterStatisticsWidget::paintEvent(QPaintEvent *event) { QStylePainter(this).drawPixmap(0, 0, pixmap); @@ -307,7 +362,7 @@ void TurtleRouterStatisticsWidget::paintEvent(QPaintEvent *event) void TurtleRouterStatisticsWidget::resizeEvent(QResizeEvent *event) { QRect TaskGraphRect = geometry(); - maxWidth = TaskGraphRect.width(); + maxWidth = 900;//TaskGraphRect.width(); maxHeight = TaskGraphRect.height(); QWidget::resizeEvent(event); diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.h b/retroshare-gui/src/gui/TurtleRouterDialog.h index 955cb163f..02e63a06b 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.h +++ b/retroshare-gui/src/gui/TurtleRouterDialog.h @@ -46,6 +46,8 @@ class TurtleRouterStatisticsWidget: public QWidget const std::vector&) ; private: + static QString speedString(float f) ; + QPixmap pixmap ; int maxWidth,maxHeight ; }; diff --git a/retroshare-gui/src/gui/TurtleRouterDialog.ui b/retroshare-gui/src/gui/TurtleRouterDialog.ui index 8fa1d1db0..c50d2f11a 100644 --- a/retroshare-gui/src/gui/TurtleRouterDialog.ui +++ b/retroshare-gui/src/gui/TurtleRouterDialog.ui @@ -40,6 +40,12 @@ 0 + + + 800 + 0 + + QFrame::StyledPanel