Simulation Input and Output Data Streams - 2023.1 English

AI Engine Tools and Flows User Guide (UG1076)

Document ID
UG1076
Release Date
2023-06-23
Version
2023.1 English

Simulation Input File

The default bit width for input/output streams is 32 bits. The bit width specifies the number of samples per line on the simulation input file. The interpretation of the samples on each line of the input file is dependent on the data type expected and the PLIO data width. The following table shows how the samples in the input data file are interpreted, depending on the data type and its corresponding PLIO interface specification.

Table 1. Simulation Input Data Dependency on Data Type and PLIO Width
Data Type PLIO 32 bit PLIO 64 bit PLIO 128 bit
adf::input_plio in = adf::input_plio::create("DataIn1", adf::plio_32_bits, "input.txt"); adf::input_plio in = adf::input_plio::create("DataIn1", adf::plio_64_bits, "input.txt"); adf::input_plio in = adf::input_plio::create("DataIn1", adf::plio_128_bits, "input.txt");
int8 4 values per line. For example:

6 8 3 2

8 values per line. For example:

6 8 3 2 6 8 3 2

16 values per line. For example:

6 8 3 2 6 8 3 2 6 8 3 2 6 8 3 2

int16 2 values per line. For example:

24 18

4 values per line. For example:

24 18 24 18

8 values per line. For example:

24 18 24 18 24 18 24 18

int32 Single value per line

2386

2 values per line. For example:

2386 2386

4 values per line. For example:

2386 2386 2386 2386

int64 N/A 45678 2 values per line. For example:

45678 95578

cint16 1 cint value per line – real, imaginary. For example:

1980 485

2 cint values per line. For example:

1980 45 180 85

4 cint values per line. For example:

1980 485 180 85 980 48 190 45

cint32 N/A 1 cint value per line – real, imaginary. For example:

1980 485

2 cint values per line. For example:

1980 45 180 85

float 1 floating point value per line. For example:

893.5689

2 floating point values per line. For example:

893.5689 3459.3452

4 floating point values per line. For example:

893.5689 39.32 459.352 349.345

cfloat N/A 1 floating point cfloat value per line, real, imaginary. For example:

893.5689 24156.456

2 floating point cfloat values per line, real, imaginary. For example:

893.5689 24156.456 93.689 256.46

Simulation Output File

On each output PLIO port a file containing the stream content can be created automatically by the simulator using the same type of declaration as the input PLIO data files:
adf::output_plio out1 = adf::output_plio::create("DataOut1",adf::plio_32_bits,"output1.txt");
adf::output_plio out2 = adf::output_plio::create("DataOut2",adf::plio_64_bits,"output2.txt");
adf::output_plio out3 = adf::output_plio::create("DataOut3",adf::plio_128_bits,"output3.txt");
The same format as the input applies for the output created file. Depending on the data type and the PLIO bitwidth, a number of data will be displayed on each line. Each output line is timestamped by the simulator so that you can estimate the data throughput during the simulation. The timestamp does not have a uniform time unit you can have:
  • picosecond (ps)
  • nanosecond (ns)
  • microsecond (us)
  • millisecond (ms)
  • second (s)
If the stream comes from a source that generates a TLAST flag at the end of a frame, this TLAST is also written in the output file. Below is an example of such an output file:

...
T 15984 ns
4552 4555 
T 15988 ns
4558 4561 
T 15992 ns
4564 4567 
T 15996 ns
4570 4573 
T 16 us
4576 4579 
T 16004 ns
4582 4585 
T 16008 ns
4588 4591 
T 16012 ns
4594 4597 
T 16016 ns
4600 4603 
T 16020 ns
4606 4609 
T 16024 ns
TLAST
4612 4615 
T 17940 ns
4618 4621 
T 17944 ns
4624 4627 
T 17948 ns
4630 4633 
T 17952 ns
...

As a summary each output of the PLIO port has the following format:
  • Timestamp
  • Optional TLAST
  • Sample values

From the output you can estimate the throughput of the designs for this PLIO port. Timestamps are related only to valid output. When the PLIO port is quiet, there is no indication on the output file.

Compute the throughput as the number of output samples divided by the timestamp difference:

Throughput = NumberOfSamples / (LastTimestamp - FirstTimestamp)

This simple equation will overestimate the throughput if you do not take into account all the clock cycles occuring after the last output sample.

