Repository: Xilinx/mlir-aie
Pull request #2245: Fix parse trace bug for repeat
Author: login: jackl-xilinx
Created: 2025-04-28T21:47:48Z | Merged: 2025-04-29T21:12:54Z



Diff:
diff --git a/programming_examples/basic/matrix_multiplication/makefile-common b/programming_examples/basic/matrix_multiplication/makefile-common
index b3aec79c2dd..48109db0eae 100644
--- a/programming_examples/basic/matrix_multiplication/makefile-common
+++ b/programming_examples/basic/matrix_multiplication/makefile-common
@@ -149,13 +149,13 @@ run: ${targetname}.exe ${xclbin_target}
 trace: ${targetname}.exe ${trace_xclbin_target} ${insts_target}
 	export XRT_HACK_UNSECURE_LOADING_XCLBIN=1 && \
 	${powershell} ./$< -x ${trace_xclbin_target} -i ${insts_target} -k MLIR_AIE -M $M -K $K -N $N ${runargs} -t ${trace_size}
-	${srcdir}/../../../utils/parse_trace.py --filename trace.txt --mlir ${trace_mlir_target} --colshift ${col_shift} > trace_mm.json
+	${srcdir}/../../../utils/parse_trace.py --input trace.txt --mlir ${trace_mlir_target} --colshift ${col_shift} --output trace_mm.json
 
 #	${powershell} ./$< -x ${trace_xclbin_target} -i ${insts_target} -k MLIR_AIE -M $M -K $K -N $N -v 1 --warmup 0 --iters 1 -t ${trace_size}
 
 .PHONY: parse_trace
 parse_trace:
-	${srcdir}/../../../utils/parse_trace.py --filename trace.txt --mlir ${trace_mlir_target} --colshift 1 > trace_mm.json
+	${srcdir}/../../../utils/parse_trace.py --input trace.txt --mlir ${trace_mlir_target} --colshift 1 --output trace_mm.json
 
 .PHONY: clean
 clean: clean_trace
diff --git a/programming_examples/basic/passthrough_kernel/Makefile b/programming_examples/basic/passthrough_kernel/Makefile
index cf6b3ad7b71..dc33b4d3f8a 100755
--- a/programming_examples/basic/passthrough_kernel/Makefile
+++ b/programming_examples/basic/passthrough_kernel/Makefile
@@ -83,13 +83,13 @@ run_py: build/final_${data_size}.xclbin build/insts_${data_size}.bin
 
 trace: ${targetname}_${data_size}.exe build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin
 	${powershell} ./$< -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie2_trace_lineBased_8b_${data_size}.mlir --colshift ${colshift} > trace_passthrough_kernel.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_passthrough_kernel.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie2_trace_lineBased_8b_${data_size}.mlir --colshift ${colshift} --output trace_passthrough_kernel.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_passthrough_kernel.json
 
 trace_py: build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin
 	${powershell} python3 ${srcdir}/test.py -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size} -i1s ${in1_size} -os ${out_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie2_trace_lineBased_8b_${data_size}.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie2_trace_lineBased_8b_${data_size}.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 clean_trace:
 	rm -rf tmpTrace trace.txt parse*json trace*json
diff --git a/programming_examples/basic/vector_reduce_add/Makefile b/programming_examples/basic/vector_reduce_add/Makefile
index ca21c00c01b..6146550a1e8 100644
--- a/programming_examples/basic/vector_reduce_add/Makefile
+++ b/programming_examples/basic/vector_reduce_add/Makefile
@@ -61,7 +61,7 @@ run: ${targetname}.exe build/final.xclbin
 	${powershell} ./$< -x build/final.xclbin -i build/insts.bin -k MLIR_AIE
 
 trace:
-	../../utils/parse_eventIR.py --filename trace.txt --mlir build/aie.mlir --colshift $(colshift) > parse_eventIR_vs.json
+	../../utils/parse_trace.py --input trace.txt --mlir build/aie.mlir --colshift $(colshift) --output parse_eventIR_vs.json
 
 clean_trace:
 	rm -rf tmpTrace trace.txt
diff --git a/programming_examples/basic/vector_reduce_max/Makefile b/programming_examples/basic/vector_reduce_max/Makefile
index 6210bc850dc..540092a7af4 100755
--- a/programming_examples/basic/vector_reduce_max/Makefile
+++ b/programming_examples/basic/vector_reduce_max/Makefile
@@ -79,8 +79,8 @@ run_py: build/final.xclbin build/insts.bin
 
 trace: ${targetname}.exe build/final_trace.xclbin build/insts.bin 
 	${powershell} ./$< -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie2_trace.mlir --colshift ${colshift} > trace_vector_reduce_max.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_vector_reduce_max.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie2_trace.mlir --colshift ${colshift} --output trace_vector_reduce_max.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_vector_reduce_max.json
 
 clean_trace:
 	rm -rf tmpTrace trace.txt parse*json trace*json
diff --git a/programming_examples/basic/vector_reduce_min/Makefile b/programming_examples/basic/vector_reduce_min/Makefile
index d70a6ce6faa..4c042b9ae01 100755
--- a/programming_examples/basic/vector_reduce_min/Makefile
+++ b/programming_examples/basic/vector_reduce_min/Makefile
@@ -61,7 +61,7 @@ run: ${targetname}.exe build/final.xclbin
 	${powershell} ./$< -x build/final.xclbin -i build/insts.bin -k MLIR_AIE
 
 trace:
-	../../utils/parse_eventIR.py --filename trace.txt --mlir build/aie.mlir --colshift ${colshift} > parse_eventIR_vs.json
+	../../utils/parse_trace.py --input trace.txt --mlir build/aie.mlir --colshift ${colshift} --output parse_eventIR_vs.json
 
 clean_trace:
 	rm -rf tmpTrace trace.txt
diff --git a/programming_examples/basic/vector_scalar_mul/Makefile b/programming_examples/basic/vector_scalar_mul/Makefile
index e130a4e8d4b..846f8d1a2a6 100644
--- a/programming_examples/basic/vector_scalar_mul/Makefile
+++ b/programming_examples/basic/vector_scalar_mul/Makefile
@@ -101,13 +101,13 @@ run_py: build/final_${data_size}.xclbin build/insts_${data_size}.bin
 
 trace: ${targetname}_${data_size}.exe build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin 
 	${powershell} ./$< -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 trace_py: build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin
 	${powershell} python3 ${srcdir}/test.py -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size} -i1s ${in1_size} -i2s ${in2_size} -os ${out_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 
 clean_trace:
diff --git a/programming_examples/ml/conv2d/Makefile b/programming_examples/ml/conv2d/Makefile
index 2768ad01e50..52e35b9cbb2 100755
--- a/programming_examples/ml/conv2d/Makefile
+++ b/programming_examples/ml/conv2d/Makefile
@@ -97,8 +97,8 @@ run_py: build/final.xclbin
 
 trace_py: build/final_trace.xclbin
 	${powershell} python3 ${srcdir}/test.py -x build/final_trace.xclbin -i build/insts_trace.bin -k MLIR_AIE -wd ${width} -ht ${height} -ic ${in_channels} -oc ${out_channels} -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename log/trace_conv2d.txt --mlir build/aie2_trace.mlir --colshift ${colshift} > log/trace_conv2d.json
-	${srcdir}/../../utils/get_trace_summary.py --filename log/trace_conv2d.json
+	${srcdir}/../../utils/parse_trace.py --input log/trace_conv2d.txt --mlir build/aie2_trace.mlir --colshift ${colshift} --output log/trace_conv2d.json
+	${srcdir}/../../utils/get_trace_summary.py --input log/trace_conv2d.json
 
 clean:
 	rm -rf build *.elf* *.lst *.bif aie2.mlir.prj log* *.xclbin sim \
diff --git a/programming_examples/ml/eltwise_add/Makefile b/programming_examples/ml/eltwise_add/Makefile
index 3f9940e4c2a..b3e25918a4d 100644
--- a/programming_examples/ml/eltwise_add/Makefile
+++ b/programming_examples/ml/eltwise_add/Makefile
@@ -79,13 +79,13 @@ run: ${targetname}_${data_size}.exe build/final_${data_size}.xclbin build/insts_
 
 trace: ${targetname}_${data_size}.exe build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin 
 	${powershell} ./$< -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 trace_py: build/final_trace_${data_size}.xclbin build/insts_${data_size}.bin
 	${powershell} python3 ${srcdir}/test.py -x build/final_trace_${data_size}.xclbin -i build/insts_${data_size}.bin -k MLIR_AIE -t ${trace_size} -i1s ${in1_size} -i2s ${in2_size} -os ${out_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace_${data_size}.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 clean_trace:
 	rm -rf tmpTrace trace.txt parse*json trace*json
diff --git a/programming_examples/ml/eltwise_mul/Makefile b/programming_examples/ml/eltwise_mul/Makefile
index d646abe6817..036fc9a6674 100644
--- a/programming_examples/ml/eltwise_mul/Makefile
+++ b/programming_examples/ml/eltwise_mul/Makefile
@@ -75,8 +75,8 @@ run: ${targetname}.exe build/final.xclbin
 
 trace: ${targetname}.exe build/final_trace.xclbin
 	${powershell} ./$< -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} > trace_eltwise_mul.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_eltwise_mul.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} --output trace_eltwise_mul.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_eltwise_mul.json
 
 clean:
 	rm -rf build _build ${targetname}.exe
diff --git a/programming_examples/ml/relu/Makefile b/programming_examples/ml/relu/Makefile
index 23cb7557b0a..80038905dbf 100644
--- a/programming_examples/ml/relu/Makefile
+++ b/programming_examples/ml/relu/Makefile
@@ -76,8 +76,8 @@ run: ${targetname}.exe build/final.xclbin
 
 trace: ${targetname}.exe build/final_trace.xclbin
 	${powershell} ./$< -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} > trace_${targetname}.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_${targetname}.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} --output trace_${targetname}.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_${targetname}.json
 
 clean:
 	rm -rf build _build ${targetname}.exe
diff --git a/programming_examples/ml/softmax/Makefile b/programming_examples/ml/softmax/Makefile
index 42625d49a10..ba50991d223 100755
--- a/programming_examples/ml/softmax/Makefile
+++ b/programming_examples/ml/softmax/Makefile
@@ -102,8 +102,8 @@ profile: ${targetname}.exe build/final.xclbin
 
 trace: ${targetname}.exe build/final_trace.xclbin
 	${powershell} ./$< -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} > trace_softmax.json
-	${srcdir}/../../utils/get_trace_summary.py --filename trace_softmax.json
+	${srcdir}/../../utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} --output trace_softmax.json
+	${srcdir}/../../utils/get_trace_summary.py --input trace_softmax.json
 
 clean: 
 	rm -rf build _build ${targetname}.exe 
diff --git a/programming_examples/utils/README.md b/programming_examples/utils/README.md
index 01f8d6e2ae9..fb61b262869 100644
--- a/programming_examples/utils/README.md
+++ b/programming_examples/utils/README.md
@@ -36,12 +36,15 @@ Shell script to do in-place cleanup of microcode files (e.g. core_*.lst). When v
 The text file generated by the host code (`test.cpp` or `test.py`) are formatted as 32-bit hex values, one per line. This python script parses the raw trace packet data and creates a waveform json file for view on Perfetto http://ui.perfetto.dev. The script syntax is:
 
 ```bash
-parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift 1 > parse_eventIR_vs.json
+parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift 1 --output parse_eventIR_vs.json
 ```
 
 * **--filename** : Input trace packet text file. This is generated during the running of our python host code
 * **--mlir**     : MLIR source. This is needed to parse what events and tiles we are monitoring to generate labels for our waveform visualizer.
-* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
+* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. For npu devices (phoenix), this is typically 1 while npu2 (strix) uses 0.
+
+    **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
+* **--output** : output json file
 
 
 ## <u>Trace parser - eventIR based ([parse_eventIR.py](./parse_eventIR.py))</u>
@@ -52,9 +55,9 @@ The text file generated by the host code (`test.cpp` or `test.py`) are formatted
 The script syntax is:
 
 ```bash
-parse_eventIR.py --filename trace.txt --mlir build/aie_trace.mlir --colshift 1 > parse_eventIR_vs.json
+parse_eventIR.py --input trace.txt --mlir build/aie_trace.mlir --colshift 1 --output parse_eventIR_vs.json
 ```
-* **--filename** : Input trace packet text file. This is generated during the running of our python host code
+* **--input** : Input trace packet text file. This is generated during the running of our python host code
 * **--mlir**     : MLIR source. This is needed to parse what events and tiles we are monitoring to generate labels for our waveform visualizer.
 * **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
 
diff --git a/programming_examples/utils/clean_microcode.sh b/programming_examples/utils/clean_microcode.sh
index 1b2e24754ca..fc3c22e8148 100755
--- a/programming_examples/utils/clean_microcode.sh
+++ b/programming_examples/utils/clean_microcode.sh
@@ -4,5 +4,8 @@ sed -i ':a;N;$!ba;s/\.delay_slot\n//g' $1
 sed -i ':a;N;$!ba;s/\.swstall delay_slot\n//g' $1
 sed -i ':a;N;$!ba;s/\.no_stack_arguments\n//g' $1
 sed -i ':a;N;$!ba;s/\.swstall chess_separator_scheduler\n//g' $1
+sed -i ':a;N;$!ba;s/\.aggressive_scheduled_block_id [0-9]*\n//g' $1
+sed -i ':a;N;$!ba;s/\.aggressive_scheduled_block_id first\n//g' $1
+sed -i ':a;N;$!ba;s/\.aggressive_scheduled_block_id last\n//g' $1
 sed -i ':a;N;$!ba;s/\.noswbrkpt\n//g' $1
 sed -i ':a;N;$!ba;s/\.nohwbrkpt\n//g' $1
diff --git a/programming_examples/utils/get_trace_summary.py b/programming_examples/utils/get_trace_summary.py
index e761ef4a8ef..f71dec42bf9 100755
--- a/programming_examples/utils/get_trace_summary.py
+++ b/programming_examples/utils/get_trace_summary.py
@@ -8,7 +8,7 @@
 
 def parse_args():
     parser = argparse.ArgumentParser()
-    parser.add_argument("--filename", help="Trace file", required=True)
+    parser.add_argument("--input", help="Trace file", required=True)
     # parser.add_argument("--mlir", help="mlir source file", required=True)
     # parser.add_argument(
     #    "--colshift", help="column shift adjustment to source mlir", required=False
@@ -22,7 +22,7 @@ def parse_args():
 
 
 opts = parse_args()
