wiki:802.11/wlan_exp/examples/throughput_stats

Version 2 (modified by murphpo, 10 years ago) (diff)

--

802.11 Reference Design: Aggregate Throughput Example

This example of the Experiments Framework uses two WARP v3 nodes, one configured as an AP, the other as a STA. The script steps through PHY rates, measuring unidirectional throughput for ~10 seconds for each rate. This script demonstrates how to:

  • Control two WARP v3 nodes from one wlan_exp script
  • Use the wlan_exp framework Local Traffic Generator (LTG) to create traffic
  • Read Tx/Rx packet counts from nodes to calculate per-flow throughput

The flow of the script is:

  1. Initialize two WARP v3 nodes
  2. Ensure nodes are configured as one AP, one STA and that the STA is associated with AP
  3. Start a fully-backlogged locally generated traffic (LTG) flow from AP -> STA
  4. For each WLAN rate:
    1. Read current Tx/Rx packet counts at STA
    2. Wait 10 seconds
    3. Read current Tx/Rx packet counts at STA again
    4. Calculate throughput for 10 second window
  5. Stop the traffic flow
  6. Print the results

To run this example:

  • Setup wlan_exp (see Getting Started for details)
  • Configure two WARP v3 nodes with the 802.11 Reference Design bitstream- one AP, one STA
  • Open a Python shell
  • CD to the Python_Reference/Examples directory from the expanded 802.11 Reference design archive
  • Run python throughput_two_nodes.py

The script will run for ~80 seconds, then display its results:

RESULS GO HERE

Source: the script is included in the 802.11 Reference Design archive at Python_Reference/examples/throughput_two_nodes.py.

The latest version of the throughput_two_nodes.py script is also shown below.

"""
------------------------------------------------------------------------------
Mango 802.11 Reference Design Experiments Framework - Two Node Throughput
------------------------------------------------------------------------------
License:   Copyright 2014-2019, Mango Communications. All rights reserved.
           Distributed under the WARP license (http://warpproject.org/license)
------------------------------------------------------------------------------
This script uses the 802.11 ref design and wlan_exp to measure throughput 
between an AP and an associated STA using the AP's local traffic generator 
(LTG).

Hardware Setup:
  - Requires two WARP v3 nodes
    - One node configured as AP using 802.11 Reference Design v1.7 or later
    - One node configured as STA using 802.11 Reference Design v1.7 or later
    - Two nodes configured as IBSS using 802.11 Reference Design v1.7 or later
  - PC NIC and ETH B on WARP v3 nodes connected to common Ethernet switch

Required Script Changes:
  - Set NETWORK to the IP address of your host PC NIC network (eg X.Y.Z.0 for IP X.Y.Z.W)
  - Set NODE_SERIAL_LIST to the serial numbers of your WARP nodes

Description:
  This script initializes two WARP v3 nodes, one AP and one STA or two IBSS. 
It will use wlan_exp commands to set up the network for the experiment.  The 
script then , sets the Tx rate for the nodes; initiates a traffic flow from 
the node 1 to node 2 and measures throughput by counting the number of bytes
received successfully at node 2. This process repeats for node 2 -> node 1 and 
head-to-head traffic flows.
------------------------------------------------------------------------------
"""
import sys
import time
import wlan_exp.config as config
import wlan_exp.util as util
import wlan_exp.ltg as ltg

#-------------------------------------------------------------------------
#  Global experiment variables
#

# Change these values to match your experiment / network setup
NETWORK              = '10.0.0.0'
USE_JUMBO_ETH_FRAMES = False
NODE_SERIAL_LIST     = ['W3-a-00001', 'W3-a-00002']

# BSS parameters
SSID                 = "WARP Xput Example"
CHANNEL              = 1
BEACON_INTERVAL      = 100

# Set the per-trial duration (in seconds)
TRIAL_TIME           = 10

#-------------------------------------------------------------------------
#  Initialization
#
print("\nInitializing experiment\n")

# Create an object that describes the network configuration of the host PC
network_config = config.WlanExpNetworkConfiguration(network=NETWORK,
                                                    jumbo_frame_support=USE_JUMBO_ETH_FRAMES)

# Create an object that describes the WARP v3 nodes that will be used in this experiment
nodes_config   = config.WlanExpNodesConfiguration(network_config=network_config,
                                                  serial_numbers=NODE_SERIAL_LIST)

# Initialize the Nodes
#   This command will fail if either WARP v3 node does not respond
nodes = util.init_nodes(nodes_config, network_config)