This might be highly overestimated if this is a frame-based output. In that case, the output has the following format:
  • Frame 0 output (tstart_0 up to tend_0)
  • Quiet interframe
  • Frame 1 output (tstart_1 up to tend_1)
  • Quiet interframe
  • ...
  • Frame N-1 output (tstart_N-1 up to tend_N-1)
  • Quiet interframe
  • Frame N output (tstart_N up to tend_N)

In that case you have to take into account the interframe timelapse for each frame output. This can be done if you use only the N first frames (from 0 to N-1). In that case, replace the time stamps of the throughput equation with:

  • FirstTimestamp = tstart_0
  • LastTimestamp = tstart_N (the first output timestamp of the last frame)

Below is an example python script that calculates the PLIO throughput It analyzes the simulation output file and calculates the throughput.


import numpy as np
from math import *
import sys
import argparse

def GetTime_ns(Stamp):
  Time_ns = float(Stamp[1])
  if(Stamp[2] == 'ps'):
    Time_ns = Time_ns/1000.0
  elif(Stamp[2] == 'us'):
    Time_ns = Time_ns*1000.0
  elif(Stamp[2] == 'ms'):
    Time_ns = Time_ns*1000000.0
  elif(Stamp[2] == 's'):
    Time_ns = Time_ns*1000000000.0
  return(Time_ns)


def ReadFile(filename):
  # Detect the number of data per PLIO output
  fdr = open(filename,'r')
  ts = fdr.readline()
  d = fdr.readline()
  dw = d.split()
  fdr.close()


  coltime = 0
  coldata = 1
  numdata = len(dw)
  coltlast = numdata + 1


  # Initializes the output array
  # Format: timestamp (in ns) val1 val2 ... valN TLAST (0 or 1)
  a = np.zeros((0,numdata+2))
  fdr = open(filename,'r')
  line = ' '
  lnum = 0;

  while line !="" :
    line = fdr.readline()
    if line=='':
      continue
    res = line.split()

    if(res[0] != 'T'): # It should be a timestamp
      continue

    l = np.zeros((1,numdata+2))
    # Extract the time stamp
    l[0][0] = GetTime_ns(res)


    line = fdr.readline()
    res = line.split()
    # extract the TLAST
    if(res[0]=='TLAST'):
      tlast = 1
      line = fdr.readline()
      res = line.split()
    else:
      tlast = 0

    l[0,coltlast] = tlast
    # Extract all values
    for i in range(numdata):
      l[0,i+1] = float(res[i])

      # Appends to the whole array
      a = np.append( a , l,axis=0)

  fdr.close()
  return(a)

def Throughput(Filename,IsComplex):
  V = ReadFile(Filename)
  print("\n==============================")
  print(Filename)
  print("\n")

  NRows = V.shape[0]
  NCols = V.shape[1]
  NFullFrames = int(np.sum(V[:,NCols-1]))
  print("Number of Full Frames: " + str(NFullFrames))


  # Basic Throughput computation
  if IsComplex:
    Ratio = 0.5
  else:
    Ratio = 1
  RawThroughputMsps = float(NRows*(NCols-2))/(V[NRows-1,0]-V[0,0])*Ratio*1000.0
  print("Raw Throughput: %.2f" % RawThroughputMsps)

  # If the output is frame based, compute a more precise throughput
  tlast = np.where(V[:,NCols-1] == 1.0)
  if(len(tlast[0])<=1):
    TotalThroughput = RawThroughput
  else:
    tlast = tlast[0]
    EndRow = tlast[len(tlast)-2]+1
    # EndRow is the number of Rows I take into account for the number of datasource
    # The timestamp I am interested in is the timestamp of the next transaction
    TotalThroughputMsps = float(EndRow*(NCols-2))/(V[EndRow,0]-V[0,0])*Ratio*1000.0
    print(" Throughput: %.2f" % TotalThroughputMsps)

  print("\n")

# Entry point of this file
if __name__ == "__main__":
  parser = argparse.ArgumentParser(prog=sys.argv[0], description='Compute the throughput corresponding to some output of AIE Simulations')
  parser.add_argument('--iscomplex', action='store_true', help='Indicates Complex data in the file')
  parser.add_argument('filename',nargs='+')
  Args = sys.argv
  Args.pop(0)
  args = parser.parse_args(Args)

for f in args.filename:
  Throughput(f,args.iscomplex)