210 likes | 347 Vues
Selected MaxCompiler Examples. Sasa Stojanovic stojsasa@etf.rs Veljko Milutinovic vm@etf.rs. One has to know how to program Maxeler machines, in order to get the best possible speedup out of them!
E N D
Selected MaxCompiler Examples Sasa Stojanovic stojsasa@etf.rs Veljko Milutinovic vm@etf.rs
One has to knowhow to program Maxeler machines,in order to get the best possible speedup out of them! For some applications (G),there is a large difference betweenwhat an experienced programmer achieves,andwhat an un-experienced one can achieve! For some other applications (B),no matter how experienced the programmer is,the speedup will not be revolutionary(may be even <1). Introduction How-to? What-to?
Lemas: • 1. The what-to and what-not-to is important to know! • 2. The how-to and how-not-to is important to know! N.B. • The what-to/what-not-to is taught using a figure and formulae(the next slide). • The how-to is taught throughmost of the examples to follow (all except the introductory one). Introduction Lemas
Introduction The Essential Figure: tCPU = N * NOPS * CCPU*TclkCPU /NcoresCPU tGPU = N * NOPS * CGPU*TclkGPU / NcoresGPU tDF = NOPS * CDF * TclkDF + (N – NDF) * TclkDF / NDF Assumptions: 1. Software includes enough parallelism to keep all cores busy 2. The only limiting factor is the number of cores.
When is Maxeler better? • If the number of operations in a single loop iteration is above some critical value • Then More data items means more advantage for Maxeler. In other words: • More data does not mean better performance if the #operations/iteration is below a critical value. • Ideal scenario is to bring data (PCIe relatively slow to MaxCard),and then to work on it a lot (the MaxCard is fast). Conclusion: • If we see an application with a small #operations/iteration, it is possibly (not always) a “what-not-to” application,and we better execute it on the host;otherwise, we will (or may) have a slowdown. Introduction Bottomline: Communications are Expensive ADDITIVE SPEEDUP ENABLER ADDITIVE SPEEDUP MAKER
Maxeler: One new result in each cycle e.g. Clock = 200MHz Period = 5ns One result every 5ns[No matter how many operations in each loop iteration]Consequently: More operations does not mean proportionally more time;however, more operations means higher latency till the first result. CPU: One new result after each iteration e.g. Clock=4GHz Period = 250ps One result every 250ps times #ops[If #ops > 20 => Maxeler is better, although it uses a slower clock] Also: The CPU example will feature an additional slowdown,due to memory hierarchy access and pipeline related hazards => critical #ops (bringing the same performance) is significantly below 20!!! Introduction A More Concrete Explanation:
Maxeler has no cache,but does have a memory hierarchy. However, memory hierarchy access with Maxeler is carefully planed by the programmer at the program write time (FPGAmem+onBoardMEM). As opposed to memory hierarchy access with a multiCore CPU/GPU which calculates the access address at the program run time. Introduction Don’t Missunderstand!
Java to configure Maxeler!C to program the host! One or more kernels!Only one manager! In theory, Simulator builder not needed if a card is used.In practice, you need it until the testing is over, since the compilation process is slow, for hardware, and fast, for software (simulator). Introduction N.B.
E#1: Hello world E#2: Vector addition E#3: Type mixing E#4: Addition of a constant and a vector E#5: Input/output control E#6: Conditional execution E#7: Moving average 1D E#8: Moving average 2D E#9: Array summation E#10: Optimization of E#9 Content Content
Write a program that sends the “Hello World!” stringfrom the Host to the MAX2 card, for the MAX2 card kernel to return it back to the host. To be learned through this example: • How to make the configuration of the accelerator (MAX2 card) using Java: • How to make a simple kernel (ops description) using Java (the only language), • How to write the standard manager (configuration description based on kernel(s))using Java, • How to test the kernel using a test (code+data) written in Java, • How to compile the Java code for MAX2, • How to write a simple C code that runs on the hostand triggers the kernel, • How to write the C code that streams data to the kernel, • How to write the C code that accepts data from the kernel, • How to simulate and execute an application program in Cthat runs on the host and periodically calls the accelerator. Example No. 1 Example No.1: Hello World!
One or more kernel files, to define operations of the application: • <app_name>Kernel[<additional_name>].java One (or more) Java file, for simulator-based testing of the kernel(s);here we only test the kernel(s), with various data inputs: • <app_name>SimRunner.java One manager file for transforming the kernel(s) into the configuration of the MAX card(instantiation and connection of kernels);instantiation maps into DFEs the behavior defined by kernels;if more kernels, connection links outputs and inputs of kernels: • <app_name>Manager.java Simulator builder (Java kernel(s) compiled and linked to host code, for simulation (on a PC): • <app_name>HostSimBuilder.java Hardware builder (same as above, for execution (on a MAX card or a MAX system): • <app_name>HWBuilder.java Application code that uses the MAX card accelerator: • <app_name>HostCode.c Makefile (comes together with any Maxeler package) • A script file that defines the compilation related commands and their sequence,plus the user’s selection of the “make” argument, e.g. “make app-sim,” “make build-sim,” etc (type: make w/o an argument, to see options). Example No. 1 Standard Files in a MAX Project
package ind.z1; // it is always good to have an easy reusability import com.maxeler.maxcompiler.v1.kernelcompiler.Kernel; import com.maxeler.maxcompiler.v1.kernelcompiler.KernelParameters; import com.maxeler.maxcompiler.v1.kernelcompiler.types.base.HWVar; // all above comes with the MaxelerOS // the class Kernel includes all the necessary code and is open for the user to extend it public class helloKernel extends Kernel { public helloKernel(KernelParameters parameters) { super(parameters); // Input: HWVar x1 = io.input("x", hwInt(8)); HWVar result = x1; // Output: io.output("z", result, hwInt(8)); } } // concrete parameters are passed to the general Kernel = passing to a superClass // x comes from the PCIe bus; HWVar x1 is a memory location on the FPGA chip, of the type HWVar // type HWVar is defined by the package imported from the Maxeler library (the line 3 above) Example No. 1 example1Kernel.java It is possible to substitute the last three lines with: io.output("z", io.input(“x”, hwInt(8)), hwInt(8));
package ind.z1; import com.maxeler.maxcompiler.v1.managers.standard.SimulationManager; // now the kernel has to be tested public class helloSimRunner { public static void main(String[] args) { SimulationManager m = new SimulationManager(“helloSim"); helloKernel k = new helloKernel(m.makeKernelParameters()); m.setKernel(k); // the simulation manager m is set to use the kernel k m.setInputData("x", 1, 2, 3, 4, 5, 6, 7, 8); // this method passes test data to the kernel m.setKernelCycles(8); // it is specified that the kernel will be executed 8 times m.runTest(); // the manager is activated, to start the process of 8 kernel runs m.dumpOutput(); // the method to prepare the output is also provided by Maxeler double expectedOutput[] = {1, 2, 3, 4, 5, 6, 7, 8}; // we define what we expect m.checkOutputData("z", expectedOutput); // we compare the obtained and the expected m.logMsg("Test passed OK!"); // if “execution came till here,” a screen message is displayed } } // static – only one instance of main // viod – main returns no data; just shows data on the screen Example No. 1 example1SimRunner.java
package ind.z1; // more import from the Maxeler library is needed! import static config.BoardModel.BOARDMODEL; // the universal simulator is nailed down import com.maxeler.maxcompiler.v1.kernelcompiler.Kernel; // now we can use Kernel import com.maxeler.maxcompiler.v1.managers.standard.Manager; // now we can use Manager import com.maxeler.maxcompiler.v1.managers.standard.Manager.IOType; // now can use IOType public class helloHostSimBuilder { public static void main(String[] args) { Manager m = new Manager(true,”helloHostSim", BOARDMODEL); // making Manager Kernel k = new helloKernel(m.makeKernelParameters(“helloKernel")); // making Kernel m.setKernel(k); // linking Kernel k to Manager m m.setIO(IOType.ALL_PCIE); // the selected type is bit-compatible with PCIe m.build(); // an executable code is generated, to be executed later // the build method is defined by Maxeler inside the imported manager class } } Example No. 1 example1HostSimBuilder.java
package ind.z1; // the next 4 lines are the same as before import static config.BoardModel.BOARDMODEL; import com.maxeler.maxcompiler.v1.kernelcompiler.Kernel; import com.maxeler.maxcompiler.v1.managers.standard.Manager; import com.maxeler.maxcompiler.v1.managers.standard.Manager.IOType; // the next lines differ in only one detail: The parameter “true” is missing; defined by Maxeler public class helloHWBuilder { public static void main(String[] args) { Manager m = new Manager(“hello", BOARDMODEL); Kernel k = new helloKernel( m.makeKernelParameters() ); m.setKernel(k); m.setIO(IOType.ALL_PCIE); m.build(); } } Example No. 1 example1HwBuilder.java
#include <stdio.h> // standard input/output #include <MaxCompilerRT.h> // the MaxCompilerRT functionality is included int main(intargc, char* argv[]) { // the next 5 lines define data char *device_name = (argc==2 ? argv[1] : "/dev/maxeler0"); // default device defined max_maxfile_t* maxfile; max_device_handle_t* device; char data_in1[16] = "Hello world!"; char data_out[16]; printf("Opening and configuring FPGA.\n"); // the lines to follow initialize Maxeler maxfile = max_maxfile_init_hello(); // defined in MaxCompilerRT.h device = max_open_device(maxfile, device_name); max_set_terminate_on_error(device); Example No. 1 example1HostCode.c 1/2
printf("Streaming data to/from FPGA...\n"); // screen dump // the next statement passes data to/from Maxeler // and tells Manager to run Kernel 16 times max_run(device, max_input("x", data_in1, 16 * sizeof(char)), max_output("z", data_out, 16 * sizeof(char)), max_runfor(“helloKernel", 16), max_end()); printf("Checking data read from FPGA.\n"); // screen dump max_close_device(device); // freeing the memory, by closing the device, max_destroy(maxfile); // and by destroying the maxfile return 0; } Example No. 1 example1HostCode.c 2/2
# ALL THE CODE BELOW IS DEFINED BY MAXELER # Root of the project directory tree BASEDIR=../../.. # Java package name PACKAGE=ind/z1 # Application name APP=example1 # Names of your maxfiles HWMAXFILE=$(APP).max HOSTSIMMAXFILE=$(APP)HostSim.max # Java application builders HWBUILDER=$(APP)HWBuilder.java HOSTSIMBUILDER=$(APP)HostSimBuilder.java SIMRUNNER=$(APP)SimRunner.java # C host code HOSTCODE=$(APP)HostCode.c # Target board BOARD_MODEL=23312 # Include the master makefile.include nullstring := space := $(nullstring) # comment MAXCOMPILERDIR_QUOTE:=$(subst $(space),\ ,$(MAXCOMPILERDIR)) include $(MAXCOMPILERDIR_QUOTE)/examples/common/Makefile.include Example No. 1 Makefile: Always the Same
package config; import com.maxeler.maxcompiler.v1.managers.MAX2BoardModel; public class BoardModel { public static final MAX2BoardModel BOARDMODEL = MAX2BoardModel.MAX2336B; } // THIS ENABLES THE USER TO WRITE BOARDMODEL, // INSTEAD OF USING THE COMPLICATED NAME EXPRESSION // IN THE LAST LINE Example No. 1 BoardModel.java
Types Hardware Types: Provided by Maxeler // we used: HWFloat
Floating point numbers - HWFloat: • hwFloat(exponent_bits, mantissa_bits); • float ~ hwFloat(8,24) • double ~ hwFloat(11,53) Fixed point numbers - HWFix: • hwFix(integer_bits, fractional_bits, sign_mode) • SignMode.UNSIGNED • SignMode.TWOSCOMPLEMENT Integers - HWFix: • hwInt(bits) ~ hwFix(bits, 0, SignMode.TWOSCOMPLEMENT) Unsigned integers - HWFix: • hwUint(bits) ~ hwFix(bits, 0, SignMode.UNSIGNED) Boolean – HWFix: • hwBool() ~ hwFix(1, 0, SignMode.UNSIGNED) • 1 ~ true • 2 ~ false Raw bits – HWRawBits: • hwRawBits(width) Types Hardware Primitive Types