# Reset all (optional)
# for node in nodes:
#     node.reset_all()

# Extract the different types of nodes from the list of initialized nodes
#     - This will work for both 'DCF' and 'NOMAC' mac_low projects
n_ap_l   = util.filter_nodes(nodes=nodes, mac_high='AP',   serial_number=NODE_SERIAL_LIST, warn=False)
n_sta_l  = util.filter_nodes(nodes=nodes, mac_high='STA',  serial_number=NODE_SERIAL_LIST, warn=False)
n_ibss_l = util.filter_nodes(nodes=nodes, mac_high='IBSS', serial_number=NODE_SERIAL_LIST, warn=False)


# Check that setup is valid:
#     1) AP and STA
#     2) Two IBSS nodes
if len(n_ap_l) == 1 and len(n_sta_l) == 1:
    # Setup the two nodes
    node1 = n_ap_l[0]
    node2 = n_sta_l[0]

    # Configure the AP to reject authentication requests from wireless clients
    #    - Uncomment this line to block any wireless associations during the experiment
    # node1.set_authentication_address_filter(allow='NONE')

    # Configure AP BSS
    node1.configure_bss(ssid=SSID, channel=CHANNEL, beacon_interval=BEACON_INTERVAL)

    # Establish the association between nodes
    #     - This will change the STA to the appropriate channel
    node1.add_association(node2)
    
elif len(n_ibss_l) == 2:
    # Setup the two nodes
    node1 = n_ibss_l[0]
    node2 = n_ibss_l[1]

    # Create the BSS_INFO describing the ad-hoc network
    bssid    = util.create_locally_administered_bssid(node1.wlan_mac_address)

    # Add both nodes to the new IBSS
    node1.configure_bss(bssid=bssid, ssid=SSID, channel=CHANNEL, beacon_interval=BEACON_INTERVAL)
    node2.configure_bss(bssid=bssid, ssid=SSID, channel=CHANNEL, beacon_interval=BEACON_INTERVAL)

else:
    print("ERROR: Node configurations did not match requirements of script.\n")
    print("    Ensure two nodes are ready, either:\n")
    print("        1) one using the AP design, one using the STA design, or\n")
    print("        2) two using the IBSS design\n")
    sys.exit(0)

#-------------------------------------------------------------------------
#  Setup
#

print("\nExperimental Setup:")

# Set the rate of both nodes to 26 Mbps (mcs = 3, phy_mode = 'HTMF')
mcs       = 3
phy_mode  = util.phy_modes['HTMF']
rate_info = util.get_rate_info(mcs, phy_mode)

# Put each node in a known, good state
for node in [node1, node2]:
    node.enable_ethernet_portal(enable=False)
    node.set_tx_rate_data(mcs, phy_mode, device_list='ALL_UNICAST')
    node.reset(log=True, txrx_counts=True, ltg=True, tx_queues=True) # Do not reset associations/bss_info
    network_info = node.get_network_info()

    msg = ""
    if (node == node1):
        msg += "\nNode 1: \n"
    if (node == node2):
        msg += "\nNode 2: \n"

    msg += "    Description = {0}\n".format(node.description)
    msg += "    Channel     = {0}\n".format(util.channel_info_to_str(util.get_channel_info(network_info['channel'])))
    msg += "    Rate        = {0}\n".format(util.rate_info_to_str(rate_info))
    print(msg)

print("")

# Check that the nodes are part of the same BSS.  Otherwise, the LTGs below will fail.
if not util.check_bss_membership([node1, node2]):
    print("\nERROR: Nodes are not part of the same BSS.")
    util.check_bss_membership([node1, node2], verbose=True)
    print("Ensure that both nodes are part of the same BSS.")
    sys.exit(0)

#-------------------------------------------------------------------------
#  Run Experiments
#
print("\nRun Experiment:")

# Experiments:
#   1) Node1 -> Node2 throughput
#   2) Node2 -> Node1 throughput
#   3) Head-to-head throughput
#
# This experiment is basically the same for each iteration.  Therefore, the 
# main control variables for each iteration have been placed into the 
# dictionary below to make readability easier by not having repeated code.
#
experiment_params = [{'node1_ltg_en' : True,  'node2_ltg_en' : False, 'desc' : 'Node 1 -> Node 2'},
                     {'node1_ltg_en' : False, 'node2_ltg_en' : True,  'desc' : 'Node 2 -> Node 1'},
                     {'node1_ltg_en' : True,  'node2_ltg_en' : True,  'desc' : 'Head-to-Head'}]


