Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fedsd utility updated to make the RTI optional and support enclaves visualization #1870

Merged
merged 9 commits into from
Jun 29, 2023
5 changes: 2 additions & 3 deletions util/scripts/launch-fedsd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ rti_csv_file=''
for each_lft_file in $lft_files_list
do
# Tranform to csv
trace_to_csv $each_lft_file
${base}/bin/trace_to_csv $each_lft_file
# Get the file name
csv=${each_lft_file%.*}
if [ $csv == 'rti' ]
Expand All @@ -93,9 +93,8 @@ for each_lft_file in $lft_files_list
# echo $csv_files_list

# FIXME: Check that python3 is in the path.
if [ $rti_csv_file == '' ]
if [ ! -z $rti_csv_file ]
then
# FIXME: Support the case where no rti file is given
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
Expand Down
66 changes: 44 additions & 22 deletions util/tracing/visualization/fedsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def load_and_process_csv_file(csv_file) :
# Remove all the lines that do not contain communication information
# which boils up to having 'RTI' in the 'event' column
df = df[df['event'].str.contains('Sending|Receiving|Scheduler advancing time ends') == True]

# Fix the parameters of the event 'Scheduler advancing time ends'
# We rely on the fact that the first row of the csv file cannot be the end of advancing time
id = df.iloc[-1]['self_id']
df['self_id'] = id
df = df.astype({'self_id': 'int', 'partner_id': 'int'})

# Add an inout column to set the arrow direction
Expand All @@ -86,28 +91,20 @@ def load_and_process_csv_file(csv_file) :
if __name__ == '__main__':
args = parser.parse_args()

# Check if the RTI trace file exists
if (not exists(args.rti)):
print('Error: No RTI csv trace file! Specify with -r argument.')
exit(1)

# The RTI and each of the federates have a fixed x coordinate. They will be
# saved in a dict
x_coor = {}
actors = []
actors_names = {}
padding = 50
spacing = 200 # Spacing between federates

############################################################################
#### RTI trace processing
############################################################################
trace_df = load_and_process_csv_file(args.rti)

# Set the RTI x coordinate
x_coor[-1] = padding * 2
actors.append(-1)
actors_names[-1] = "RTI"
# Temporary use
trace_df['x1'] = x_coor[-1]

trace_df = pd.DataFrame()

############################################################################
#### Federates trace processing
Expand All @@ -118,20 +115,45 @@ def load_and_process_csv_file(csv_file) :
if (not exists(fed_trace)):
print('Warning: Trace file ' + fed_trace + ' does not exist! Will resume though')
continue
fed_df = load_and_process_csv_file(fed_trace)
try:
fed_df = load_and_process_csv_file(fed_trace)
except Exception as e:
print(f"Warning: Problem processing trace file {fed_trace}: `{e}`")
continue

if (not fed_df.empty):
# Get the federate id number
fed_id = fed_df.iloc[-1]['self_id']
# Add to the list of sequence diagram actors and add the name
actors.append(fed_id)
actors_names[fed_id] = Path(fed_trace).stem
# Derive the x coordinate of the actor
x_coor[fed_id] = (padding * 2) + (spacing * (len(actors)-1))
x_coor[fed_id] = (padding * 2) + (spacing * (len(actors) - 1))
fed_df['x1'] = x_coor[fed_id]
# Append into trace_df
trace_df = pd.concat([trace_df, fed_df])
fed_df = fed_df[0:0]


############################################################################
#### RTI trace processing, if any
############################################################################
if (exists(args.rti)):
rti_df = load_and_process_csv_file(args.rti)
rti_df['x1'] = x_coor[-1]
else:
# If there is no RTI, derive one.
# This is particularly useful for tracing enclaves
# FIXME: Currently, `fedsd` is used either for federates OR enclaves.
# As soon as there is a consensus on how to visualize federations where
# a federate has several enclves, the utility will be updated.
rti_df = trace_df[['event', 'self_id', 'partner_id', 'logical_time', 'microstep', 'physical_time', 'inout']].copy()
rti_df = rti_df[rti_df['event'].str.contains('AdvLT') == False]
rti_df.columns = ['event', 'partner_id', 'self_id', 'logical_time', 'microstep', 'physical_time', 'inout']
rti_df['inout'] = rti_df['inout'].apply(lambda e: 'in' if 'out' in e else 'out')
rti_df['x1'] = rti_df['self_id'].apply(lambda e: x_coor[int(e)])

