Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d347be9
WIP implement dependencies
achocron Apr 8, 2021
4881531
Merge branch 'alchocro/qir-controller-logging' into alchocro/qir-cont…
achocron Apr 9, 2021
fb064e6
Implement executable generator
achocron Apr 9, 2021
e2a5516
Merge branch 'alchocro/qir-controller-logging' into alchocro/qir-cont…
achocron Apr 9, 2021
48973d4
Implement driver generator
achocron Apr 9, 2021
65a6ae7
Clean up
achocron Apr 9, 2021
529f543
Fix typo
achocron Apr 9, 2021
74eaa03
Fix log
achocron Apr 9, 2021
7b18063
Merge remote-tracking branch 'origin/feature/azure-quantum-simulator'…
achocron Apr 9, 2021
860d9d0
Refactor executable runner
achocron Apr 12, 2021
0853fcd
Clean up
achocron Apr 13, 2021
6b067c0
Fix tests
achocron Apr 14, 2021
98ffe1b
Clean up
achocron Apr 14, 2021
d022efe
Merge remote-tracking branch 'origin/feature/azure-quantum-simulator'…
achocron Apr 14, 2021
5c8d26f
WIP
achocron Apr 14, 2021
3761797
WIP
achocron Apr 14, 2021
6a01cd1
WIP
achocron Apr 14, 2021
0e4eb93
Create working test and fix issues
achocron Apr 15, 2021
e4e6c22
Fix header
achocron Apr 15, 2021
432d88e
Fix header
achocron Apr 15, 2021
b80383b
Address feedbacks
achocron Apr 15, 2021
667aefc
Merge branch 'alchocro/controller-tests' of https://github.com/micros…
achocron Apr 15, 2021
b0f0285
Update package
achocron Apr 15, 2021
b7cb61f
Remove logic to copy include files
achocron Apr 16, 2021
f9de9da
Add runtime building to test script
achocron Apr 16, 2021
56c2d95
Fix build configuration issue in test script
achocron Apr 16, 2021
cdded09
Merge branch 'feature/azure-quantum-simulator' into alchocro/controll…
cesarzc Apr 19, 2021
7446f8b
Try adding clang to path
achocron Apr 19, 2021
0168179
Merge branch 'alchocro/controller-tests' of https://github.com/micros…
achocron Apr 19, 2021
92d1269
Print path in script
achocron Apr 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,8 @@ ASALocalRun/
dbw_test

# Controller test artifacts
/src/Qir/Controller/test-artifacts/
/src/Qir/Controller/test-artifacts/
/src/Qir/Controller/src