#-------------------------------------------------------------------------
#  Experiment:  Compute throughput from node counts
#
for experiment in experiment_params:

    print("\nTesting {0} throughput for rate {1} ...".format(experiment['desc'], util.rate_info_to_str(rate_info)))

    # Start a flow from the AP's local traffic generator (LTG) to the STA
    #    Set the flow to 1400 byte payloads, fully backlogged (0 usec between new pkts), run forever
    #    Start the flow immediately
    if (experiment['node1_ltg_en']):
        node1_ltg_id  = node1.ltg_configure(ltg.FlowConfigCBR(dest_addr=node2.wlan_mac_address,
                                                              payload_length=1400, 
                                                              interval=0), auto_start=True)

    # Start a flow from the STA's local traffic generator (LTG) to the AP
    #    Set the flow to 1400 byte payloads, fully backlogged (0 usec between new pkts), run forever
    #    Start the flow immediately
    if (experiment['node2_ltg_en']):
        node2_ltg_id  = node2.ltg_configure(ltg.FlowConfigCBR(dest_addr=node1.wlan_mac_address,
                                                              payload_length=1400, 
                                                              interval=0), auto_start=True)

    # Record the initial Tx/Rx counts
    #     - This example is interested in received throughput not transmitted 
    #       throughput.  Therefore, it must use the received (RX) counts and 
    #       not the transmitted (TX) counts for the experiment.  To use the 
    #       RX counts, it must first get them from the receiving node.  For 
    #       example, to see the packets received from Node 1 at Node 2, get 
    #       the TX/RX counts from Node 2 for Node 1.  This is opposite of TX 
    #       counts which must be extracted from the transmitting node.  For 
    #       example, to see the packets transmitted from Node 1 to Node 2, get 
    #       the TX/RX counts from Node 1 for Node 2.  
    #
    node2_txrx_counts_for_node1_start = node2.get_txrx_counts(node1)
    node1_txrx_counts_for_node2_start = node1.get_txrx_counts(node2)

    # Wait for the TRIAL_TIME
    time.sleep(TRIAL_TIME)

    # Record the ending Tx/Rx counts
    node2_txrx_counts_for_node1_end = node2.get_txrx_counts(node1)
    node1_txrx_counts_for_node2_end = node1.get_txrx_counts(node2)

    # Stop the AP LTG flow and purge any remaining transmissions in the queue so that nodes are in a known, good state
    if (experiment['node1_ltg_en']):
        node1.ltg_stop(node1_ltg_id)
        node1.ltg_remove(node1_ltg_id)
        node1.queue_tx_data_purge_all()

    # Stop the STA LTG flow and purge any remaining transmissions in the queue so that nodes are in a known, good state
    if (experiment['node2_ltg_en']):
        node2.ltg_stop(node2_ltg_id)
        node2.ltg_remove(node2_ltg_id)
        node2.queue_tx_data_purge_all()

    # Compute the throughput
    #     - Timestamps are in microseconds; bits/usec == Mbits/sec
    #     - In Python 3.x, the division operator is always floating point.  In order to be compatible with all versions
    #       of python, cast operands to floats to ensure floating point division
    #
    node1_to_node2_num_bits  = float((node2_txrx_counts_for_node1_end['data_num_rx_bytes'] - node2_txrx_counts_for_node1_start['data_num_rx_bytes']) * 8)
    node1_to_node2_time_span = float(node2_txrx_counts_for_node1_end['retrieval_timestamp'] - node2_txrx_counts_for_node1_start['retrieval_timestamp'])
    node1_to_node2_xput      = node1_to_node2_num_bits / node1_to_node2_time_span
    print("    Node 1 -> Node 2:  Rate = {0:>4.1f} Mbps   Throughput = {1:>5.2f} Mbps".format(rate_info['phy_rate'], node1_to_node2_xput))

    node2_to_node1_num_bits  = float((node1_txrx_counts_for_node2_end['data_num_rx_bytes'] - node1_txrx_counts_for_node2_start['data_num_rx_bytes']) * 8)
    node2_to_node1_time_span = float(node1_txrx_counts_for_node2_end['retrieval_timestamp'] - node1_txrx_counts_for_node2_start['retrieval_timestamp'])
    node2_to_node1_xput      = node2_to_node1_num_bits / node2_to_node1_time_span
    print("    Node 2 -> Node 1:  Rate = {0:>4.1f} Mbps   Throughput = {1:>5.2f} Mbps".format(rate_info['phy_rate'], node2_to_node1_xput))

for node in [node1, node2]:
    node.enable_ethernet_portal(enable=True)