diff --git a/util/tracing/Makefile b/util/tracing/Makefile index 201f65584..9700ac82f 100644 --- a/util/tracing/Makefile +++ b/util/tracing/Makefile @@ -1,7 +1,8 @@ # Makefile for utilities that convert Lingua Franca trace files # into other formats. # @author: Edward A. Lee -REACTOR_C=../../ +REACTOR_C=../.. +CURRENT_PATH=$(shell pwd) CC=gcc CFLAGS= -I$(REACTOR_C)/include/core/ \ -I$(REACTOR_C)/include/core/modal_models \ @@ -12,7 +13,8 @@ CFLAGS= -I$(REACTOR_C)/include/core/ \ DEPS= LIBS=-lcurl -INSTALL_PREFIX ?= /usr/local/bin +INSTALL_PREFIX ?= /usr/local +BIN_INSTALL_PATH = $(INSTALL_PREFIX)/bin %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) @@ -27,11 +29,12 @@ trace_to_influxdb: trace_to_influxdb.o trace_util.o $(CC) -o trace_to_influxdb trace_to_influxdb.o trace_util.o $(LIBS) install: trace_to_csv trace_to_chrome trace_to_influxdb - mv trace_to_csv $(INSTALL_PREFIX) - mv trace_to_chrome $(INSTALL_PREFIX) - mv trace_to_influxdb $(INSTALL_PREFIX) - ln -f -s launch-fedsd.sh $(INSTALL_PREFIX)/fedsd - chmod +x launch-fedsd.sh + cp trace_to_csv $(BIN_INSTALL_PATH) + cp trace_to_chrome $(BIN_INSTALL_PATH) + cp trace_to_influxdb $(BIN_INSTALL_PATH) + cp ./visualization/fedsd.py $(BIN_INSTALL_PATH) + ln -f -s $(BIN_INSTALL_PATH)/fedsd.py $(BIN_INSTALL_PATH)/fedsd + chmod +x $(BIN_INSTALL_PATH)/fedsd clean: rm -f *.o diff --git a/util/tracing/launch-fedsd.sh b/util/tracing/launch-fedsd.sh deleted file mode 100755 index 341e67332..000000000 --- a/util/tracing/launch-fedsd.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/bin/bash - -#============================================================================ -# Description: Visualize federated trace data for RTI-federate interactions. -# Authors: Chadlia Jerad -# Edward A. Lee -# Usage: Usage: fedsd -r [rti.csv] -f [fed.csv ...] -#============================================================================ - -#============================================================================ -# Preamble -#============================================================================ - -# Copied from build.sh FIXME: How to avoid copying - -# Find the directory in which this script resides in a way that is compatible -# with MacOS, which has a `readlink` implementation that does not support the -# necessary `-f` flag to canonicalize by following every symlink in every -# component of the given name recursively. -# This solution, adapted from an example written by Geoff Nixon, is POSIX- -# compliant and robust to symbolic links. If a chain of more than 1000 links -# is encountered, we return. -find_dir() ( - start_dir=$PWD - cd "$(dirname "$1")" - link=$(readlink "$(basename "$1")") - count=0 - while [ "${link}" ]; do - if [[ "${count}" -lt 1000 ]]; then - cd "$(dirname "${link}")" - link=$(readlink "$(basename "$1")") - ((count++)) - else - return - fi - done - real_path="$PWD/$(basename "$1")" - cd "${start_dir}" - echo `dirname "${real_path}"` -) - -# Report fatal error and exit. -function fatal_error() { - 1>&2 echo -e "\e[1mfedsd: \e[31mfatal error: \e[0m$1" - exit 1 -} - -abs_path="$(find_dir "$0")" - -if [[ "${abs_path}" ]]; then - base=`dirname $(dirname ${abs_path})` -else - fatal_error "Unable to determine absolute path to $0." -fi - -# Get the lft files -lft_files_list=$@ - -if [ -z "$lft_files_list" ] -then - echo "Usage: fedsd [lft files]" - exit 1 -fi - -# Initialize variables -csv_files_list='' -extension='.csv' -rti_csv_file='' - -# Iterate over the lft file list to: -# - First, transform into csv -# - Second, construct the csv fiel name -# - Then construct the csv file list -# The csv file list does include the rti, it is put in a separate variable -for each_lft_file in $lft_files_list - do - # Tranform to csv - ${base}/bin/trace_to_csv $each_lft_file - # Get the file name - csv=${each_lft_file%.*} - if [ $csv == 'rti' ] - then - # Set the rti csv file - rti_csv_file='rti.csv' - else - # Construct the csv file name and add it to the list - csv_files_list="$csv$extension $csv_files_list" - fi - done - -# echo $lft_files_list -# echo $rti_csv_file -# echo $csv_files_list - -# FIXME: Check that python3 is in the path. -if [ ! -z $rti_csv_file ] -then - python3 "${base}/util/tracing/visualization/fedsd.py" "-f" $csv_files_list -else - echo Building the communication diagram for the following trace files: $lft_files_list in trace_svg.html - python3 "${base}/util/tracing/visualization/fedsd.py" "-r" "$rti_csv_file" "-f" $csv_files_list -fi diff --git a/util/tracing/visualization/README.md b/util/tracing/visualization/README.md index c74803663..929f6bb3e 100644 --- a/util/tracing/visualization/README.md +++ b/util/tracing/visualization/README.md @@ -1,7 +1,9 @@ # Trace sequence diagram visualizer `fedsd` is a utility that reports the interactions (exchanged messages) -between federates and the RTI in a sequence-diagram-like format. +between federates and the RTI in a sequence-diagram-like format. +It also reports the interactions between different encalves in an enclaved execution, where no RTI trace file is provided. + To use `fedsd`, you need to first obtain an execution trace. To do this, enable the tracing mechanism in your Lingua Franca program by setting the `tracing` target property to `true` and then compile and run the program. @@ -10,7 +12,7 @@ internally running `trace_to_csv`. It then aggregates the data from all `.csv` files to do the matching and draw the sequence diagram. # Installing -`fedsd` is installed together with the rest of the tracing tools. For instructions refer to `~/util/tracing/README.md`. +`fedsd` is installed together with the rest of the tracing tools. For instructions refer to `util/tracing/README.md`. # Running @@ -20,16 +22,20 @@ file will be generated for each of the federates, in addition to `rti.lft`. The contains the RTI trace. If, however, the federation is launched manually, then running the `RTI` command should be passed the `-t` flag in order to make sure that it, too, has tracing enabled: -``` -$ RTI -n -t +```bash +RTI -n -t ``` It is most convenient to launch the RTI and all federates from the same working directory so that they will all write their trace file to that directory. -Once the federation stopped executing, run `fedsd` on all generated `.lft` files: +Once the federation stopped executing, running `fedsd` will operate on all the `.lft` files in the current directory: +```bash +fedsd ``` -$ fedsd *.lft +It is also possible to operate on specific files. In such a case, run `fedsd` with `-r` flag to provide the RTI trace file, and `-f` flag to privide the list of federates +trace files. Bith argumenets are optional. +```bash +fedsd -r -f ``` -The output is an html file named `trace_svg.html` (in the current directory) that contains the sequence of interactions -between the federates and the RTI. +The output is an html file named `trace_svg.html` (in the current directory) that contains the sequence of interactions between the federates and the RTI. diff --git a/util/tracing/visualization/fedsd.py b/util/tracing/visualization/fedsd.py index ce77998b5..9d482ab82 100644 --- a/util/tracing/visualization/fedsd.py +++ b/util/tracing/visualization/fedsd.py @@ -1,11 +1,13 @@ -''' -Define arrows: - (x1, y1) ==> (x2, y2), when unique result (this arrow will be tilted) - (x1, y1) --> (x2, y2), when a possible result (could be not tilted)? -If not arrow, then triangle with text +#!/usr/bin/python3 + +# Utility that reports the interactions (exchanged messages) between federates and the RTI in a +# sequence-diagram-like format, or between enclaves in an enclaved execution. +# +# The utility operates on lft trace files and outputs an html file embedding an svg image. +''' In the dataframe, each row will be marked with one op these values: - - 'arrow': draw a non-dashed arrow + - 'arrow': draw a solid arrow - 'dot': draw a dot only - 'marked': marked, not to be drawn - 'pending': pending @@ -35,26 +37,284 @@ \ ' -#!/usr/bin/env python3 +# Disctionary for pruning event names. Usefule for tracepoint matching and +# communication rendering +prune_event_name = { + "Sending ACK": "ACK", + "Sending TIMESTAMP": "TIMESTAMP", + "Sending NET": "NET", + "Sending LTC": "LTC", + "Sending STOP_REQ": "STOP_REQ", + "Sending STOP_REQ_REP": "STOP_REQ_REP", + "Sending STOP_GRN": "STOP_GRN", + "Sending FED_ID": "FED_ID", + "Sending PTAG": "PTAG", + "Sending TAG": "TAG", + "Sending REJECT": "REJECT", + "Sending RESIGN": "RESIGN", + "Sending PORT_ABS": "ABS", + "Sending CLOSE_RQ": "CLOSE_RQ", + "Sending TAGGED_MSG": "T_MSG", + "Sending P2P_TAGGED_MSG": "P2P_T_MSG", + "Sending MSG": "MSG", + "Sending P2P_MSG": "P2P_MSG", + "Sending ADR_AD": "ADR_AD", + "Sending ADR_QR": "ADR_QR", + "Receiving ACK": "ACK", + "Receiving TIMESTAMP": "TIMESTAMP", + "Receiving NET": "NET", + "Receiving LTC": "LTC", + "Receiving STOP_REQ": "STOP_REQ", + "Receiving STOP_REQ_REP": "STOP_REQ_REP", + "Receiving STOP_GRN": "STOP_GRN", + "Receiving FED_ID": "FED_ID", + "Receiving PTAG": "PTAG", + "Receiving TAG": "TAG", + "Receiving REJECT": "REJECT", + "Receiving RESIGN": "RESIGN", + "Receiving PORT_ABS": "ABS", + "Receiving CLOSE_RQ": "CLOSE_RQ", + "Receiving TAGGED_MSG": "T_MSG", + "Receiving P2P_TAGGED_MSG": "P2P_T_MSG", + "Receiving MSG": "MSG", + "Receiving P2P_MSG": "P2P_MSG", + "Receiving ADR_AD": "ADR_AD", + "Receiving ADR_QR": "ADR_QR", + "Receiving UNIDENTIFIED": "UNIDENTIFIED", + "Scheduler advancing time ends": "AdvLT" +} + +prune_event_name.setdefault(" ", "UNIDENTIFIED") + import argparse # For arguments parsing import pandas as pd # For csv manipulation -from os.path import exists +import os +import sys from pathlib import Path import math -import fedsd_helper as fhlp +import subprocess # Define the arguments to pass in the command line -parser = argparse.ArgumentParser(description='Set of the csv trace files to render.') -parser.add_argument('-r','--rti', type=str, default="rti.csv", - help='RTI csv trace file.') +parser = argparse.ArgumentParser(description='Set of the lft trace files to render.') +parser.add_argument('-r','--rti', type=str, + help='RTI\'s lft trace file.') parser.add_argument('-f','--federates', nargs='+', action='append', - help='List of the federates csv trace files.') + help='List of the federates\' lft trace files.') # Events matching at the sender and receiver ends depend on whether they are tagged # (the elapsed logical time and microstep have to be the same) or not. # Set of tagged events (messages) non_tagged_messages = {'FED_ID', 'ACK', 'REJECT', 'ADR_RQ', 'ADR_AD', 'MSG', 'P2P_MSG'} + +################################################################################ +### Routines to get svg descriptions +################################################################################ + +def svg_string_draw_line(x1, y1, x2, y2, type=''): + ''' + Constructs the svg html string to draw a line from (x1, y1) to (x2, y2). + + Args: + * x1: Int X coordinate of the source point + * y1: Int Y coordinate of the source point + * x2: Int X coordinate of the sink point + * y2: Int Y coordinate of the sink point + * type: The type of the message (for styling) + Returns: + * String: the svg string of the lineĀ© + ''' + str_line = '\t\n' + return str_line + + +def svg_string_draw_arrow_head(x1, y1, x2, y2, type='') : + ''' + Constructs the svg html string to draw the arrow end + + Args: + * x1: Int X coordinate of the source point + * y1: Int Y coordinate of the source point + * x2: Int X coordinate of the sink point + * y2: Int Y coordinate of the sink point + * type: The type (for styling) + Returns: + * String: the svg string of the triangle + ''' + + if (y2 != y1): + rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90 + else: + if (x1 > x2): + rotation = 0 + else: + rotation = - 180 + + style = '' + if (type): + style = ' class="'+type+'"' + + str_line = '' + if (x1 > x2) : + str_line = '\t\n' + else : + str_line = '\t\n' + + return str_line + + +def svg_string_draw_label(x1, y1, x2, y2, label) : + ''' + Computes the rotation angle of the text and then constructs the svg string. + + Args: + * x1: Int X coordinate of the source point + * y1: Int Y coordinate of the source point + * x2: Int X coordinate of the sink point + * y2: Int Y coordinate of the sink point + * label: The label to draw + Returns: + * String: the svg string of the text + ''' + # FIXME: Need further improvement, based of the position of the arrows + # FIXME: Rotation value is not that accurate. + if (x2 < x1) : + # Left-going arrow. + if (y2 != y1): + rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90 + else: + rotation = 0 + + str_line = '\t'+label+'\n' + else : + # Right-going arrow. + if (y2 != y1): + rotation = - math.ceil(math.atan((x1-x2)/(y1-y2)) * 180 / 3.14) + 90 + else: + rotation = 0 + str_line = '\t'+label+'\n' + #print('rot = '+str(rotation)+' x1='+str(x1)+' y1='+str(y1)+' x2='+str(x2)+' y2='+str(y2)) + return str_line + + +def svg_string_draw_arrow(x1, y1, x2, y2, label, type=''): + ''' + Constructs the svg html string to draw the arrow from (x1, y1) to (x2, y2). + The arrow end is constructed, together with the label + + Args: + * x1: Int X coordinate of the source point + * y1: Int Y coordinate of the source point + * x2: Int X coordinate of the sink point + * y2: Int Y coordinate of the sink point + * label: String Label to draw on top of the arrow + * type: The type of the message + Returns: + * String: the svg string of the arrow + ''' + str_line1 = svg_string_draw_line(x1, y1, x2, y2, type) + str_line2 = svg_string_draw_arrow_head(x1, y1, x2, y2, type) + str_line3 = svg_string_draw_label(x1, y1, x2, y2, label) + return str_line1 + str_line2 + str_line3 + +def svg_string_draw_side_label(x, y, label, anchor="start") : + ''' + Put a label to the right of the x, y point, + unless x is small, in which case put it to the left. + + Args: + * x: Int X coordinate of the source point + * y: Int Y coordinate of the source point + * label: Label to put by the point. + * anchor: One of "start", "middle", or "end" to specify the text-anchor. + Returns: + * String: the svg string of the text + ''' + offset = 5 + if (anchor == 'end'): + offset = -5 + elif (anchor == 'middle'): + offset = 0 + str_line = '\t'+label+'\n' + return str_line + +def svg_string_comment(comment): + ''' + Constructs the svg html string to write a comment into an svg file. + + Args: + * comment: String Comment to add + Returns: + * String: the svg string of the comment + ''' + str_line = '\n\t\n' + return str_line + +def svg_string_draw_dot(x, y, label) : + ''' + Constructs the svg html string to draw at a dot. + + Args: + * x: Int X coordinate of the dot + * y: Int Y coordinate of the dot + * label: String to draw + Returns: + * String: the svg string of the triangle + ''' + str_line = '' + str_line = '\t\n' + str_line = str_line + '\t'+label+'\n' + return str_line + +def svg_string_draw_dot_with_time(x, y, time, label) : + ''' + Constructs the svg html string to draw at a dot with a prefixed physical time. + + Args: + * x: Int X coordinate of the dot + * y: Int Y coordinate of the dot + * time: The time + * label: String to draw + Returns: + * String: the svg string of the triangle + ''' + str_line = '' + str_line = '\t\n' + str_line = str_line + '\t '+time+': '+label+'\n' + return str_line + +def svg_string_draw_adv(x, y, label) : + ''' + Constructs the svg html string to draw at a dash, meaning that logical time is advancing there. + + Args: + * x: Int X coordinate of the dash + * y: Int Y coordinate of the dash + * label: String to draw + Returns: + * String: the svg string of the triangle + ''' + str_line1 = svg_string_draw_line(x-5, y, x+5, y, "ADV") + str_line2 = svg_string_draw_side_label(x, y, label) + return str_line1 + str_line2 + + +################################################################################ +### Routines to process lft and csv files +################################################################################ + def load_and_process_csv_file(csv_file) : ''' Loads and processes the csv entries, based on the type of the actor (if RTI @@ -84,13 +344,120 @@ def load_and_process_csv_file(csv_file) : df['inout'] = df['event'].apply(lambda e: 'in' if 'Receiving' in e else 'out') # Prune event names - df['event'] = df['event'].apply(lambda e: fhlp.prune_event_name[e]) + df['event'] = df['event'].apply(lambda e: prune_event_name[e]) return df +def command_is_in_path(command): + ''' + Checks if a command is in the PATH. + + Args: + * command: The command to check. + Returns: + * True if the command is in the PATH, False otherwise. + ''' + # Get the PATH environment variable. + path = os.environ["PATH"] + + # Split the PATH into a list of directories. + directories = path.split(os.pathsep) + + # Check if the command is in the list of directories. + for directory in directories: + if os.path.isdir(directory): + if command in os.listdir(directory): + return True + return False + +def convert_lft_file_to_csv(lft_file): + ''' + Call trace_to_csv command to convert the given binary lft trace file to csv format. + + Args: + * lft_file: the lft trace file + Return: + * File: the converted csv file, if the conversion succeeds, and empty string otherwise. + * String: the error message, in case the conversion did not succeed, and empty string otherwise. + ''' + convert_process = subprocess.run(['trace_to_csv', lft_file], stdout=subprocess.DEVNULL) + + if (convert_process.returncode == 0): + csv_file = os.path.splitext(lft_file)[0] + '.csv' + return csv_file, '' + else: + return '', str(convert_process.stderr) + +def get_and_convert_lft_files(rti_lft_file, federates_lft_files): + ''' + Check if the passed arguments are valid, in the sense that the files do exist. + If not arguments were passed, then look up the local lft files. + Then, convert to csv. + + Args: + * File: the argument passed at the command line as the rti lft trace file. + * Array: the argument passed at the command line as array of federates lft trace files. + Return: + * File: the converted RTI trace csv file, or empty, if no RTI trace lft file is found + * Array: Array of files of converted federates trace csv files + ''' + if (not rti_lft_file and not federates_lft_files): + federates_lft_files = [] + + for file in os.listdir(): + if (file == 'rti.lft'): + rti_lft_file = 'rti.lft' + elif (file.endswith('.lft')): + federates_lft_files.append(file) + else: + # If files were given, then check they exist + if (rti_lft_file): + if (not os.path.exists(rti_lft_file)): + print('Warning: Trace file ' + rti_lft_file + ' does not exist! Will resume though') + else: + for file in federates_lft_files: + if (not os.path.exists(file)): + print('Warning: Trace file ' + file + ' does not exist! Will resume though') + + # Sanity check that there is at least one lft file! + if (not rti_lft_file and not federates_lft_files): + print('Fedsd: Error: No lft files found. Abort!') + sys.exit(1) + + # Now, convert lft files to csv + if (rti_lft_file): + rti_csv_file, error = convert_lft_file_to_csv(rti_lft_file) + if (not rti_csv_file): + print('Fedsf: Error converting the RTI\'s lft file: ' + error) + else: + print('Fedsd: Successfully converted trace file ' + rti_lft_file + ' to ' + rti_csv_file + '.') + + federates_csv_files = [] + for file in federates_lft_files: + fed_csv_file, error = convert_lft_file_to_csv(file) + if (not fed_csv_file): + print('Fedsf: Error converting the federate lft file ' + file + ': ' + error) + else: + print('Fedsd: Successfully converted trace file ' + file + ' to ' + fed_csv_file + '.') + federates_csv_files.append(fed_csv_file) + + return rti_csv_file, federates_csv_files + +################################################################################ +### Main program to run +################################################################################ if __name__ == '__main__': args = parser.parse_args() + # Check that trace_to_csv is in PATH + if (not command_is_in_path('trace_to_csv')): + print('Fedsd: Error: trace_to_csv utility is not in PATH. Abort!') + sys.exit(1) + + # Look up the lft files and transform them to csv files + + rti_csv_file, federates_csv_files = get_and_convert_lft_files(args.rti, args.federates) + # The RTI and each of the federates have a fixed x coordinate. They will be # saved in a dict x_coor = {} @@ -110,11 +477,8 @@ def load_and_process_csv_file(csv_file) : #### Federates trace processing ############################################################################ # Loop over the given list of federates trace files - if (args.federates) : - for fed_trace in args.federates[0]: - if (not exists(fed_trace)): - print('Warning: Trace file ' + fed_trace + ' does not exist! Will resume though') - continue + if (federates_csv_files) : + for fed_trace in federates_csv_files: try: fed_df = load_and_process_csv_file(fed_trace) except Exception as e: @@ -137,8 +501,8 @@ def load_and_process_csv_file(csv_file) : ############################################################################ #### RTI trace processing, if any ############################################################################ - if (exists(args.rti)): - rti_df = load_and_process_csv_file(args.rti) + if (rti_csv_file): + rti_df = load_and_process_csv_file(rti_csv_file) rti_df['x1'] = x_coor[-1] else: # If there is no RTI, derive one. @@ -271,17 +635,17 @@ def load_and_process_csv_file(csv_file) : for key in x_coor: title = actors_names[key] if (key == -1): - f.write(fhlp.svg_string_comment('RTI Actor and line')) + f.write(svg_string_comment('RTI Actor and line')) center = 15 else: - f.write(fhlp.svg_string_comment('Federate '+str(key)+': ' + title + ' Actor and line')) + f.write(svg_string_comment('Federate '+str(key)+': ' + title + ' Actor and line')) center = 5 - f.write(fhlp.svg_string_draw_line(x_coor[key], math.ceil(padding/2), x_coor[key], svg_height, False)) + f.write(svg_string_draw_line(x_coor[key], math.ceil(padding/2), x_coor[key], svg_height, False)) f.write('\t\n') f.write('\t'+title+'\n') # Now, we need to iterate over the traces to draw the lines - f.write(fhlp.svg_string_comment('Draw interactions')) + f.write(svg_string_comment('Draw interactions')) for index, row in trace_df.iterrows(): # For time labels, display them on the left for the RTI, right for everthing else. anchor = 'start' @@ -298,11 +662,11 @@ def load_and_process_csv_file(csv_file) : label = row['event'] + '(' + f'{int(row["logical_time"]):,}' + ', ' + str(row['microstep']) + ')' if (row['arrow'] == 'arrow'): - f.write(fhlp.svg_string_draw_arrow(row['x1'], row['y1'], row['x2'], row['y2'], label, row['event'])) + f.write(svg_string_draw_arrow(row['x1'], row['y1'], row['x2'], row['y2'], label, row['event'])) if (row['inout'] in 'in'): - f.write(fhlp.svg_string_draw_side_label(row['x2'], row['y2'], physical_time, anchor)) + f.write(svg_string_draw_side_label(row['x2'], row['y2'], physical_time, anchor)) else: - f.write(fhlp.svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) + f.write(svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) elif (row['arrow'] == 'dot'): if (row['inout'] == 'in'): label = "(in) from " + str(row['partner_id']) + ' ' + label @@ -310,16 +674,16 @@ def load_and_process_csv_file(csv_file) : label = "(out) to " + str(row['partner_id']) + ' ' + label if (anchor == 'end'): - f.write(fhlp.svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) - f.write(fhlp.svg_string_draw_dot(row['x1'], row['y1'], label)) + f.write(svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) + f.write(svg_string_draw_dot(row['x1'], row['y1'], label)) else: - f.write(fhlp.svg_string_draw_dot_with_time(row['x1'], row['y1'], physical_time, label)) + f.write(svg_string_draw_dot_with_time(row['x1'], row['y1'], physical_time, label)) elif (row['arrow'] == 'marked'): - f.write(fhlp.svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) + f.write(svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor)) elif (row['arrow'] == 'adv'): - f.write(fhlp.svg_string_draw_adv(row['x1'], row['y1'], label)) + f.write(svg_string_draw_adv(row['x1'], row['y1'], label)) f.write('\n\n\n') @@ -329,3 +693,4 @@ def load_and_process_csv_file(csv_file) : # Write to a csv file, just to double check trace_df.to_csv('all.csv', index=True) + print('Fedsd: Successfully generated the sequence diagram in trace_svg.html.') diff --git a/util/tracing/visualization/fedsd_helper.py b/util/tracing/visualization/fedsd_helper.py deleted file mode 100644 index 37b339669..000000000 --- a/util/tracing/visualization/fedsd_helper.py +++ /dev/null @@ -1,255 +0,0 @@ -import math - -# Disctionary for pruning event names. Usefule for tracepoint matching and -# communication rendering -prune_event_name = { - "Sending ACK": "ACK", - "Sending TIMESTAMP": "TIMESTAMP", - "Sending NET": "NET", - "Sending LTC": "LTC", - "Sending STOP_REQ": "STOP_REQ", - "Sending STOP_REQ_REP": "STOP_REQ_REP", - "Sending STOP_GRN": "STOP_GRN", - "Sending FED_ID": "FED_ID", - "Sending PTAG": "PTAG", - "Sending TAG": "TAG", - "Sending REJECT": "REJECT", - "Sending RESIGN": "RESIGN", - "Sending PORT_ABS": "ABS", - "Sending CLOSE_RQ": "CLOSE_RQ", - "Sending TAGGED_MSG": "T_MSG", - "Sending P2P_TAGGED_MSG": "P2P_T_MSG", - "Sending MSG": "MSG", - "Sending P2P_MSG": "P2P_MSG", - "Sending ADR_AD": "ADR_AD", - "Sending ADR_QR": "ADR_QR", - "Receiving ACK": "ACK", - "Receiving TIMESTAMP": "TIMESTAMP", - "Receiving NET": "NET", - "Receiving LTC": "LTC", - "Receiving STOP_REQ": "STOP_REQ", - "Receiving STOP_REQ_REP": "STOP_REQ_REP", - "Receiving STOP_GRN": "STOP_GRN", - "Receiving FED_ID": "FED_ID", - "Receiving PTAG": "PTAG", - "Receiving TAG": "TAG", - "Receiving REJECT": "REJECT", - "Receiving RESIGN": "RESIGN", - "Receiving PORT_ABS": "ABS", - "Receiving CLOSE_RQ": "CLOSE_RQ", - "Receiving TAGGED_MSG": "T_MSG", - "Receiving P2P_TAGGED_MSG": "P2P_T_MSG", - "Receiving MSG": "MSG", - "Receiving P2P_MSG": "P2P_MSG", - "Receiving ADR_AD": "ADR_AD", - "Receiving ADR_QR": "ADR_QR", - "Receiving UNIDENTIFIED": "UNIDENTIFIED", - "Scheduler advancing time ends": "AdvLT" -} - -prune_event_name.setdefault(" ", "UNIDENTIFIED") - -################################################################################ -### Routines to write to csv file -################################################################################ - -def svg_string_draw_line(x1, y1, x2, y2, type=''): - ''' - Constructs the svg html string to draw a line from (x1, y1) to (x2, y2). - - Args: - * x1: Int X coordinate of the source point - * y1: Int Y coordinate of the source point - * x2: Int X coordinate of the sink point - * y2: Int Y coordinate of the sink point - * type: The type of the message (for styling) - Returns: - * String: the svg string of the lineĀ© - ''' - str_line = '\t\n' - return str_line - - -def svg_string_draw_arrow_head(x1, y1, x2, y2, type='') : - ''' - Constructs the svg html string to draw the arrow end - - Args: - * x1: Int X coordinate of the source point - * y1: Int Y coordinate of the source point - * x2: Int X coordinate of the sink point - * y2: Int Y coordinate of the sink point - * type: The type (for styling) - Returns: - * String: the svg string of the triangle - ''' - - if (y2 != y1): - rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90 - else: - if (x1 > x2): - rotation = 0 - else: - rotation = - 180 - - style = '' - if (type): - style = ' class="'+type+'"' - - str_line = '' - if (x1 > x2) : - str_line = '\t\n' - else : - str_line = '\t\n' - - return str_line - - -def svg_string_draw_label(x1, y1, x2, y2, label) : - ''' - Computes the rotation angle of the text and then constructs the svg string. - - Args: - * x1: Int X coordinate of the source point - * y1: Int Y coordinate of the source point - * x2: Int X coordinate of the sink point - * y2: Int Y coordinate of the sink point - * label: The label to draw - Returns: - * String: the svg string of the text - ''' - # FIXME: Need further improvement, based of the position of the arrows - # FIXME: Rotation value is not that accurate. - if (x2 < x1) : - # Left-going arrow. - if (y2 != y1): - rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90 - else: - rotation = 0 - - str_line = '\t'+label+'\n' - else : - # Right-going arrow. - if (y2 != y1): - rotation = - math.ceil(math.atan((x1-x2)/(y1-y2)) * 180 / 3.14) + 90 - else: - rotation = 0 - str_line = '\t'+label+'\n' - #print('rot = '+str(rotation)+' x1='+str(x1)+' y1='+str(y1)+' x2='+str(x2)+' y2='+str(y2)) - return str_line - - -def svg_string_draw_arrow(x1, y1, x2, y2, label, type=''): - ''' - Constructs the svg html string to draw the arrow from (x1, y1) to (x2, y2). - The arrow end is constructed, together with the label - - Args: - * x1: Int X coordinate of the source point - * y1: Int Y coordinate of the source point - * x2: Int X coordinate of the sink point - * y2: Int Y coordinate of the sink point - * label: String Label to draw on top of the arrow - * type: The type of the message - Returns: - * String: the svg string of the arrow - ''' - str_line1 = svg_string_draw_line(x1, y1, x2, y2, type) - str_line2 = svg_string_draw_arrow_head(x1, y1, x2, y2, type) - str_line3 = svg_string_draw_label(x1, y1, x2, y2, label) - return str_line1 + str_line2 + str_line3 - -def svg_string_draw_side_label(x, y, label, anchor="start") : - ''' - Put a label to the right of the x, y point, - unless x is small, in which case put it to the left. - - Args: - * x: Int X coordinate of the source point - * y: Int Y coordinate of the source point - * label: Label to put by the point. - * anchor: One of "start", "middle", or "end" to specify the text-anchor. - Returns: - * String: the svg string of the text - ''' - offset = 5 - if (anchor == 'end'): - offset = -5 - elif (anchor == 'middle'): - offset = 0 - str_line = '\t'+label+'\n' - - return str_line - -def svg_string_comment(comment): - ''' - Constructs the svg html string to write a comment into an svg file. - - Args: - * comment: String Comment to add - Returns: - * String: the svg string of the comment - ''' - str_line = '\n\t\n' - return str_line - - -def svg_string_draw_dot(x, y, label) : - ''' - Constructs the svg html string to draw at a dot. - - Args: - * x: Int X coordinate of the dot - * y: Int Y coordinate of the dot - * label: String to draw - Returns: - * String: the svg string of the triangle - ''' - str_line = '' - str_line = '\t\n' - str_line = str_line + '\t'+label+'\n' - return str_line - -def svg_string_draw_dot_with_time(x, y, time, label) : - ''' - Constructs the svg html string to draw at a dot with a prefixed physical time. - - Args: - * x: Int X coordinate of the dot - * y: Int Y coordinate of the dot - * time: The time - * label: String to draw - Returns: - * String: the svg string of the triangle - ''' - str_line = '' - str_line = '\t\n' - str_line = str_line + '\t '+time+': '+label+'\n' - return str_line - -def svg_string_draw_adv(x, y, label) : - ''' - Constructs the svg html string to draw at a dash, meaning that logical time is advancing there. - - Args: - * x: Int X coordinate of the dash - * y: Int Y coordinate of the dash - * label: String to draw - Returns: - * String: the svg string of the triangle - ''' - str_line1 = svg_string_draw_line(x-5, y, x+5, y, "ADV") - str_line2 = svg_string_draw_side_label(x, y, label) - return str_line1 + str_line2