-cycles = trace_utils.get_cycles_summary(opts.filename)
+cycles = trace_utils.get_cycles_summary(opts.input)
 
 print("Total number of full kernel invocations is " + str(len(cycles)))
 print(
diff --git a/programming_examples/utils/parse_trace.py b/programming_examples/utils/parse_trace.py
index a6b59edb30d..7045d9498b1 100755
--- a/programming_examples/utils/parse_trace.py
+++ b/programming_examples/utils/parse_trace.py
@@ -20,11 +20,12 @@
 
 def parse_args():
     parser = argparse.ArgumentParser()
-    parser.add_argument("--filename", help="Trace file", required=True)
+    parser.add_argument("--input", help="Input trace file", required=True)
     parser.add_argument("--mlir", help="mlir source file", required=True)
     parser.add_argument(
         "--colshift", help="column shift adjustment to source mlir", required=False
     )
+    parser.add_argument("--output", help="Output json file", required=True)
     parser.add_argument("--debug", help="debug mode", required=False)
     # TODO tracelabels removed since we can have multiple sets of labels for each pkt_type & loc combination
     # parser.add_argument('--tracelabels',
@@ -33,11 +34,14 @@ def parse_args():
     return parser.parse_args(sys.argv[1:])
 
 
-def check_for_valid_trace(filename, toks):
+# Check for valid trace packets data
+# 1) if only 1 trace packet
+# 2) if first trace packet is all 0's
+def check_for_valid_trace(filename, trace_pkts, of):
     if DEBUG:
-        print("len(toks): ", str(len(toks)))
-        print("toks[0]:", toks[0])
-    if len(toks) < 2 or toks[0] == "00000000":
+        print("len(trace_pkts): ", str(len(trace_pkts)), file=of)
+        print("trace_pkts[0]:", trace_pkts[0], file=of)
+    if len(trace_pkts) < 2 or trace_pkts[0] == "00000000":
         print(
             "[ERROR] Empty trace file. Valid trace was not written to",
             filename,
@@ -75,12 +79,15 @@ def parse_pkt_hdr_in_stream(word):
     return hdr
 
 
-# toks_list:   list (idx = types of traces, currently 4, value = stream_dict)
+# Sorts list of trace packets into a list indexed by trace type (core, mem, shim, memtile)
+# and the value is dictionary tile location (key) and trace packets (value)
+#
+# trace_pkts_sorted:   list (idx = types of traces, currently 4, value = stream_dict)
 # stream_dict: dict (key = row,col, value = list of word streams)
-def core_trace_and_mem_trace_de_interleave(word_stream):
-    toks_list = list()
+def trace_pkts_de_interleave(word_stream):
+    trace_pkts_sorted = list()
     for t in range(NumTraceTypes):
-        toks_list.append(dict())
+        trace_pkts_sorted.append(dict())
 
     # core_streams = dict()   # pkt type 0
     # mem_stream = dict()     # pkt type 1
@@ -106,8 +113,8 @@ def core_trace_and_mem_trace_de_interleave(word_stream):
                 for tt in range(NumTraceTypes):
                     if pkt_hdr["type"] == tt:
                         curr_pkt_type = tt
-                        if toks_list[tt].get(curr_loc) == None:
-                            toks_list[tt][curr_loc] = list()
+                        if trace_pkts_sorted[tt].get(curr_loc) == None:
+                            trace_pkts_sorted[tt][curr_loc] = list()
                         valid_type_found = True
                 if not valid_type_found:
                     sys.exit("Error: Invalid packet type")
@@ -118,15 +125,17 @@ def core_trace_and_mem_trace_de_interleave(word_stream):
                 curr_vld
             ):  # ignores first 8 chunks of data is pkt hdr was invalid. TODO Is this right?
                 # or shoudl we require valid header in first chunk of data
-                toks_list[curr_pkt_type][curr_loc].append(
+                trace_pkts_sorted[curr_pkt_type][curr_loc].append(
                     word_stream[i]
-                )  # TODO assuem curr_pkt_type is valid
+                )  # TODO assume curr_pkt_type is valid
                 # for tt in range(NumTraceTypes):
                 #     if curr_pkt_type == tt:
                 #         toks_list[tt][curr_loc].append(word_stream[i])
-    return toks_list
+    return trace_pkts_sorted
 
 
+# Convert trace packets into byte streams
+#
 # toks_list is a list of toks dictionaries where each dictionary is a type (core, mem, shim, memtile)
 # each dictionary key is a tile location (row,col) whose value is a list of stream data
 def convert_to_byte_stream(toks_list):
@@ -162,6 +171,8 @@ def convert_to_byte_stream(toks_list):
     return byte_stream_list
 
 
+# Convert byte streams to equivalent packet commands
+#
 # byte_stream_list: list (idx = trace type, value = word_stream_dict)
 # word_stream_dict: dict (key = row,col, value = list of words)
 #
@@ -366,43 +377,58 @@ def lookupEventNameInStr(event, pid, pid_events):
     #         return "Mm2s1FinishedTask"
 
 
-# multiples is a list of events that are being activated
-def deactivate(
+# This function assert an end event for all active events if:
+# 1) the cycles from the last event is > 0
+# 2) active event is not in list of new events (multiples)
+#
+# if cycles > 0, deactivate all events
+# if cycles == 0, deactivate all events except this one
+#
+# multiples - list of new active events
+# active_events - list of existing active events
+# timer - current running time
+# cycles - # of cycles from last event
+# pid -
+# trace_type -
+# loc -
+# pid_events -
+def deactivate_events(
     multiples, active_events, timer, cycles, pid, trace_type, loc, pid_events
 ):
     for k in active_events.keys():  # an active event
         if cycles > 0 or (cycles == 0 and not k in multiples):
             # if not k in multiples: # active event it not in multiples list
             if active_events[k] > 0:
-                # trace_event = {'name':"Event"+str(k)}
-                # trace_event = {'name':events_to_name[k]}
-                # trace_event = {'name':lookupEventNameInStr(str(k), pid, pid_events)}
-                # trace_event = {'name':lookup_event_name_by_type(trace_type, str(k), pid_events)} # TODO remove
                 trace_event = {
                     "name": lookup_event_name_by_type(
                         trace_type, pid_events[trace_type][loc][k]
                     )
                 }  # TODO remove
-                # trace_event['args']['name'] = lookup_event_name_by_type(trace_type, pid_events[trace_type][loc][k])
-                #                trace_event['ts'] = active_events[k]
                 trace_event["ts"] = timer
                 trace_event["ph"] = "E"
-                # trace_event['pid'] = 0
                 trace_event["pid"] = pid
                 trace_event["tid"] = k
                 trace_event["args"] = {}
-                # trace_event['keys'] = multiples
-                # trace_event['active_events'] = active_events.keys()
-                # trace_event['opcode'] = "Deactivate" + str(multiples)
-
                 trace_events.append(trace_event)
             active_events[k] = 0
 
 
-# def update(t):
-#     for k in active_events.keys():
-#         if active_events[k]:
-#             active_events[k] = t
+# Assert a begin siganl for the current event unless the event is still active
+def activate_event(event, tt, loc, timer, pid, active_events, pid_events, trace_events):
+    try:
+        if active_events[event] == 0:
+            trace_event = {
+                "name": lookup_event_name_by_type(tt, pid_events[tt][loc][event])
+            }
+            trace_event["ts"] = timer
+            trace_event["ph"] = "B"
+            trace_event["pid"] = pid
+            trace_event["tid"] = event
+            trace_event["args"] = {}
+            trace_events.append(trace_event)
+            active_events[event] = 1
+    except KeyError:
+        pass
 
 
 # def convert_commands_to_json(trace_events, commands, pid, pid_events):
@@ -410,7 +436,7 @@ def deactivate(
 #
 # commands:  list (idx = trace type, value = byte_stream_dict)
 # byte_stream_dict: dict (key = row,col, value = list of commands)
-def convert_commands_to_json(trace_events, commands, pid_events):
+def convert_commands_to_json(trace_events, commands, pid_events, of):
     # for bsd in commands: # byte_stream_dict for each trace type. TODO how to get index of bsd?
     for tt in range(
         len(commands)
@@ -428,8 +454,8 @@ def convert_commands_to_json(trace_events, commands, pid_events):
                     + ", loc: "
                     + str(loc)
                     + ", NUM_EVENTS: "
-                    + str(NUM_EVENTS)
-                    + "\n"
+                    + str(NUM_EVENTS),
+                    file=of,
                 )
 
             if loc in pid_events[tt]:
@@ -453,36 +479,20 @@ def convert_commands_to_json(trace_events, commands, pid_events):
                 sys.exit(1)
 
             active_events = dict()
-            for i in range(16):  # TODO we only have 8 events at a time though right?
+            for i in range(8):  # 8 max events at a time
                 active_events[i] = 0
 
+            if DEBUG:
+                print("num commands:", len(command), file=of)
             for c in command:
-                # for c in flat_commands:
-                # print(c)
                 t = c["type"]
-                # if 'Start' in t:
-                # timer = c['timer_value'] # TODO Turn off timer for now to test sync among tiles/type
-                # elif 'Single' in t:
                 if "Single" in t:
                     event = c["event"]
                     cycles = int(c["cycles"])
-
-                    # timer = timer + 1 + int(c['cycles'])   # Timer at top
                     timer = timer + 1
-
-                    # if cycles > 0, deactivate all events
-                    # if cycles == 0, deactivate all events except this one
-
-                    # TODO NO? deactivate all active_events that is not this event
                     multiple_list = list()
-                    # for k in c.keys():
-                    #     if "event" in k:
-                    #         multiple_list.append(c[k]) # TODO overkill since there should only be one?
                     multiple_list.append(c["event"])
-                    # for k in active_events.keys():
-                    #     if cycles > 0 or (cycles == 0 and k != event):
-                    #         multiple_list.append(k)
-                    deactivate(
+                    deactivate_events(
                         multiple_list,
                         active_events,
                         timer,
@@ -492,51 +502,26 @@ def convert_commands_to_json(trace_events, commands, pid_events):
                         loc,
                         pid_events,
                     )
-
                     timer = timer + cycles
+                    activate_event(
+                        event,
+                        tt,
+                        loc,
+                        timer,
+                        pid,
+                        active_events,
+                        pid_events,
+                        trace_events,
+                    )
 
-                    # If its already started, don't start it again ...
-                    try:
-                        if active_events[event] == 0:
-                            # trace_event = {'name':events_to_name[event]}
-                            # trace_event = {'name':lookupEventNameInStr(str(event), pid, pid_events)}
-                            # trace_event = {'name':lookupEventNameInStr(str(event), pid, pid_events)} # TODO
-                            trace_event = {
-                                "name": lookup_event_name_by_type(
-                                    tt, pid_events[tt][loc][event]
-                                )
-                            }
-                            trace_event["ts"] = timer
-                            trace_event["ph"] = "B"
-                            # trace_event['pid'] = 0
-                            trace_event["pid"] = pid
-                            trace_event["tid"] = event
-                            trace_event["args"] = {}
-                            # trace_event['opcode'] = "Single"
-                            trace_events.append(trace_event)
-                            #                active_events[event] = timer  + 1
-                            active_events[event] = 1
-                    except KeyError:
-                        pass
-                    # timer = timer + 1 + int(c['cycles'])
                 elif "Multiple" in t:
                     cycles = int(c["cycles"])
-
-                    # timer = timer + 1 + int(c['cycles'])
                     timer = timer + 1
-
-                    # if cycles > 0, deactivate all events
-                    # if cycles == 0, deactivate all events except this one
-
-                    # TODO NO? deactivate all active_events that is not this event
                     multiple_list = list()
                     for k in c.keys():
                         if "event" in k:
                             multiple_list.append(c[k])
-                    # for k in active_events.keys():
-                    #     if cycles > 0 or (cycles == 0 and k != event):
-                    #         multiple_list.append(k)
-                    deactivate(
+                    deactivate_events(
                         multiple_list,
                         active_events,
                         timer,
@@ -546,40 +531,62 @@ def convert_commands_to_json(trace_events, commands, pid_events):
                         loc,
                         pid_events,
                     )
-
                     timer = timer + cycles
 
                     for k in c.keys():
-                        if not "event" in k:
-                            continue
-                        # If its already started, don't start it again ...
-                        try:
-                            event = c[k]
-                            if active_events[event] == 0:
-                                # trace_event = {'name':events_to_name[event]}
-                                # trace_event = {'name':lookupEventNameInStr(str(event), pid, pid_events)} # TODO
-                                trace_event = {
-                                    "name": lookup_event_name_by_type(
-                                        tt, pid_events[tt][loc][event]
-                                    )
-                                }
-                                trace_event["ts"] = timer
-                                trace_event["ph"] = "B"
-                                # trace_event['pid'] = 0
-                                trace_event["pid"] = pid
-                                trace_event["tid"] = event
-                                trace_event["args"] = {}
-                                # trace_event['opcode'] = "Multiple" + str(list(c.keys()))
-                                trace_events.append(trace_event)
-                                #                    active_events[event] = timer  + 1
-                                active_events[event] = 1
-                        except KeyError:
-                            pass
-                    # timer = timer + 1 + int(c['cycles'])
+                        if "event" in k:
+                            activate_event(
+                                c[k],
+                                tt,
+                                loc,
+                                timer,
+                                pid,
+                                active_events,
+                                pid_events,
+                                trace_events,
+                            )
 
                 elif "Repeat" in t:
-                    timer = timer + int(c["repeats"])
-            #        update(timer)
+                    if (
+                        cycles == 0
+                    ):  # last event has cycles == 0 so we just extend it by the repaet count
+                        timer = timer + int(c["repeats"])
+                    else:
+                        deactivate_events(
+                            multiple_list,
+                            active_events,
+                            timer,
+                            cycles,
+                            pid,
+                            tt,
+                            loc,
+                            pid_events,
+                        )
+                        timer = timer + cycles
+                        if len(multiple_list) > 1:
+                            for k in c.keys():
+                                if "event" in k:
+                                    activate_event(
+                                        c[k],
+                                        tt,
+                                        loc,
+                                        timer,
+                                        pid,
+                                        active_events,
+                                        pid_events,
+                                        trace_events,
+                                    )
+                        else:
+                            activate_event(
+                                event,
+                                tt,
+                                loc,
+                                timer,
+                                pid,
+                                active_events,
+                                pid_events,
+                                trace_events,
+                            )
 
 
 def process_name_metadata(trace_events, pid, trace_type, loc):
@@ -972,157 +979,90 @@ def setup_trace_metadata(trace_events, pid_events):
 # set colshift based on optional argument
 colshift = int(opts.colshift) if opts.colshift else 0
 
-with open(opts.filename, "r") as f:
-    toks = f.read().split("\n")
-
-    if DEBUG:
-        print("\nDEBUG: toks")
-        print(toks)
-        print("\n\n")
-
-    if not check_for_valid_trace(opts.filename, toks):
-        sys.exit(1)
-
-    # De-interleave core and memory trace
-    # [core_toks, mem_toks] = core_trace_and_mem_trace_de_interleave(toks)
-
-    # TODO Change this to list of toks instead of a fixed set?
-    toks_list = core_trace_and_mem_trace_de_interleave(toks)
-
-    if DEBUG:
-        print("\nDEBUG: stream")
-        print(toks_list)
-        print("\n\n")
-
-    bs_0 = convert_to_byte_stream(toks_list)
-    # core_bs_0    = convert_to_byte_stream(core_toks)
-    # mem_bs_0     = convert_to_byte_stream(mem_toks)
-    # shim_bs_0   = convert_to_byte_stream(shim_toks)
-    # memtile_bs_0 = convert_to_byte_stream(memtile_toks)
-
-    if DEBUG:
-        print("\nDEBUG: byte stream")
-        print(bs_0)
-        print("\n\n")
-
-    # core_bs_1 = convert_to_byte_stream(core_toks[1])
-    # mem_bs_0 = convert_to_byte_stream(mem_toks[0])
-    # mem_bs_1 = convert_to_byte_stream(mem_toks[1])
-
-    commands_0 = convert_to_commands(bs_0, False)
-    # core_commands_0    = convert_to_commands(core_bs_0, False)
-    # mem_commands_0     = convert_to_commands(mem_bs_0, False)
-    # shim_commands_0   = convert_to_commands(shim_bs_0, False)
-    # memtile_commands_0 = convert_to_commands(memtile_bs_0, False)
-
-    # core_commands_1 = convert_to_commands(core_bs_1, False)
-    # mem_commands_0 = convert_to_commands(mem_bs_0, False)
-    # mem_commands_1 = convert_to_commands(mem_bs_1, False)
-
-if DEBUG:
-    print("\nDEBUG: commands_0")
-    print(commands_0)
-    print("\n\n")
+try:
+    with open(opts.input, "r") as f:
+        # Create array of trace packets
+        trace_pkts = f.read().split("\n")
+except:
+    print(
+        "ERROR:", opts.input, "could not be opened. Check for valid trace source file."
+    )
+    sys.exit(1)
 
-# pid_events track the labels associated with pkt_type/ trace and row,col
-#
-# pid_events: list(idx=pkt_type, value=labels_dict)
-# label_dict: dict(key=row,col, value=labels list)
-# labels_list: list(idx=label idx, value=label code), idx=len is pid
-#
 pid_events = list()
 
-if opts.mlir:
+try:
     with open(opts.mlir, "r") as mf:
         lines = mf.read().split("\n")
         pid_events = parse_mlir_trace_events(lines)
-# TODO need an else if mlir is not defined, some default or make it required?
-# else:
+except:
+    print("ERROR:", opts.mlir, "could not be opened. Check for valid MLIR file.")
+    exit(1)
 
+try:
+    of = open(opts.output, "w")
+except:
+    print("ERROR:", opts.mlir, "could not be opened. Check for valid output JSON file.")
+    exit(1)
 
-# flat_commands = flatten_repeat_command(commands)
-
-# events_to_name= list()
-# core_events = dict()
-# events_to_name.append(core_events)
+if DEBUG:
+    print("DEBUG mode enabled:", file=of)
+    print("pkt type 0: core tile", file=of)
+    print("pkt type 1: core mem tile", file=of)
+    print("pkt type 2: shim tile", file=of)
+    print("pkt type 3: mem tile", file=of)
+    print("", file=of)
+    print("DEBUG: trace_pkts", file=of)
+    print(trace_pkts, file=of)
+    print("", file=of)
+
+    print("DEBUG: pid events\n", file=of)
+    # print(pid_events, file=of)
+    for idx, dict_i in enumerate(pid_events):
+        print("pkt type", idx, ":", file=of)
+        for key, value in dict_i.items():
+            print(key, value, file=of)
+    print("", file=of)
+
+if not check_for_valid_trace(opts.input, trace_pkts, of):
+    sys.exit(1)
+
+trace_pkts_sorted = trace_pkts_de_interleave(trace_pkts)
 
-# if opts.tracelabels:
-#     for i in range(8):
-#         events_to_name[0][i] = opts.tracelabels[i]
-# else:
-#     events_to_name[0][0] = "Instr_Vector"
-#     events_to_name[0][1] = "Tile Start"
-#     events_to_name[0][2] = "Tile End"
-#     events_to_name[0][3] = "Read A"
-#     events_to_name[0][4] = "Read B"
-#     events_to_name[0][5] = "Write C"
-#     events_to_name[0][6] = "Lock Stall"
-#     events_to_name[0][7] = "Lock Acquire"
+if DEBUG:
+    print("DEBUG: trace_pkts_sorted", file=of)
+    for idx, dict_i in enumerate(trace_pkts_sorted):
+        print("pkt type", idx, ":", file=of)
+        for key, value in dict_i.items():
+            print(key, value, file=of)
+    print("", file=of)
 
-# print (json.dumps(commands))
+byte_streams = convert_to_byte_stream(trace_pkts_sorted)
 
-trace_events = list()
-# Let's name the threads
-# active_events = dict()
-
-# for i in range(8):
-# for i in range(16):
-#     active_events[i]  = 0
-# name_dict = dict()
-# # {"name": "thread_name", "ph":"M","pid":0, "tid":0,"args":{"name":"Phil"}}
-# name_dict["name"] = "thread_name"
-# name_dict["ph"]   = "M"           # Metadate
-# name_dict["pid"]  = 0             # We only have one process, but we may want one per core
-# name_dict["tid"]  = i             # I have baked in 8 here, we need this to be informed by how many events are supported
-# name_dict["args"] = {"name":events_to_name[i]}
-# trace_events.append(name_dict)
-
-# timer = 0
-
-# {'type': 'Start', 'timer_value': 0}
-# {'type': 'Single2', 'event': 0, 'cycles': 1161}
-# {'type': 'Single0', 'event': 0, 'cycles': 0}
-# {'type': 'Repeat1', 'repeats': 34}
-# {'type': 'Single0', 'event': 0, 'cycles': 2}
-# {'type': 'Single0', 'event': 0, 'cycles': 0}
-# {'type': 'Repeat1', 'repeats': 24}
-# {'type': 'Multiple0', 'cycles': 0, 'event0': 0, 'event2': 2}
-# {'type': 'Single0', 'event': 0, 'cycles': 0}
-# {'type': 'Repeat0', 'repeats': 4}
-# {'type': 'Single1', 'event': 3, 'cycles': 117}
-# {'type': 'Single1', 'event': 0, 'cycles': 21}
-# {'type': 'Single0', 'event': 0, 'cycles': 0}
-# {'type': 'Repeat1', 'repeats': 21}
-# {'type': 'Multiple0', 'cycles': 0, 'event0': 0, 'event1': 1}
-# {'type': 'Repeat0', 'repeats': 8}
-# {'type': 'Single0', 'event': 1, 'cycles': 0}
+if DEBUG:
+    print("DEBUG: byte stream", file=of)
+    for idx, dict_i in enumerate(byte_streams):
+        print("pkt type", idx, ":", file=of)
+        for key, value in dict_i.items():
+            print(key, value, file=of)
+    print("", file=of)
 
-# ------------------------------------------------------------------------------
-# Convert commands to json
-# ------------------------------------------------------------------------------
+commands_0 = convert_to_commands(byte_streams, False)
 
-# for pid in range(4):
-# for pid in range(1):
-#     process_name_metadata(trace_events, pid)
-#     for tid in range(8):
-#         thread_name_metadata(trace_events, pid, tid, pid_events)
+if DEBUG:
+    print("DEBUG: commands_0", file=of)
+    for idx, dict_i in enumerate(commands_0):
+        print("pkt type", idx, ":", file=of)
+        for key, commands in dict_i.items():
+            print(key, file=of)
+            for i in commands:
+                print("\t", i, file=of)
+    print("", file=of)
 
-# pid will be a product of number of trace types and trace tiles
+trace_events = list()
 
 setup_trace_metadata(trace_events, pid_events)
 
-if DEBUG:
-    print("\nDEBUG: pid events\n")
-    print(pid_events)
-    print("\n\n")
-
-# TODO Loop over cores/mem to call convert_commands_to_json
-convert_commands_to_json(trace_events, commands_0, pid_events)
-
-# convert_commands_to_json(trace_events, mem_commands_0, 1, pid_events)
-# convert_commands_to_json(trace_events, core_commands_1, 2, pid_events)
-# convert_commands_to_json(trace_events, mem_commands_1, 3, pid_events)
+convert_commands_to_json(trace_events, commands_0, pid_events, of)
 
-# for t in trace_events:
-#     print(t)
-print(json.dumps(trace_events))
+print(json.dumps(trace_events).replace("'", '"').replace(", {", ",\n{"), file=of)
diff --git a/programming_examples/utils/trace_utils.py b/programming_examples/utils/trace_utils.py
index 29276ac2eb8..684f5cc3637 100644
--- a/programming_examples/utils/trace_utils.py
+++ b/programming_examples/utils/trace_utils.py
@@ -77,7 +77,7 @@ def trace_to_json(trace_file: str, mlir_file: str, output_name: str = "trace.jso
     command = [
         os.environ["MLIR_AIE_INSTALL_DIR"]
         + "/../../programming_examples/utils/parse_trace.py",
-        "--filename",
+        "--input",
         trace_file,
         "--mlir",
         mlir_file,
diff --git a/programming_guide/section-4/section-4b/Makefile b/programming_guide/section-4/section-4b/Makefile
index af30f07f9ef..5211ca7fccc 100644
--- a/programming_guide/section-4/section-4b/Makefile
+++ b/programming_guide/section-4/section-4b/Makefile
@@ -80,13 +80,13 @@ run_py: build/final.xclbin build/insts.bin
 
 trace: ${targetname}.exe build/final_trace.xclbin build/insts.bin 
 	${powershell} ./$< -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size}
-	${srcdir}/../../../programming_examples/utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} > trace_4b.json
-	${srcdir}/../../../programming_examples/utils/get_trace_summary.py --filename trace_4b.json
+	${srcdir}/../../../programming_examples/utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} --output trace_4b.json
+	${srcdir}/../../../programming_examples/utils/get_trace_summary.py --input trace_4b.json
 
 trace_py: build/final_trace.xclbin build/insts.bin
 	${powershell} python3 ${srcdir}/test.py -x build/final_trace.xclbin -i build/insts.bin -k MLIR_AIE -t ${trace_size} -i1s ${in1_size} -i2s ${in2_size} -os ${out_size}
-	${srcdir}/../../../programming_examples/utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} > trace_4b.json
-	${srcdir}/../../../programming_examples/utils/get_trace_summary.py --filename trace_4b.json
+	${srcdir}/../../../programming_examples/utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift ${colshift} --output trace_4b.json
+	${srcdir}/../../../programming_examples/utils/get_trace_summary.py --input trace_4b.json
 
 
 clean_trace:
diff --git a/programming_guide/section-4/section-4b/README.md b/programming_guide/section-4/section-4b/README.md
index 2f9e6015769..4a3bf93e2c6 100644
--- a/programming_guide/section-4/section-4b/README.md
+++ b/programming_guide/section-4/section-4b/README.md
@@ -212,7 +212,7 @@ Just like the C/C++ host code wrapper `setup_and_run_aie` found in [../../../run
 ## <u>3. Parse text file to generate a waveform json file</u>
 Once the packet trace text file is generated (`trace.txt`), we use a python-based trace parser ([parse_trace.py](../../../programming_examples/utils/parse_trace.py)) to interpret the trace values and generate a waveform json file for visualization (with Perfetto). This is a step in the [Makefile](./Makefile) but can be executed from the command line as well.
 ```Makefile
-	../../../programming_examples/utils/parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift 1 > trace_4b.json
+	../../../programming_examples/utils/parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift 1 --output trace_4b.json
 ```
 This leverages the python parse scripts under [programming_examples/utils](../../../programming_examples/utils/). See the [README.md](../../../programming_examples/utils/README.md) to get more details about how to use the python parse scripts.
 


Reviews:
user: login: jgmelber
body: Just a small comment on documentation 
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-29T18:01:38Z
user: login: jackl-xilinx
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-29T19:44:43Z

Review comments:
diff_hunk: @@ -36,12 +36,15 @@ Shell script to do in-place cleanup of microcode files (e.g. core_*.lst). When v
 The text file generated by the host code (`test.cpp` or `test.py`) are formatted as 32-bit hex values, one per line. This python script parses the raw trace packet data and creates a waveform json file for view on Perfetto http://ui.perfetto.dev. The script syntax is:
 
 ```bash
-parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift 1 > parse_eventIR_vs.json
+parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift 1 --output parse_eventIR_vs.json
 ```
 
 * **--filename** : Input trace packet text file. This is generated during the running of our python host code
 * **--mlir**     : MLIR source. This is needed to parse what events and tiles we are monitoring to generate labels for our waveform visualizer.
-* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
+* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. 
+
+    **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
path: programming_examples/utils/README.md
user: login: jgmelber
body: Can you note that this is PHX specific. In-general the comments here aren't very clear that this is accounting for virtualization vs physical location of tiles in the NPU array.
created_at: 2025-04-29T17:59:51Z
author_association: COLLABORATOR
diff_hunk: @@ -36,12 +36,15 @@ Shell script to do in-place cleanup of microcode files (e.g. core_*.lst). When v
 The text file generated by the host code (`test.cpp` or `test.py`) are formatted as 32-bit hex values, one per line. This python script parses the raw trace packet data and creates a waveform json file for view on Perfetto http://ui.perfetto.dev. The script syntax is:
 
 ```bash
-parse_trace.py --filename trace.txt --mlir build/aie_trace.mlir --colshift 1 > parse_eventIR_vs.json
+parse_trace.py --input trace.txt --mlir build/aie_trace.mlir --colshift 1 --output parse_eventIR_vs.json
 ```
 
 * **--filename** : Input trace packet text file. This is generated during the running of our python host code
 * **--mlir**     : MLIR source. This is needed to parse what events and tiles we are monitoring to generate labels for our waveform visualizer.
-* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
+* **--colshift** : runtime column shift. This specifies how much the actual design was shifted from the default position when it was scheduled and called. The reason we need this is becuase even if our design is configured for column 0, the actual loading and execution of the design may place it in column 1, 2, 3 etc. We account for this shift since the parser needs to match the actual column location of the generated trace data. Usually 1 is the right value. 
+
+    **NOTE** - the underlying tools currently default to column 1 to avoid using column 0 on Ryzen AI since that column does not have a shimDMA and is therefore avoided at the moment.
path: programming_examples/utils/README.md
user: login: jackl-xilinx
body: Good suggestion! I'll add that. Thanks.

created_at: 2025-04-29T19:44:43Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-28T22:05:39Z
body: <!--<!doctype codecov html>--><html><head><meta name='viewport' content='width=device-width,initial-scale=1'><meta charset='UTF-8'><link rel='stylesheet' type='text/css' href='''style.css'></head><body><h2>Coverage Report</h2><h4>Created: 2025-04-29 14:55</h4><p>Click <a href='''http://clang.llvm.org/docs/SourceBasedCodeCoverage.html#interpreting-reports'>here</a> for information about interpreting this report.</p><div class='centered'><table><tr><td class='column-entry-bold'>Filename</td><td class='column-entry-bold'>Function Coverage</td><td class='column-entry-bold'>Line Coverage</td><td class='column-entry-bold'>Region Coverage</td><td class='column-entry-bold'>Branch Coverage</td></tr><tr class='light-row-bold'><td>Totals</td><td class='column-entry-gray'>- </td><td class='column-entry-gray'>- </td><td class='column-entry-gray'>- </td><td class='column-entry-gray'>- </td></tr></table></div><h5>Generated by llvm-cov -- llvm version 18.1.3</h5></body></html>
author_association: CONTRIBUTOR
user: login: jgmelber
created_at: 2025-04-29T20:36:53Z
body: LGTM
author_association: COLLABORATOR