输入文件
输入/输出串流的默认位宽为 32 位。位宽用于指定仿真输入文件上每行的样本数。输入文件的每一行上样本的解读取决于期望的数据类型和 PLIO 数据宽度。下表根据数据类型及其对应的 PLIO 接口规范,显示了输入数据文件中的样本解读方式。
数据类型 | PLIO 32 位 | PLIO 64 位 | PLIO 128 位 |
---|---|---|---|
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 个值。例如: 6 8 3 2 |
每行 8 个值。例如: 6 8 3 2 6 8 3 2 |
每行 16 个值。例如: 6 8 3 2 6 8 3 2 6 8 3 2 6 8 3 2 |
int16 | 每行 2 个值。例如: 24 18 |
每行 4 个值。例如: 24 18 24 18 |
每行 8 个值。例如: 24 18 24 18 24 18 24 18 |
int32 | 每行 1 个值 2386 |
每行 2 个值。例如: 2386 2386 |
每行 4 个值。例如: 2386 2386 2386 2386 |
int64 | 不适用 | 45678 | 每行 2 个值。例如: 45678 95578 |
cint16 | 每行 1 个 cint 值:实数,虚数。例如: 1980 485 |
每行 2 个 cint 值。例如: 1980 45 180 85 |
每行 4 个 cint 值。例如: 1980 485 180 85 980 48 190 45 |
cint32 | 不适用 | 每行 1 个 cint 值:实数,虚数。例如: 1980 485 |
每行 2 个 cint 值。例如: 1980 45 180 85 |
float | 每行 1 个浮点值。例如: 893.5689 |
每行 2 个浮点值。例如: 893.5689 3459.3452 |
每行 4 个浮点值。例如: 893.5689 39.32 459.352 349.345 |
cfloat | 不适用 | 每行 1 个浮点 cfloat 值:实数,虚数。例如: 893.5689 24156.456 |
每行 2 个浮点 cfloat 值:实数,虚数。例如: 893.5689 24156.456 93.689 256.46 |
PLIO 和包串流接口要求
当 TXT 文件用于提供表示 PLIO 端口和包串流接口的数据时,应遵循以下 TXT 文件要求。
-
tkeep
始终有效。不支持将tkeep
信号设置为 False。 - 根据接口宽度,一行中的多个数据样本可以合并发送。第一个数据样本在接口的最低位中发送。例如,如果数据类型为 int16 且 AI 引擎到 PL 接口位宽为 64 位,那么
0 1 2 3
行作为0x0003000200010000
发送到 AI 引擎。0 1 2 3
- TXT 文件中的
tlast
表示以下行的tlast
等于 1。如果tlast
为 1,那么发送到 AI 引擎的数据样本数可等于或小于 AI 引擎到 PL 接口的宽度。例如,如果数据类型为 int16 且 AI 引擎到 PL 接口位宽为 64 位,那么最后一行的4 5
作为0x00050004
随tlast
一并发送到 AI 引擎:0 1 2 3 tlast 4 5
- 对于包串流接口,
tlast
等于 1 表示包结束。包的报头应以无符号十进制格式来指定。例如,如果 AI 引擎到 PL 接口位宽为 64 位,那么以下行会发送包报头0x8fff0000
(无符号十进制下为 2415853568):tlast 2415853568
如果包串流接口的数据类型为 64 位,且 AI 引擎到 PL 接口位宽为 64 位,那么以下行会向 AI 引擎发送包报头0x8fff0000
、包数据0x0
,然后发送包数据0xfffeffff
:2415853568 0 tlast -1 -2
输出文件
在每个输出 PLIO 端口上,仿真器可使用与输入 PLIO 数据文件相同类型的声明来自动创建包含串流内容的文件。
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");
- 皮秒 (ps)
- 纳秒 (ns)
- 微秒 (us)
- 毫秒 (ms)
- 秒 (s)
如果串流的来源是在每一帧末尾生成的 TLAST 标记,那么此 TLAST 也会写入输出文件。以下提供了此类输出文件示例。
...
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
...
- 时间戳
- TLAST 和 TKEEP
- 样本 DATA 值
您可基于输出来为此 PLIO 端口估算设计吞吐量。时间戳仅与有效输出相关。当 PLIO 端口处于静默状态时,输出文件上没有任何指示信息。
吞吐量计算方式为输出样本数除以时间戳差值:
如果不考虑最后一个输出样本之后发生的所有时钟周期,那么此简单公式将过高估算吞吐量。
- 帧 0 输出(tstart_0 到 tend_0)
- 帧间静默
- 帧 1 输出(tstart_1 到 tend_1)
- 帧间静默
- ...
- 帧 N-1 输出(tstart_N-1 到 tend_N-1)
- 帧间静默
- 帧 N 输出(tstart_N 到 tend_N)
在此情况下,您必须考虑每个帧输出的帧间耗用时间。如果您仅使用前 N 个帧(从 0 到 N-1),那么这是可行的。在此情况下,请将吞吐量公式的时间戳替换为:
-
FirstTimestamp = tstart_0
-
LastTimestamp = tstart_N
(最后一帧的第一个输出时间戳)
以下提供了计算 PLIO 吞吐量的 Python 脚本示例,其中对仿真输出文件进行了分析并对吞吐量进行了计算。
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)