static void Main(string[] args) { Task.Run(async() => { using (var hastlayer = await Hastlayer.Create()) { #region Configuration var configuration = new HardwareGenerationConfiguration("Nexys4 DDR"); configuration.AddHardwareEntryPointType <ParallelAlgorithm>(); configuration.TransformerConfiguration().AddMemberInvocationInstanceCountConfiguration( new MemberInvocationInstanceCountConfigurationForMethod <ParallelAlgorithm>(p => p.Run(null), 0) { MaxDegreeOfParallelism = ParallelAlgorithm.MaxDegreeOfParallelism }); configuration.VhdlTransformerConfiguration().VhdlGenerationMode = VhdlGenerationMode.Debug; hastlayer.ExecutedOnHardware += (sender, e) => { Console.WriteLine( "Executing " + e.MemberFullName + " on hardware took " + e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds + "ms (net) " + e.HardwareExecutionInformation.FullExecutionTimeMilliseconds + " milliseconds (all together)"); }; #endregion #region HardwareGeneration var hardwareRepresentation = await hastlayer.GenerateHardware( new[] { typeof(Program).Assembly }, configuration); await hardwareRepresentation.HardwareDescription.WriteSource("Hast_IP.vhd"); #endregion #region Execution var parallelAlgorithm = await hastlayer.GenerateProxy(hardwareRepresentation, new ParallelAlgorithm()); var output1 = parallelAlgorithm.Run(234234); var output2 = parallelAlgorithm.Run(123); var output3 = parallelAlgorithm.Run(9999); var sw = System.Diagnostics.Stopwatch.StartNew(); var cpuOutput = new ParallelAlgorithm().Run(234234); sw.Stop(); Console.WriteLine("On CPU it took " + sw.ElapsedMilliseconds + "ms."); #endregion } }).Wait(); Console.ReadKey(); }
public async Task <IHastlayer> InitializeHastlayer(bool verifyOutput, bool randomSeedEnable) { _verifyOutput = verifyOutput; _randomSeedEnable = randomSeedEnable; LogItFunction("Creating Hastlayer Factory..."); var hastlayer = await Hastlayer.Create(); hastlayer.ExecutedOnHardware += (sender, e) => { LogItFunction("Hastlayer timer: " + e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds + "ms (net) / " + e.HardwareExecutionInformation.FullExecutionTimeMilliseconds + " ms (total)" ); }; var configuration = new HardwareGenerationConfiguration((await hastlayer.GetSupportedDevices()).First().Name); configuration.VhdlTransformerConfiguration().VhdlGenerationConfiguration = VhdlGenerationConfiguration.Debug; configuration.EnableCaching = false; LogItFunction("Generating hardware..."); if (_kpzTarget.HastlayerParallelizedAlgorithm()) { configuration.AddHardwareEntryPointType <KpzKernelsParallelizedInterface>(); configuration.TransformerConfiguration().AddAdditionalInlinableMethod <RandomMwc64X>(r => r.NextUInt32()); } else if (_kpzTarget.HastlayerPlainAlgorithm()) { configuration.AddHardwareEntryPointType <KpzKernelsInterface>(); } else // if (kpzTarget == KpzTarget.PrngTest) { configuration.AddHardwareEntryPointType <PrngTestInterface>(); } var hardwareRepresentation = await hastlayer.GenerateHardware(new[] { typeof(KpzKernelsParallelizedInterface).Assembly, typeof(RandomMwc64X).Assembly }, configuration); await hardwareRepresentation.HardwareDescription.WriteSource(VhdlOutputFilePath); LogItFunction("Generating proxy..."); if (_kpzTarget.HastlayerOnFpga()) { var proxyConf = new ProxyGenerationConfiguration { VerifyHardwareResults = _verifyOutput }; if (_kpzTarget == KpzTarget.Fpga) { Kernels = await hastlayer.GenerateProxy( hardwareRepresentation, new KpzKernelsInterface(), proxyConf); } else if (_kpzTarget == KpzTarget.FpgaParallelized) { KernelsParallelized = await hastlayer.GenerateProxy( hardwareRepresentation, new KpzKernelsParallelizedInterface(), proxyConf); } else //if(kpzTarget == KpzTarget.PrngTest) { KernelsP = await hastlayer.GenerateProxy( hardwareRepresentation, new PrngTestInterface(), proxyConf); } LogItFunction("FPGA target detected"); } else //if (kpzTarget == KpzTarget.HastlayerSimulation()) { Kernels = new KpzKernelsInterface(); KernelsParallelized = new KpzKernelsParallelizedInterface(); LogItFunction("Simulation target detected"); } if (_kpzTarget.HastlayerPlainAlgorithm()) { LogItFunction("Running TestAdd..."); uint resultFpga = Kernels.TestAddWrapper(4313, 123); uint resultCpu = 4313 + 123; if (resultCpu == resultFpga) { LogItFunction(string.Format("Success: {0} == {1}", resultFpga, resultCpu)); } else { LogItFunction(string.Format("Fail: {0} != {1}", resultFpga, resultCpu)); } } if (_kpzTarget == KpzTarget.PrngTest) { LogItFunction("Running TestPrng..."); var kernelsCpu = new PrngTestInterface(); ulong randomSeed = 0x37a92d76a96ef210UL; var smCpu = kernelsCpu.PushRandomSeed(randomSeed); var smFpga = KernelsP.PushRandomSeed(randomSeed); LogItFunction("PRNG results:"); bool success = true; for (int PrngTestIndex = 0; PrngTestIndex < 10; PrngTestIndex++) { uint prngCpuResult = kernelsCpu.GetNextRandom(smCpu); uint prngFpgaResult = KernelsP.GetNextRandom(smFpga); if (prngCpuResult != prngFpgaResult) { success = false; } LogItFunction(String.Format("{0}, {1}", prngCpuResult, prngFpgaResult)); } if (success) { LogItFunction("TestPrng succeeded!"); } else { LogItFunction("TestPrng failed!"); } } return(hastlayer); }
static void Main(string[] args) { // Wrapping the whole program into Task.Run() is a workaround for async just to be able to run all this from // inside a console app. Task.Run(async() => { /* * On a high level these are the steps to use Hastlayer: * 1. Create the Hastlayer shell. * 2. Configure hardware generation and generate FPGA hardware representation of the given .NET code. * 3. Generate proxies for hardware-transformed types and use these proxies to utilize hardware * implementations. (You can see this inside the SampleRunners.) */ // Configuring the Hastlayer shell. Which flavor should we use? If you're unsure then you'll need // the Client flavor: This will let you connect to a remote Hastlayer service to run the software // to hardware transformation. var hastlayerConfiguration = new HastlayerConfiguration { Flavor = HastlayerFlavor.Developer }; // Initializing a Hastlayer shell. Since this is non-trivial to do you can cache this shell object // while the program runs and re-use it continuously. No need to always wrap it into a using() like // here, just make sure to Dispose() it before the program terminates. using (var hastlayer = await Hastlayer.Create(hastlayerConfiguration)) { // Hooking into an event of Hastlayer so some execution information can be made visible on the // console. hastlayer.ExecutedOnHardware += (sender, e) => { Console.WriteLine( "Executing " + e.MemberFullName + " on hardware took " + e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds + " milliseconds (net) " + e.HardwareExecutionInformation.FullExecutionTimeMilliseconds + " milliseconds (all together)"); }; // We need to set what kind of device (FPGA/FPGA board) to generate the hardware for. var devices = await hastlayer.GetSupportedDevices(); // Let's just use the first one that is available. However you might want to use a specific // device, not just any first one. var configuration = new HardwareGenerationConfiguration(devices.First().Name); // If you're running Hastlayer in the Client flavor, you also need to configure some credentials // here: var remoteClientConfiguration = configuration.RemoteClientConfiguration(); remoteClientConfiguration.AppName = "TestApp"; remoteClientConfiguration.AppSecret = "appsecret"; if (hastlayerConfiguration.Flavor == HastlayerFlavor.Client && remoteClientConfiguration.AppSecret == "appsecret") { throw new InvalidOperationException( "You haven't changed the default remote credentials! Write to [email protected] to receive access if you don't have yet."); } // Letting the configuration of samples run. Check out those methods too! switch (Configuration.SampleToRun) { case Sample.Fix64Calculator: Fix64CalculatorSampleRunner.Configure(configuration); break; case Sample.GenomeMatcher: GenomeMatcherSampleRunner.Configure(configuration); break; case Sample.ParallelAlgorithm: ParallelAlgorithmSampleRunner.Configure(configuration); break; case Sample.ImageProcessingAlgorithms: ImageProcessingAlgorithmsSampleRunner.Configure(configuration); break; case Sample.Loopback: LoopbackSampleRunner.Configure(configuration); break; case Sample.MonteCarloAlgorithm: MonteCarloAlgorithmSampleRunner.Configure(configuration); break; case Sample.ObjectOrientedShowcase: ObjectOrientedShowcaseSampleRunner.Configure(configuration); break; case Sample.PrimeCalculator: PrimeCalculatorSampleRunner.Configure(configuration); break; case Sample.RecursiveAlgorithms: RecursiveAlgorithmsSampleRunner.Configure(configuration); break; case Sample.SimdCalculator: SimdCalculatorSampleRunner.Configure(configuration); break; default: break; } // The generated VHDL code will contain debug-level information, though it will be slower to // create. configuration.VhdlTransformerConfiguration().VhdlGenerationConfiguration = VhdlGenerationConfiguration.Debug; Console.WriteLine("Hardware generation starts."); // Generating hardware from the sample assembly with the given configuration. var hardwareRepresentation = await hastlayer.GenerateHardware( new[] { // Selecting any type from the sample assembly here just to get its Assembly object. typeof(PrimeCalculator).Assembly, typeof(Fix64).Assembly }, configuration); Console.WriteLine("Hardware generation finished, writing VHDL source to file."); if (!string.IsNullOrEmpty(Configuration.VhdlOutputFilePath)) { await hardwareRepresentation.HardwareDescription.WriteSource(Configuration.VhdlOutputFilePath); } Console.WriteLine("VHDL source written to file, starting hardware execution."); // Running samples. switch (Configuration.SampleToRun) { case Sample.Fix64Calculator: await Fix64CalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.GenomeMatcher: await GenomeMatcherSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ParallelAlgorithm: await ParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ImageProcessingAlgorithms: await ImageProcessingAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.Loopback: await LoopbackSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.MonteCarloAlgorithm: await MonteCarloAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ObjectOrientedShowcase: await ObjectOrientedShowcaseSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.PrimeCalculator: await PrimeCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.RecursiveAlgorithms: await RecursiveAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.SimdCalculator: await SimdCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; default: break; } } }).Wait(); Console.WriteLine("Press any key to exit."); Console.ReadKey(); }
private static async Task MainTask(Options configuration) { using (var hastlayer = await Hastlayer.Create(new HastlayerConfiguration { Flavor = HastlayerFlavor.Developer })) { // Get devices and if asked exit with the device list. var devices = await hastlayer.GetSupportedDevices(); if (devices == null || !devices.Any()) { throw new Exception("No devices are available!"); } if (configuration.ListDevices) { foreach (var d in devices) { Console.WriteLine(d.Name); } return; } // If there is an output file name, then the file type can not be None. if (configuration.OutputFileType == OutputFileType.None && !string.IsNullOrEmpty(configuration.OutputFileName)) { configuration.OutputFileType = OutputFileType.Hexdump; } // Try to load selected device or pick the first available if none were selected. if (string.IsNullOrEmpty(configuration.DeviceName)) { configuration.DeviceName = devices.First().Name; } var selectedDevice = devices.FirstOrDefault(device => device.Name == configuration.DeviceName); if (selectedDevice == null) { throw new Exception($"Target device '{configuration.DeviceName}' not found!"); } var channelName = selectedDevice.DefaultCommunicationChannelName; var(memory, accessor) = GenerateMemory(configuration.PayloadType, configuration.PayloadLengthCells, configuration.InputFileName); // Save input to file using the format of the output file type. SaveFile(configuration.OutputFileType, configuration.PayloadType, configuration.InputFileName, true, memory); // Create reference copy of input to compare against output. var referenceMemory = configuration.NoCheck ? null : SimpleMemoryAccessor.Create(accessor.Get()); Console.WriteLine("Starting hardware execution."); var communicationService = await hastlayer.GetCommunicationService(channelName); communicationService.TesterOutput = Console.Out; var executionContext = new BasicExecutionContext(hastlayer, selectedDevice.Name, selectedDevice.DefaultCommunicationChannelName); var info = await communicationService.Execute(memory, configuration.MemberId, executionContext); Console.WriteLine("Executing test on hardware took {0:0.##}ms (net) {1:0.##}ms (all together)", info.HardwareExecutionTimeMilliseconds, info.FullExecutionTimeMilliseconds); // Save output to file. SaveFile(configuration.OutputFileType, configuration.PayloadType, configuration.OutputFileName, false, memory); if (!string.IsNullOrWhiteSpace(configuration?.JsonOutputFileName)) { var json = JsonConvert.SerializeObject(new { Success = true, Result = info }); File.WriteAllText(configuration.JsonOutputFileName, json); } // Verify results if wanted. if (!configuration.NoCheck) { Verify(memory, referenceMemory); } } }
static async Task MainTask(string[] args) { /* * On a high level these are the steps to use Hastlayer: * 1. Create the Hastlayer shell. * 2. Configure hardware generation and generate FPGA hardware representation of the given .NET code. * 3. Generate proxies for hardware-transformed types and use these proxies to utilize hardware * implementations. (You can see this inside the SampleRunners.) */ // Configuring the Hastlayer shell. Which flavor should we use? If you're unsure then you'll need // the Client flavor: This will let you connect to a remote Hastlayer service to run the software // to hardware transformation. var hastlayerConfiguration = new HastlayerConfiguration { Flavor = HastlayerFlavor.Developer }; // Initializing a Hastlayer shell. Since this is non-trivial to do you can cache this shell object // while the program runs and re-use it continuously. No need to always wrap it into a using() like // here, just make sure to Dispose() it before the program terminates. using (var hastlayer = await Hastlayer.Create(hastlayerConfiguration)) { // Hooking into an event of Hastlayer so some execution information can be made visible on the // console. hastlayer.ExecutedOnHardware += (sender, e) => { Console.WriteLine( "Executing " + e.MemberFullName + " on hardware took " + e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds + " milliseconds (net) " + e.HardwareExecutionInformation.FullExecutionTimeMilliseconds + " milliseconds (all together)"); }; // A little helper for later. var argsList = (IList <string>)args; string GetArgument(string name) { name = "-" + name; return(args.Contains(name) ? args[argsList.IndexOf(name) + 1] : null); } // We need to set what kind of device (FPGA/FPGA board) to generate the hardware for. var devices = await hastlayer.GetSupportedDevices(); if (devices == null || !devices.Any()) { throw new Exception("No devices are available!"); } // Let's just use the first one that is available unless it's specified. if (string.IsNullOrEmpty(Configuration.DeviceName)) { Configuration.DeviceName = devices.First().Name; } var targetDeviceName = GetArgument("device") ?? Configuration.DeviceName; var selectedDevice = devices.FirstOrDefault(device => device.Name == targetDeviceName); if (selectedDevice == null) { throw new Exception($"Target device '{targetDeviceName}' not found!"); } var configuration = new HardwareGenerationConfiguration(selectedDevice.Name); // If you're running Hastlayer in the Client flavor, you also need to configure some credentials: var remoteClientConfiguration = configuration.RemoteClientConfiguration(); remoteClientConfiguration.AppName = GetArgument("appname") ?? Configuration.AppName; remoteClientConfiguration.AppSecret = GetArgument("appsecret") ?? Configuration.AppSecret; if (hastlayerConfiguration.Flavor == HastlayerFlavor.Client && remoteClientConfiguration.AppSecret == "appsecret") { throw new InvalidOperationException( "You haven't changed the default remote credentials! Write to [email protected] to receive access if you don't have yet."); } // If the sample was selected in the command line use that, or otherwise the default. Configuration.SampleToRun = (Sample)Enum.Parse(typeof(Sample), GetArgument("sample") ?? Configuration.SampleToRun.ToString(), true); // Letting the configuration of samples run. Check out those methods too! switch (Configuration.SampleToRun) { case Sample.Fix64Calculator: Fix64CalculatorSampleRunner.Configure(configuration); break; case Sample.FSharpParallelAlgorithm: FSharpParallelAlgorithmSampleRunner.Configure(configuration); break; case Sample.GenomeMatcher: GenomeMatcherSampleRunner.Configure(configuration); break; case Sample.ParallelAlgorithm: ParallelAlgorithmSampleRunner.Configure(configuration); break; case Sample.ImageProcessingAlgorithms: ImageProcessingAlgorithmsSampleRunner.Configure(configuration); break; case Sample.Loopback: LoopbackSampleRunner.Configure(configuration); break; case Sample.MemoryTest: MemoryTestSampleRunner.Configure(configuration); break; case Sample.MonteCarloPiEstimator: MonteCarloPiEstimatorSampleRunner.Configure(configuration); break; case Sample.ObjectOrientedShowcase: ObjectOrientedShowcaseSampleRunner.Configure(configuration); break; case Sample.PrimeCalculator: PrimeCalculatorSampleRunner.Configure(configuration); break; case Sample.RecursiveAlgorithms: RecursiveAlgorithmsSampleRunner.Configure(configuration); break; case Sample.SimdCalculator: SimdCalculatorSampleRunner.Configure(configuration); break; default: break; } // The generated VHDL code will contain debug-level information, though it will be slower to create. configuration.VhdlTransformerConfiguration().VhdlGenerationConfiguration = VhdlGenerationConfiguration.Debug; Console.WriteLine("Hardware generation starts."); // Generating hardware from the sample assembly with the given configuration. var hardwareRepresentation = await hastlayer.GenerateHardware( new[] { // Selecting any type from the sample assembly here just to get its Assembly object. typeof(PrimeCalculator).Assembly, typeof(Fix64).Assembly, typeof(FSharpSampleAssembly.FSharpParallelAlgorithmContainer).Assembly }, configuration); Console.WriteLine("Hardware generation finished."); Console.WriteLine(); // Be sure to check out transformation warnings. Most of the time the issues noticed shouldn't cause // any problems, but sometimes they can. if (hardwareRepresentation.HardwareDescription.Warnings.Any()) { Console.WriteLine( "There were the following transformation warnings, which may hint on issues that can cause the hardware implementation to produce incorrect results:" + Environment.NewLine + string.Join(Environment.NewLine, hardwareRepresentation.HardwareDescription.Warnings.Select(warning => "* " + warning.ToString()))); Console.WriteLine(); } if (!string.IsNullOrEmpty(Configuration.VhdlOutputFilePath)) { Console.WriteLine("Writing VHDL source to file."); await hardwareRepresentation.HardwareDescription.WriteSource(Configuration.VhdlOutputFilePath); Console.WriteLine("VHDL source written to file."); Console.WriteLine(); } Console.WriteLine("Starting hardware execution."); // Running samples. try { switch (Configuration.SampleToRun) { case Sample.Fix64Calculator: await Fix64CalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.FSharpParallelAlgorithm: await FSharpParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.GenomeMatcher: await GenomeMatcherSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ParallelAlgorithm: await ParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ImageProcessingAlgorithms: await ImageProcessingAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.Loopback: await LoopbackSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.MemoryTest: await MemoryTestSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.MonteCarloPiEstimator: await MonteCarloPiEstimatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.ObjectOrientedShowcase: await ObjectOrientedShowcaseSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.PrimeCalculator: await PrimeCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.RecursiveAlgorithms: await RecursiveAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation); break; case Sample.SimdCalculator: await SimdCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation); break; default: break; } } catch (AggregateException ex) when(ex.InnerException is HardwareExecutionResultMismatchException) { // If you set ProxyGenerationConfiguration.VerifyHardwareResults to true (when calling // GenerateProxy()) then everything will be computed in software as well to check the hardware. // You'll get such an exception if there is any mismatch. This shouldn't normally happen, but it's // not impossible in corner cases. var mismatches = ((HardwareExecutionResultMismatchException)ex.InnerException).Mismatches; var mismatchCount = mismatches.Count(); Console.WriteLine($"There {(mismatchCount == 1 ? "was a mismatch" : $"were {mismatchCount} mismatches")} between the software and hardware execution's results! Mismatch{(mismatchCount == 1 ? string.Empty : $"es")}:");