Example of Packet Switching from an AI Engine to Multiple AI Engines - 2024.2 English - UG1079

AI Engine Kernel and Graph Programming Guide (UG1079)

Document ID
UG1079
Release Date
2024-11-28
Version
2024.2 English

If the performance allows, AI Engine kernels can be used to dispatch packets to multiple destinations. This section specifically addresses the AI Engine kernel code necessary to manage the packets, particularly the packet header. To illustrate this process, the following graph is considered:

#include <adf.h>
#include "kernels.h"

using namespace adf;
class mygraph: public adf::graph {
private:
  adf:: kernel core[4],core_m;

  adf:: pktsplit<4> sp;
public:
  adf::input_plio  in;
  adf::output_plio  out[4];
  mygraph() {
    core[0] = adf::kernel::create(aie_core1);
    core[1] = adf::kernel::create(aie_core2);
    core[2] = adf::kernel::create(aie_core3);
    core[3] = adf::kernel::create(aie_core4);
    core_m = adf::kernel::create(aie_master_core);
    adf::source(core[0]) = "aie_core1.cpp";
    adf::source(core[1]) = "aie_core2.cpp";
    adf::source(core[2]) = "aie_core3.cpp";
    adf::source(core[3]) = "aie_core4.cpp";
    adf::source(core_m) = "aie_master_core.cpp";
    adf::runtime<ratio>(core_m) = 0.9;
    repetition_count(core_m)=4;
    location<kernel>(core_m)=tile(0,0);

    in=input_plio::create("Datain0", plio_32_bits,  "data/input.txt");
    sp = adf::pktsplit<4>::create();
    for(int i=0;i<4;i++){
      out[i]=output_plio::create("Dataout"+std::to_string(i), plio_32_bits,  "data/output"+std::to_string(i)+".txt");
      adf::runtime<ratio>(core[i]) = 0.9;
      repetition_count(core[i])=1;
      adf::connect<adf::pktstream > (sp.out[i], core[i].in[0]);
      adf::connect<> (core[i].out[0], out[i].in[0]);
    }

    adf::connect<> (in.out[0], core_m.in[0]);
    adf::connect<adf::pktstream> (core_m.out[0], sp.in[0]);
  }
};

The graph view of the above graph is as follows:

Figure 1. Graph View of AI Engine to Multiple AI Engines

Below is the code for the AI Engine kernel responsible for sending packets:

#include <aie_api/aie.hpp>
#include <aie_api/aie_adf.hpp>
const uint32 pktType=0;

void aie_master_core(input_stream<int32> *in,output_pktstream *out){
	int32 user_id=readincr(in); //this is somehow specified by user
	uint32 ID=getPacketid(out,user_id);//get packet ID from user speficified destination
	writeHeader(out,pktType,ID); //Generate header for output
	for(int i=0;i<8;i++){
		int32 tmp=readincr(in);
		writeincr(out,tmp,i==7);//TLAST=1 for last word
	}
}

The pktsplit connection is established at compile time. It is fixed and cannot be modified. You can use the getPacketid() API to extract the packet ID from a specific index of the pktsplit output. This ID is automatically generated during compilation and can be used to transfer the packet from a source to a target connection in the graph.

Note: Only packets matching the extracted packet ID will reach the intended receiver kernel. Once received, the packet's header can be accessed and discarded as necessary.

Following is an example code of the receiver kernel:

#include <aie_api/aie.hpp>
#include <aie_api/aie_adf.hpp>

void aie_core1(input_pktstream *in,output_stream<int32> *out){
	readincr(in);//read header and discard

	bool tlast;
	for(int i=0;i<8;i++){
		int32 tmp=readincr(in,tlast);
		tmp+=1;
		writeincr(out,tmp,i==7);//TLAST=1 for last word
	}
}