Skip to content

Instantly share code, notes, and snippets.

@danielballan
Last active Feb 24, 2021
Embed
What would you like to do?
IOC connection time analysis

IOC connection time analysis

We will use caproto-shark to analyze CA network traffic. Note that the actual servers and clients involve may or may not be using caproto themselves; it does not matter.

  1. Install caproto and pandas if they are not already installed.

    pip install caproto[standard] pandas
    
  2. Start tcpdump to capture network traffic and write it to a file.

    sudo tcpdump -i <INTERFACE> -w some_network_traffic.pcap
    

    Use ifconfig to list the available interfaces. For example, if the servers in question are running on the localhost:

    sudo tcpdump -i lo -w some_network_traffic.pcap
    
  3. Run some EPICS client code that will create CA connections with servers (e.g. run bsui).

  4. Stop tcpdump with Ctrl+C.

  5. Analyze the results using the script in this gist.

    python benchmark.py some_network_traffic.pcap
    

Example output:

0 channel creation requests were unanswered during this capture.


Raw data:
          PV  server_address             t        dt
0   simple:A   192.168.86.22  1.614185e+09  0.014851
1   simple:B   192.168.86.22  1.614185e+09  0.014851
2   simple:C   192.168.86.22  1.614185e+09  0.014851
3  rpi:color  192.168.86.245  1.614185e+09  0.150308


Aggregated stats by server address:
                count      mean  std       min       25%       50%       75%       max
server_address                                                                        
192.168.86.22     3.0  0.014851  0.0  0.014851  0.014851  0.014851  0.014851  0.014851
192.168.86.245    1.0  0.150308  NaN  0.150308  0.150308  0.150308  0.150308  0.150308
"""
Analyze IOCs response times for channel creation (connection).
python benchmark.py some_network_traffic.pcap
"""
from collections import namedtuple
from caproto import CreateChanRequest, CreateChanResponse
from caproto.sync.shark import shark
import pandas
Pair = namedtuple("Pair", ["request", "response"])
Record = namedtuple("Record", ["PV", "server_address", "t", "dt"])
def match_request_and_response(parsed):
"From a stream of parsed CA traffic, extract channel creation request/response pairs."
unanswered_requests = {}
pairs = []
for item in parsed:
command = item.command
if isinstance(command, CreateChanRequest):
unanswered_requests[command.cid] = item
elif isinstance(command, CreateChanResponse):
request_item = unanswered_requests.pop(command.cid, None)
pairs.append(Pair(request_item, item))
return pairs, list(unanswered_requests.values())
def build_record_from_request_and_response_pair(pair):
"Extract PV name, server address, absolute time t, and request/response dt."
request, response = pair
record = Record(
PV=request.command.name,
server_address=request.dst,
t=request.timestamp,
dt=response.timestamp - request.timestamp
)
return record
def main(filepath):
with open(filepath, "rb") as file:
parsed = shark(file)
pairs, unanswered = match_request_and_response(parsed)
print(f"{len(unanswered)} channel creation requests were unanswered during this capture.")
# TODO Tally the unanswered requests by server_address and print that.
# The collections.Counter object would be useful there.
records = [build_record_from_request_and_response_pair(pair) for pair in pairs]
df = pandas.DataFrame.from_records(records, columns=Record._fields)
server_stats = df.groupby("server_address")["dt"].describe()
print("\n\nRaw data:")
print(df)
print("\n\nAggregated stats by server address:")
print(server_stats)
if __name__ == "__main__":
import sys
main(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment