Index: src/pgbr/helper/multiple-flows-application-helper.cc |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/pgbr/helper/multiple-flows-application-helper.cc |
@@ -0,0 +1,266 @@ |
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
+/* |
+ * Copyright (c) Waterford Institute of Technology, 2013, Julien Mineraud, BioFINT. |
+ * |
+ * This program is free software; you can redistribute it and/or modify |
+ * it under the terms of the GNU General Public License version 2 as |
+ * published by the Free Software Foundation; |
+ * |
+ * 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 General Public License for more details. |
+ * |
+ * You should have received a copy of the GNU General Public License |
+ * along with this program; if not, write to the Free Software |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
+ * |
+ * Author: Julien Mineraud <julien.mineraud@gmail.com> |
+ * |
+ * Acknowledgements: |
+ * This work has received support from Science Foundation Ireland via the |
+ * "A Biologically inspired framework supporting network management for |
+ * the Future Internet" starting investigator award (grant no. 09/SIRG/I1643). |
+ */ |
+ |
+#include "multiple-flows-application-helper.h" |
+#include "ns3/string.h" |
+#include "ns3/node.h" |
+#include "ns3/names.h" |
+#include "ns3/log.h" |
+#include <list> |
+#include "ns3/flow-id-tag.h" |
+ |
+NS_LOG_COMPONENT_DEFINE ("MultipleFlowsApplicationHelper"); |
+ |
+namespace ns3 { |
+namespace pgbr { |
+ |
+MultipleFlowsApplicationHelper::MultipleFlowsApplicationHelper (std::string protocol, Address address) |
+{ |
+ m_durationInterval = Seconds (10); |
+ m_durationVariable = UniformVariable (6.0, 10.0); |
+ m_startVariable = ExponentialVariable (0.5); |
+ m_payloadVariable = UniformVariable (20000, 100000); |
+ m_factory.SetTypeId ("ns3::pgbr::MultipleFlowsApplication"); |
+ m_factory.Set ("Protocol", StringValue (protocol)); |
+ m_factory.Set ("Remote", AddressValue (address)); |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::SetAttribute (std::string name, const AttributeValue &value) |
+{ |
+ m_factory.Set (name, value); |
+} |
+ |
+ApplicationContainer |
+MultipleFlowsApplicationHelper::InstallFlows (Ptr<Node> node, uint32_t packetSize, bool justOnePacket) |
+{ |
+ std::list<Flow> flows = GetFlowList (); |
+ ApplicationContainer applications; |
+ Ptr<MultipleFlowsApplication> multipleFlowApp = Install (node); |
+ for (std::list<Flow>::const_iterator it = flows.begin (); it != flows.end (); it++) |
+ { |
+ Flow f = (*it); |
+ if (f.duration > 0) |
+ { |
+ multipleFlowApp->AddInnerFlow (f.start, f.duration, f.bitRate, packetSize, false); |
+ } |
+ } |
+ NS_LOG_DEBUG ("I generated normally " << flows.size() << " flows"); |
+ applications.Add (multipleFlowApp); |
+ return applications; |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::Save (Ptr<OutputStreamWrapper> stream, Ptr<Node> src, Ptr<Node> dst) |
+{ |
+ std::list<Flow> flows = GetFlowList (); |
+ for (std::list<Flow>::const_iterator it = flows.begin (); it != flows.end (); it++) |
+ { |
+ Flow f = (*it); |
+ if (f.duration > 0) |
+ { |
+ *stream->GetStream () << f.start << "\t" << f.duration << "\t" << src->GetId () << "\t" << dst->GetId () << "\t" << f.bitRate << std::endl; |
+ } |
+ } |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::AddInterval (DataRate dataRate) |
+{ |
+ m_cbrRates.push_back (dataRate); |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::SetDurationInterval (Time durationInterval) |
+{ |
+ NS_ASSERT (durationInterval.IsStrictlyPositive ()); |
+ m_durationInterval = durationInterval; |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::SetStartVariable (RandomVariable startVariable) |
+{ |
+ m_startVariable = startVariable; |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::SetDurationVariable (RandomVariable durationVariable) |
+{ |
+ m_durationVariable = durationVariable; |
+} |
+ |
+void |
+MultipleFlowsApplicationHelper::SetPayloadVariable (RandomVariable payloadVariable) |
+{ |
+ m_payloadVariable = payloadVariable; |
+} |
+ |
+std::list<MultipleFlowsApplicationHelper::Flow> |
+MultipleFlowsApplicationHelper::GetFlowList () |
+{ |
+ std::list<Flow> flows; |
+ double_t intervalDuration = m_durationInterval.GetSeconds (); |
+ //std::list<Flow> acceptedFlows; //To reduce the number of flows that I have to search through, I can put the one that started and finished before the current interval in there |
+ for (uint32_t zone = 0; zone < m_cbrRates.size (); zone++) |
+ { |
+ NS_LOG_DEBUG ("Welcome to the zone " << zone << "!"); |
+ //First thing is to calculate in a zone, the expected |
+ uint64_t expectedGeneratedBits = m_cbrRates[zone].GetBitRate () * intervalDuration; |
+ NS_LOG_DEBUG ("The expected generated bits for zone " << zone << "=" << expectedGeneratedBits); |
+ |
+ //Second get the already generated bits from the flow vector. |
+ uint64_t alreadyInThePipe = 0; |
+ for (std::list<Flow>::const_iterator it = flows.begin (); it != flows.end (); it++) |
+ { |
+ Flow f = (*it); |
+ if (f.start + f.duration > (zone * intervalDuration)) |
+ { |
+ double start = (zone * intervalDuration); |
+ double stop = (f.start + f.duration > ((zone + 1) * intervalDuration)) ? ((zone + 1) * intervalDuration) : f.start + f.duration; |
+ alreadyInThePipe += (stop - start) * f.bitRate; |
+ } |
+ } |
+ NS_LOG_DEBUG ("There are already " << alreadyInThePipe << " bits in the pipe"); |
+ //Then there are three option. |
+ if (alreadyInThePipe == expectedGeneratedBits) |
+ { |
+ NS_LOG_DEBUG ("The bits were generated, no need to do anything"); |
+ continue; |
+ } |
+ else if (alreadyInThePipe < expectedGeneratedBits) |
+ { |
+ NS_LOG_DEBUG ("I need to generate more flows"); |
+ double_t tempStart = (zone * intervalDuration); |
+ while (alreadyInThePipe < expectedGeneratedBits) |
+ { |
+ Flow f; |
+ f.id = flows.size () + 1; |
+ f.start = tempStart + m_startVariable.GetValue (); |
+ f.duration = m_durationVariable.GetValue (); |
+ f.bitRate = m_payloadVariable.GetValue (); |
+ double_t end = (f.start + f.duration > ((zone + 1) * intervalDuration)) ? ((zone + 1) * intervalDuration) : f.start + f.duration; |
+ double_t diff = end - f.start; |
+ uint64_t addedBits = diff * f.bitRate; |
+ uint32_t leftBits = expectedGeneratedBits - alreadyInThePipe; |
+ if (addedBits > leftBits) |
+ { |
+ NS_LOG_DEBUG ("I need to modify the duration of this request to generate less bits"); |
+ double_t newDiff = leftBits * 1.0 / f.bitRate; |
+ f.duration = newDiff; |
+ addedBits = leftBits; |
+ } |
+ alreadyInThePipe += addedBits; |
+ //std::cout << "I add flow " << f << " and now, there are " << alreadyInThePipe << " bits generated for this zone\n"; |
+ //tempStart = f.start; |
+ flows.push_back (f); |
+ } |
+ } |
+ else |
+ { |
+ NS_LOG_DEBUG ("I would have to remove some flows"); |
+ while (alreadyInThePipe > expectedGeneratedBits) |
+ { |
+ uint64_t bitstooMany = alreadyInThePipe - expectedGeneratedBits; |
+ NS_LOG_DEBUG ("There are still " << bitstooMany << " many bits in the pipe"); |
+ //Find the flow that generate the most bits in the interval and stop this flows at the time required (min being the beginning of the interval) |
+ //Reproduce until I have the required number of flows. |
+ uint32_t maxBits = 0; |
+ uint32_t maxFlowId = 0; |
+ for (std::list<Flow>::const_iterator it = flows.begin (); it != flows.end (); it++) |
+ { |
+ Flow f = (*it); |
+ if (f.start + f.duration > (zone * intervalDuration)) |
+ { |
+ double_t start = f.start > (zone * intervalDuration) ? f.start : (zone * intervalDuration); |
+ double_t end = f.start + f.duration > ((zone + 1) * intervalDuration) ? (zone + 1) * intervalDuration : f.start + f.duration; |
+ double_t diff = end - start; |
+ uint32_t bitsInZone = diff * f.bitRate; |
+ if (bitsInZone > maxBits) |
+ { |
+ maxBits = bitsInZone; |
+ maxFlowId = f.id; |
+ } |
+ } |
+ } |
+ NS_ASSERT (maxBits > 0 && maxFlowId > 0); |
+ for (std::list<Flow>::iterator it = flows.begin (); it != flows.end (); it++) |
+ { |
+ if (it->id == maxFlowId) |
+ { |
+ //std::cout << "The flow that generate the most bits in zone " << zone << " is " << (*it) << "\n"; |
+ double_t start = it->start > (zone * intervalDuration) ? it->start : (zone * intervalDuration); |
+ double_t end = it->start + it->duration > ((zone + 1) * intervalDuration) ? (zone + 1) * intervalDuration : it->start + it->duration; |
+ double_t diff = end - start; |
+ uint32_t bitsInZone = diff * it->bitRate; |
+ NS_LOG_DEBUG ("It has generated " << bitsInZone << " bits in that zone"); |
+ |
+ if (bitsInZone < bitstooMany) |
+ { |
+ NS_LOG_DEBUG ("reset duration so it finishes at the zone"); |
+ //Easy, I just set the start at zone * intervalDuration |
+ if (it->start < (zone * intervalDuration)) |
+ { |
+ it->duration = (zone * intervalDuration) - it->start; |
+ } |
+ else |
+ { |
+ NS_LOG_DEBUG ("We even kill the damned thing"); |
+ it->duration = 0; |
+ } |
+ alreadyInThePipe -= bitsInZone; |
+ } |
+ else |
+ { |
+ NS_LOG_DEBUG ("I dont have to reset until the beginning of the zone, normally it should be the last call"); |
+ //In that case I have to count how much I have to remove |
+ if (it->start + it->duration > ((zone + 1) * intervalDuration)) |
+ { |
+ it->duration = ((zone + 1) * intervalDuration) - it->start; |
+ } |
+ |
+ double_t timeToMakeTheBitsToMany = bitstooMany * 1.0 / it->bitRate; |
+ it->duration = it->duration - timeToMakeTheBitsToMany; |
+ NS_ASSERT (it->duration >= 0); |
+ alreadyInThePipe = expectedGeneratedBits; |
+ } |
+ //std::cout << "The modified flow is now " << (*it) << "\n"; |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ return flows; |
+} |
+ |
+Ptr<MultipleFlowsApplication> |
+MultipleFlowsApplicationHelper::Install (Ptr<Node> node) |
+{ |
+ Ptr<MultipleFlowsApplication> app = m_factory.Create<MultipleFlowsApplication> (); |
+ node->AddApplication (app); |
+ return app; |
+} |
+ |
+}} // namespace pgbr, ns3 |