trace_df = pd.concat([trace_df, rti_df])

# Sort all traces by physical time and then reset the index
trace_df = trace_df.sort_values(by=['physical_time'])
trace_df = trace_df.reset_index(drop=True)
Expand Down Expand Up @@ -210,26 +232,23 @@ def load_and_process_csv_file(csv_file) :
if (matching_df.empty) :
# If no matching receiver, than set the arrow to 'dot',
# meaning that only a dot will be rendered
trace_df.loc[index, 'arrow'] = 'dot'
trace_df.at[index, 'arrow'] = 'dot'
else:
# If there is one or more matching rows, then consider
# the first one
matching_index = matching_df.index[0]
matching_row = matching_df.loc[matching_index]
if (inout == 'out'):
matching_index = matching_df.index[0]
matching_row = matching_df.loc[matching_index]
trace_df.at[index, 'x2'] = matching_row['x1']
trace_df.at[index, 'y2'] = matching_row['y1']
else:
matching_index = matching_df.index[-1]
matching_row = matching_df.loc[matching_index]
trace_df.at[index, 'x2'] = trace_df.at[index, 'x1']
trace_df.at[index, 'y2'] = trace_df.at[index, 'y1']
trace_df.at[index, 'x1'] = matching_row['x1']
trace_df.at[index, 'y1'] = matching_row['y1']

# Mark it, so not to consider it anymore
trace_df.at[matching_index, 'arrow'] = 'marked'

trace_df.at[index, 'arrow'] = 'arrow'

############################################################################
Expand Down Expand Up @@ -280,7 +299,10 @@ def load_and_process_csv_file(csv_file) :

if (row['arrow'] == 'arrow'):
f.write(fhlp.svg_string_draw_arrow(row['x1'], row['y1'], row['x2'], row['y2'], label, row['event']))
f.write(fhlp.svg_string_draw_side_label(row['x1'], row['y1'], physical_time, anchor))
if (row['inout'] in 'in'):
f.write(fhlp.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))
elif (row['arrow'] == 'dot'):
if (row['inout'] == 'in'):
label = "(in) from " + str(row['partner_id']) + ' ' + label
Expand Down
20 changes: 17 additions & 3 deletions util/tracing/visualization/fedsd_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ def svg_string_draw_arrow_head(x1, y1, x2, y2, type='') :
* String: the svg string of the triangle
'''

rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90
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+'"'
Expand Down Expand Up @@ -125,11 +132,18 @@ def svg_string_draw_label(x1, y1, x2, y2, label) :
# FIXME: Rotation value is not that accurate.
if (x2 < x1) :
# Left-going arrow.
rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90
if (y2 != y1):
rotation = - math.ceil(math.atan((x2-x1)/(y2-y1)) * 180 / 3.14) - 90
else:
rotation = 0

str_line = '\t<text text-anchor="end" transform="translate('+str(x1-10)+', '+str(y1-5)+') rotate('+str(rotation)+')">'+label+'</text>\n'
else :
# Right-going arrow.
rotation = - math.ceil(math.atan((x1-x2)/(y1-y2)) * 180 / 3.14) + 90
if (y2 != y1):
rotation = - math.ceil(math.atan((x1-x2)/(y1-y2)) * 180 / 3.14) + 90
else:
rotation = 0
str_line = '\t<text transform="translate('+str(x1+10)+', '+str(y1-5)+') rotate('+str(rotation)+')" text-anchor="start">'+label+'</text>\n'
#print('rot = '+str(rotation)+' x1='+str(x1)+' y1='+str(y1)+' x2='+str(x2)+' y2='+str(y2))
return str_line
Expand Down