# out folders
out/
9 changes: 4 additions & 5 deletions src/Qir/Controller/Controller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static async Task ExecuteAsync(
DirectoryInfo libraryDirectory,
DirectoryInfo includeDirectory,
FileInfo errorFile,
IQirDriverGenerator driverGenerator,
IQirSourceFileGenerator driverGenerator,
IQirExecutableGenerator executableGenerator,
IQuantumExecutableRunner executableRunner,
ILogger logger)
Expand All @@ -37,10 +37,10 @@ public static async Task ExecuteAsync(
using var inputFileStream = inputFile.OpenRead();
var input = QirExecutionWrapperSerialization.DeserializeFromFastBinary(inputFileStream);

// Step 32: Create driver.
// Step 2: Create driver.
logger.LogInfo("Creating driver file.");
var sourceDirectory = new DirectoryInfo(SourceDirectoryPath);
await driverGenerator.GenerateQirDriverCppAsync(sourceDirectory, input.EntryPoint, input.QirBytecode);
await driverGenerator.GenerateQirSourceFilesAsync(sourceDirectory, input.EntryPoint, input.QirBytecode);

// Step 3: Create executable.
logger.LogInfo("Compiling and linking executable.");
Expand All @@ -50,12 +50,11 @@ public static async Task ExecuteAsync(

// Step 4: Run executable.
logger.LogInfo("Running executable.");
using var outputFileStream = outputFile.OpenWrite();
await executableRunner.RunExecutableAsync(executableFile, input.EntryPoint, outputFile);
}
catch (Exception e)
{
logger.LogError("An error has been encountered. Will write an error to the error file and delete any output that has been generated.");
logger.LogError("An error has been encountered. Will write an error to the error file.");
logger.LogException(e);
await WriteExceptionToFileAsync(e, errorFile);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Microsoft.Quantum.Qir.Driver
{
public interface IQirDriverGenerator
public interface IQirSourceFileGenerator
{
/// <summary>
/// Generates the C++ driver source file and writes the bytecode to a file.
Expand All @@ -17,6 +17,6 @@ public interface IQirDriverGenerator
/// <param name="entryPointOperation">Entry point information.</param>
/// <param name="bytecode">The QIR bytecode.</param>
/// <returns></returns>
Task GenerateQirDriverCppAsync(DirectoryInfo sourceDirectory, EntryPointOperation entryPointOperation, ArraySegment<byte> bytecode);
Task GenerateQirSourceFilesAsync(DirectoryInfo sourceDirectory, EntryPointOperation entryPointOperation, ArraySegment<byte> bytecode);
}
}
26 changes: 0 additions & 26 deletions src/Qir/Controller/Driver/QirDriverGenerator.cs

This file was deleted.

53 changes: 53 additions & 0 deletions src/Qir/Controller/Driver/QirSourceFileGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir.Utility;
using Microsoft.Quantum.QsCompiler;
using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;

namespace Microsoft.Quantum.Qir.Driver
{
public class QirSourceFileGenerator : IQirSourceFileGenerator
{
private const string BytecodeFileName = "qir.bc";
private const string DriverFileName = "driver.cpp";
private readonly ILogger logger;

public QirSourceFileGenerator(ILogger logger)
{
this.logger = logger;
}

public async Task GenerateQirSourceFilesAsync(DirectoryInfo sourceDirectory, EntryPointOperation entryPointOperation, ArraySegment<byte> bytecode)
{
if (sourceDirectory.Exists)
{
sourceDirectory.Delete(true);
}

sourceDirectory.Create();
logger.LogInfo($"Created source directory at {sourceDirectory.FullName}.");

// Create driver.
var driverFile = new FileInfo(Path.Combine(sourceDirectory.FullName, DriverFileName));
using var driverFileStream = driverFile.OpenWrite();
GenerateQirDriverCppHelper(entryPointOperation, driverFileStream);
logger.LogInfo($"Created driver file at {driverFile.FullName}.");

// Create bytecode file.
var bytecodeFile = new FileInfo(Path.Combine(sourceDirectory.FullName, BytecodeFileName));
using var bytecodeFileStream = bytecodeFile.OpenWrite();
await bytecodeFileStream.WriteAsync(bytecode.Array, bytecode.Offset, bytecode.Count);
logger.LogInfo($"Created bytecode file at {bytecodeFile.FullName}.");
}

// Virtual method wrapper is to enable mocking in unit tests.
public virtual void GenerateQirDriverCppHelper(EntryPointOperation entryPointOperation, Stream stream)
{
QirDriverGeneration.GenerateQirDriverCpp(entryPointOperation, stream);
}
}
}
2 changes: 1 addition & 1 deletion src/Qir/Controller/Executable/ClangClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public async Task CreateExecutableAsync(string[] inputFiles, string[] libraries,

// string.Join does not automatically prepend the delimiter, so it is included again in the string here.
var librariesArg = $"{LinkFlag} {string.Join(LinkFlag, libraries)}";
var arguments = $"{inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath}";
var arguments = $"-v {inputsArg} -I {includePath} -L {libraryPath} {librariesArg} -o {outputPath}";
logger.LogInfo($"Invoking clang with the following arguments: {arguments}");
var result = await Process.ExecuteAsync(
"clang",
Expand Down
38 changes: 35 additions & 3 deletions src/Qir/Controller/Executable/QirExecutableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
// Licensed under the MIT License.

using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir.Utility;

namespace Microsoft.Quantum.Qir.Executable
{
public class QirExecutableGenerator : IQirExecutableGenerator
{
private static readonly string[] LibrariesToLink = {
"Microsoft.Quantum.Qir.Runtime",
"Microsoft.Quantum.Qir.QSharp.Foundation",
"Microsoft.Quantum.Qir.QSharp.Core"
};
private readonly IClangClient clangClient;
private readonly ILogger logger;

Expand All @@ -18,10 +24,36 @@ public QirExecutableGenerator(IClangClient clangClient, ILogger logger)
this.logger = logger;
}

public Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory)
public async Task GenerateExecutableAsync(FileInfo executableFile, DirectoryInfo sourceDirectory, DirectoryInfo libraryDirectory, DirectoryInfo includeDirectory)
{
// TODO: Compile and link libraries- "Microsoft.Quantum.Qir.Runtime", "Microsoft.Quantum.Qir.QSharp.Foundation", "Microsoft.Quantum.Qir.QSharp.Core"
throw new System.NotImplementedException();
// Wrap in a Task.Run because FileInfo methods are not asynchronous.
await Task.Run(async () =>
{
var binDirectory = executableFile.Directory;
logger.LogInfo($"Creating binary directory at {binDirectory.FullName}.");
executableFile.Directory.Create();

// Copy all library contents to bin.
logger.LogInfo("Copying library directory contents into the executable's folder.");
var libraryFiles = libraryDirectory.GetFiles();
foreach (var file in libraryFiles)
{
CopyFileIfNotExists(file, binDirectory);
}

var inputFiles = sourceDirectory.GetFiles().Select(fileInfo => fileInfo.FullName).ToArray();
await clangClient.CreateExecutableAsync(inputFiles, LibrariesToLink, libraryDirectory.FullName, includeDirectory.FullName, executableFile.FullName);
});
}

private void CopyFileIfNotExists(FileInfo fileToCopy, DirectoryInfo destinationDirectory)
{
var newPath = Path.Combine(destinationDirectory.FullName, fileToCopy.Name);
if (!File.Exists(newPath))
{
var newFile = fileToCopy.CopyTo(newPath);
logger.LogInfo($"Copied file {fileToCopy.FullName} to {newFile.FullName}");
}
}
}
}
20 changes: 18 additions & 2 deletions src/Qir/Controller/Executable/QuantumExecutableRunner.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.CommandLine.Invocation;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir.Utility;
using Microsoft.Quantum.QsCompiler;
using Microsoft.Quantum.QsCompiler.BondSchemas.EntryPoint;

namespace Microsoft.Quantum.Qir.Executable
Expand All @@ -17,9 +19,23 @@ public QuantumExecutableRunner(ILogger logger)
this.logger = logger;
}

public Task RunExecutableAsync(FileInfo executableFile, EntryPointOperation entryPointOperation, FileInfo outputFile)
public async Task RunExecutableAsync(FileInfo executableFile, EntryPointOperation entryPointOperation, FileInfo outputFile)
{
throw new System.NotImplementedException();
var arguments = QirDriverGeneration.GenerateCommandLineArguments(entryPointOperation.Arguments);
logger.LogInfo($"Invoking executable {executableFile.FullName} with the following arguments: {arguments}");
arguments = $"--simulation-output {outputFile.FullName} {arguments}";
if (outputFile.Exists)
{
outputFile.Delete();
}

outputFile.Create().Dispose();
var result = await Process.ExecuteAsync(
executableFile.FullName,
arguments,
stdOut: s => { logger.LogInfo("executable: " + s); },
stdErr: s => { logger.LogError("executable: " + s); });
logger.LogInfo($"Executable has finished running. Result code: {result}");
}
}
}
2 changes: 1 addition & 1 deletion src/Qir/Controller/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ static void Main(string[] args)
{
var logger = new Logger(new Clock());
var execGenerator = new QirExecutableGenerator(new ClangClient(logger), logger);
var driverGenerator = new QirDriverGenerator(logger);
var driverGenerator = new QirSourceFileGenerator(logger);
var execRunner = new QuantumExecutableRunner(logger);
logger.LogInfo("QIR controller beginning.");

Expand Down
6 changes: 5 additions & 1 deletion src/Qir/Controller/QirController.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@
</PropertyGroup>

<ItemGroup>
<BondCodegen Remove="src\**" />
<BondCodegen Remove="test-artifacts\**" />
<BondCodegen Remove="Tests.QirController\**" />
<Compile Remove="src\**" />
<Compile Remove="test-artifacts\**" />
<Compile Remove="Tests.QirController\**" />
<EmbeddedResource Remove="src\**" />
<EmbeddedResource Remove="test-artifacts\**" />
<EmbeddedResource Remove="Tests.QirController\**" />
<None Remove="src\**" />
<None Remove="test-artifacts\**" />
<None Remove="Tests.QirController\**" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Quantum.Compiler" Version="0.15.2104135018-alpha" />
<PackageReference Include="Microsoft.Quantum.Compiler" Version="0.15.2104136396-alpha" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20371.2" />
</ItemGroup>

Expand Down
19 changes: 5 additions & 14 deletions src/Qir/Controller/Tests.QirController/ControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Quantum.Qir;
Expand All @@ -22,7 +21,7 @@ namespace Tests.QirController
{
public class ControllerTests : IDisposable
{
private Mock<IQirDriverGenerator> driverGeneratorMock;
private Mock<IQirSourceFileGenerator> driverGeneratorMock;
private Mock<IQirExecutableGenerator> executableGeneratorMock;
private Mock<IQuantumExecutableRunner> executableRunnerMock;
private Mock<ILogger> loggerMock;
Expand All @@ -34,7 +33,7 @@ public class ControllerTests : IDisposable

public ControllerTests()
{
driverGeneratorMock = new Mock<IQirDriverGenerator>();
driverGeneratorMock = new Mock<IQirSourceFileGenerator>();
executableGeneratorMock = new Mock<IQirExecutableGenerator>();
executableRunnerMock = new Mock<IQuantumExecutableRunner>();
inputFile = new FileInfo($"{Guid.NewGuid()}-input");
Expand Down Expand Up @@ -102,9 +101,9 @@ await Controller.ExecuteAsync(
loggerMock.Object);

// Verify driver was created.
driverGeneratorMock.Verify(obj => obj.GenerateQirDriverCppAsync(
driverGeneratorMock.Verify(obj => obj.GenerateQirSourceFilesAsync(
It.IsAny<DirectoryInfo>(),
It.Is<EntryPointOperation>(entryPoint => EntryPointsAreEqual(entryPoint, input.EntryPoint)),
It.Is<EntryPointOperation>(entryPoint => Util.EntryPointsAreEqual(entryPoint, input.EntryPoint)),
It.Is<ArraySegment<byte>>(bytecode => BytecodesAreEqual(bytecode, input.QirBytecode))));

// Verify executable was generated.
Expand All @@ -118,7 +117,7 @@ await Controller.ExecuteAsync(
// Verify executable was run.
executableRunnerMock.Verify(obj => obj.RunExecutableAsync(
It.Is<FileInfo>(executableFile => actualExecutableFile.FullName == executableFile.FullName),
It.Is<EntryPointOperation>(entryPoint => EntryPointsAreEqual(entryPoint, input.EntryPoint)),
It.Is<EntryPointOperation>(entryPoint => Util.EntryPointsAreEqual(entryPoint, input.EntryPoint)),
It.Is<FileInfo>(actualOutputFile => actualOutputFile.FullName == outputFile.FullName)));
}

Expand Down Expand Up @@ -184,14 +183,6 @@ await Controller.ExecuteAsync(
Assert.Equal(errorCode, error.Code);
}

private bool EntryPointsAreEqual(EntryPointOperation entryPointA, EntryPointOperation entryPointB)
{
var method = typeof(Extensions)
.GetMethod("ValueEquals", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(EntryPointOperation), typeof(EntryPointOperation) }, null);
object[] parameters = { entryPointA, entryPointB };
return (bool)method.Invoke(null, parameters);
}

private bool BytecodesAreEqual(ArraySegment<byte> bytecodeA, ArraySegment<byte> bytecodeB)
{
if (bytecodeA.Count != bytecodeB.Count)
Expand Down
Loading