Skip to content

Commit

Permalink
Reduce runtime expenses with specialized implementations of blobs
Browse files Browse the repository at this point in the history
+ Adapt internal representations of blob values and related parts of the program to reduce processing times. Find a representation that allows for more efficient processing while maintaining interfaces making accidental mutation less likely.
+ Adapt the `FileStore` interfaces to use the same type for blobs.
+ Specialize composition hash function to reduce runtime expenses.
+ Avoid confused method reference resolution in Elm Editor: Disable the automated test depending on Elm Editor until we have linked the new assembly from CI build.
  • Loading branch information
Viir committed May 27, 2021
1 parent ed75a78 commit 289b468
Show file tree
Hide file tree
Showing 24 changed files with 370 additions and 378 deletions.
44 changes: 22 additions & 22 deletions implement/elm-fullstack/ElmFullstack/ElmApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,29 @@ public struct ElmAppInterfaceConvention

public class ElmApp
{
static public (IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> compiledAppFiles, IImmutableList<CompilationIterationReport> iterationsReports) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> sourceFiles,
static public (IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> compiledAppFiles, IImmutableList<CompilationIterationReport> iterationsReports) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> sourceFiles,
ElmAppInterfaceConfig interfaceConfig) =>
AsCompletelyLoweredElmApp(
sourceFiles,
rootModuleName: interfaceConfig.RootModuleName.Split('.').ToImmutableList(),
interfaceToHostRootModuleName: InterfaceToHostRootModuleName.Split('.').ToImmutableList());

static (IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>>, IImmutableList<CompilationIterationReport>) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> sourceFiles,
static (IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>>, IImmutableList<CompilationIterationReport>) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> sourceFiles,
IImmutableList<string> rootModuleName,
IImmutableList<string> interfaceToHostRootModuleName) =>
AsCompletelyLoweredElmApp(
sourceFiles,
rootModuleName,
interfaceToHostRootModuleName,
ImmutableStack<(IImmutableList<(CompilerSerialInterface.DependencyKey key, IImmutableList<byte> value)> discoveredDependencies, CompilationIterationReport previousIterationsReports)>.Empty);
ImmutableStack<(IImmutableList<(CompilerSerialInterface.DependencyKey key, IReadOnlyList<byte> value)> discoveredDependencies, CompilationIterationReport previousIterationsReports)>.Empty);

static (IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>>, IImmutableList<CompilationIterationReport>) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> sourceFiles,
static (IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>>, IImmutableList<CompilationIterationReport>) AsCompletelyLoweredElmApp(
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> sourceFiles,
IImmutableList<string> rootModuleName,
IImmutableList<string> interfaceToHostRootModuleName,
IImmutableStack<(IImmutableList<(CompilerSerialInterface.DependencyKey key, IImmutableList<byte> value)> discoveredDependencies, CompilationIterationReport iterationReport)> stack)
IImmutableStack<(IImmutableList<(CompilerSerialInterface.DependencyKey key, IReadOnlyList<byte> value)> discoveredDependencies, CompilationIterationReport iterationReport)> stack)
{
if (10 < stack.Count())
throw new Exception("Iteration stack depth > 10");
Expand Down Expand Up @@ -109,7 +109,7 @@ static public (IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>
}

byte[] ElmMake(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmCodeFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmCodeFiles,
IImmutableList<string> pathToFileWithElmEntryPoint,
bool makeJavascript,
bool enableDebug)
Expand Down Expand Up @@ -157,7 +157,7 @@ CompilationIterationDependencyReport completeDependencyReport()
elmMakeRequest.files
.ToImmutableDictionary(
entry => (IImmutableList<string>)entry.path.ToImmutableList(),
entry => (IImmutableList<byte>)Convert.FromBase64String(entry.content.AsBase64).ToImmutableList())
entry => (IReadOnlyList<byte>)Convert.FromBase64String(entry.content.AsBase64))
.WithComparers(EnumerableExtension.EqualityComparer<string>());

var value = ElmMake(
Expand All @@ -167,7 +167,7 @@ CompilationIterationDependencyReport completeDependencyReport()
enableDebug: elmMakeRequest.enableDebug);

return (
(key: dependencyKey, value: (IImmutableList<byte>)value.ToImmutableList()),
(key: dependencyKey, (IReadOnlyList<byte>)value),
completeDependencyReport());
}

Expand All @@ -189,11 +189,11 @@ CompilationIterationDependencyReport completeDependencyReport()
stack: stack.Push(newStackFrame));
}

static (ElmValueCommonJson.Result<IReadOnlyList<CompilerSerialInterface.CompilationError>, ImmutableDictionary<IImmutableList<string>, IImmutableList<byte>>>, CompilationIterationCompilationReport report) ElmAppCompilation(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> sourceFiles,
static (ElmValueCommonJson.Result<IReadOnlyList<CompilerSerialInterface.CompilationError>, ImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>>>, CompilationIterationCompilationReport report) ElmAppCompilation(
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> sourceFiles,
IImmutableList<string> rootModuleName,
IImmutableList<string> interfaceToHostRootModuleName,
ImmutableList<(CompilerSerialInterface.DependencyKey key, IImmutableList<byte> value)> dependencies)
ImmutableList<(CompilerSerialInterface.DependencyKey key, IReadOnlyList<byte> value)> dependencies)
{
var totalStopwatch = System.Diagnostics.Stopwatch.StartNew();
var serializeStopwatch = System.Diagnostics.Stopwatch.StartNew();
Expand Down Expand Up @@ -253,7 +253,7 @@ CompilationIterationDependencyReport completeDependencyReport()
withFilesAsList.map(files =>
files.ToImmutableDictionary(
entry => (IImmutableList<string>)entry.path.ToImmutableList(),
entry => (IImmutableList<byte>)Convert.FromBase64String(entry.content.AsBase64).ToImmutableList())
entry => (IReadOnlyList<byte>)Convert.FromBase64String(entry.content.AsBase64))
.WithComparers(EnumerableExtension.EqualityComparer<string>()));

return
Expand Down Expand Up @@ -319,12 +319,12 @@ static string BuildJavascriptToCompileElmApp()
listFunctionToPublish);
}

static public IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> CompileElmProgramAppCodeFiles() =>
ImmutableDictionary<IImmutableList<string>, IImmutableList<byte>>.Empty
static public IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> CompileElmProgramAppCodeFiles() =>
ImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>>.Empty
.WithComparers(EnumerableExtension.EqualityComparer<string>())
.SetItem(ImmutableList.Create("elm.json"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.elm.json").ToImmutableList())
.SetItem(ImmutableList.Create("src", "CompileFullstackApp.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.src.CompileFullstackApp.elm").ToImmutableList())
.SetItem(ImmutableList.Create("src", "Main.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.src.Main.elm").ToImmutableList());
.SetItem(ImmutableList.Create("elm.json"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.elm.json"))
.SetItem(ImmutableList.Create("src", "CompileFullstackApp.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.src.CompileFullstackApp.elm"))
.SetItem(ImmutableList.Create("src", "Main.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmFullstack.compile_elm_program.src.Main.elm"));

static byte[] GetManifestResourceStreamContent(string name)
{
Expand Down Expand Up @@ -412,8 +412,8 @@ struct BytesJson
{
public string AsBase64;

static public BytesJson AsJson(IImmutableList<byte> bytes) =>
new CompilerSerialInterface.BytesJson { AsBase64 = Convert.ToBase64String(bytes.ToArray()) };
static public BytesJson AsJson(IReadOnlyList<byte> bytes) =>
new BytesJson { AsBase64 = Convert.ToBase64String(bytes as byte[] ?? bytes.ToArray()) };
}
}
}
2 changes: 1 addition & 1 deletion implement/elm-fullstack/ElmFullstack/PersistentProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class PersistentProcessWithHistoryOnFileFromElm019Code : IPersistentProce

public PersistentProcessWithHistoryOnFileFromElm019Code(
IProcessStoreReader storeReader,
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmAppFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmAppFiles,
Action<string> logger,
ElmAppInterfaceConfig? overrideElmAppInterfaceConfig = null)
{
Expand Down
12 changes: 6 additions & 6 deletions implement/elm-fullstack/ElmFullstack/Process.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@ public class ProcessFromElm019Code
static public (IDisposableProcessWithStringInterface process,
(string javascriptFromElmMake, string javascriptPreparedToRun) buildArtifacts)
ProcessFromElmCodeFiles(
IReadOnlyCollection<(IImmutableList<string>, IImmutableList<byte>)> elmCodeFiles,
IReadOnlyCollection<(IImmutableList<string>, IReadOnlyList<byte>)> elmCodeFiles,
ElmAppInterfaceConfig? overrideElmAppInterfaceConfig = null) =>
ProcessFromElmCodeFiles(Composition.ToFlatDictionaryWithPathComparer(elmCodeFiles), overrideElmAppInterfaceConfig);

static public (IDisposableProcessWithStringInterface process,
(string javascriptFromElmMake, string javascriptPreparedToRun) buildArtifacts)
ProcessFromElmCodeFiles(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmCodeFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmCodeFiles,
ElmAppInterfaceConfig? overrideElmAppInterfaceConfig = null)
{
var elmAppInterfaceConfig = overrideElmAppInterfaceConfig ?? ElmAppInterfaceConfig.Default;
Expand All @@ -147,13 +147,13 @@ static public (IDisposableProcessWithStringInterface process,
}

static public string CompileElmToJavascript(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmCodeFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmCodeFiles,
IImmutableList<string> pathToFileWithElmEntryPoint,
string elmMakeCommandAppendix = null) =>
CompileElm(elmCodeFiles, pathToFileWithElmEntryPoint, "file-for-elm-make-output.js", elmMakeCommandAppendix);

static public string CompileElmToHtml(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmCodeFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmCodeFiles,
IImmutableList<string> pathToFileWithElmEntryPoint,
string elmMakeCommandAppendix = null) =>
CompileElm(elmCodeFiles, pathToFileWithElmEntryPoint, "file-for-elm-make-output.html", elmMakeCommandAppendix);
Expand All @@ -179,7 +179,7 @@ I cannot find that directory though! Is it missing? Is there a typo?
[...]
*/
static public string CompileElm(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> elmCodeFiles,
IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> elmCodeFiles,
IImmutableList<string> pathToFileWithElmEntryPoint,
string outputFileName,
string elmMakeCommandAppendix = null)
Expand All @@ -193,7 +193,7 @@ static public string CompileElm(

var command = "make " + Filesystem.MakePlatformSpecificPath(pathToFileWithElmEntryPoint) + " --output=\"" + outputFileName + "\" " + elmMakeCommandAppendix;

var attemptsResults = new List<(ExecutableFile.ProcessOutput processOutput, IReadOnlyCollection<(IImmutableList<string> path, IImmutableList<byte> content)> resultingFiles)>();
var attemptsResults = new List<(ExecutableFile.ProcessOutput processOutput, IReadOnlyCollection<(IImmutableList<string> path, IReadOnlyList<byte> content)> resultingFiles)>();

var environmentFiles =
elmCodeFiles.Select(file => (path: file.Key, content: file.Value)).ToImmutableList();
Expand Down
14 changes: 10 additions & 4 deletions implement/elm-fullstack/ElmFullstack/ProcessStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,14 @@ public ProcessStoreReaderInFileStore(IFileStore fileStore)
public IEnumerable<byte[]> EnumerateSerializedCompositionsRecordsReverse() =>
EnumerateCompositionsLogFilesPaths().Reverse()
.SelectMany(compositionFilePath =>
Encoding.UTF8.GetString(compositionFileStoreReader.GetFileContent(compositionFilePath))
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Reverse()
.Select(compositionRecord => Encoding.UTF8.GetBytes(compositionRecord)));
{
var fileContent = compositionFileStoreReader.GetFileContent(compositionFilePath);

return
Encoding.UTF8.GetString(fileContent as byte[] ?? fileContent.ToArray())
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Reverse()
.Select(compositionRecord => Encoding.UTF8.GetBytes(compositionRecord));
});

public ReductionRecord GetReduction(byte[] reducedCompositionHash)
{
Expand Down Expand Up @@ -152,7 +157,8 @@ public ReductionRecord GetReduction(byte[] reducedCompositionHash)
0;

var reductionRecordFromFile =
JsonConvert.DeserializeObject<ReductionRecordInFile>(Encoding.UTF8.GetString(fileContent.AsSpan(payloadStartIndex)));
JsonConvert.DeserializeObject<ReductionRecordInFile>(
Encoding.UTF8.GetString((fileContent as byte[] ?? fileContent.ToArray()).AsSpan(payloadStartIndex)));

if (reducedCompositionHashBase16 != reductionRecordFromFile.ReducedCompositionHashBase16)
throw new Exception("Unexpected content in file " + string.Join("/", filePath) + ", composition hash does not match.");
Expand Down
12 changes: 6 additions & 6 deletions implement/elm-fullstack/ElmInteractive/ElmInteractive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ static public JavaScriptEngineSwitcher.Core.IJsEngine PrepareJsEngineToEvaluateE
return javascriptEngine;
}

static public IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> ParseElmSyntaxAppCodeFiles() =>
ImmutableDictionary<IImmutableList<string>, IImmutableList<byte>>.Empty
static public IImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>> ParseElmSyntaxAppCodeFiles() =>
ImmutableDictionary<IImmutableList<string>, IReadOnlyList<byte>>.Empty
.WithComparers(EnumerableExtension.EqualityComparer<string>())
.SetItem(ImmutableList.Create("elm.json"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.elm.json").ToImmutableList())
.SetItem(ImmutableList.Create("src", "Pine.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.Pine.elm").ToImmutableList())
.SetItem(ImmutableList.Create("src", "ElmInteractive.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.ElmInteractive.elm").ToImmutableList())
.SetItem(ImmutableList.Create("src", "Main.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.Main.elm").ToImmutableList());
.SetItem(ImmutableList.Create("elm.json"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.elm.json"))
.SetItem(ImmutableList.Create("src", "Pine.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.Pine.elm"))
.SetItem(ImmutableList.Create("src", "ElmInteractive.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.ElmInteractive.elm"))
.SetItem(ImmutableList.Create("src", "Main.elm"), GetManifestResourceStreamContent("elm_fullstack.ElmInteractive.interpret_elm_program.src.Main.elm"));

static byte[] GetManifestResourceStreamContent(string name)
{
Expand Down
9 changes: 5 additions & 4 deletions implement/elm-fullstack/Pine/CommonConversion.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;

Expand All @@ -11,8 +12,8 @@ static public byte[] ByteArrayFromStringBase16(string base16) =>
.Select(octetIndex => Convert.ToByte(base16.Substring(octetIndex * 2, 2), 16))
.ToArray();

static public string StringBase16FromByteArray(byte[] array) =>
BitConverter.ToString(array).Replace("-", "").ToLowerInvariant();
static public string StringBase16FromByteArray(IReadOnlyList<byte> bytes) =>
BitConverter.ToString(bytes as byte[] ?? bytes.ToArray()).Replace("-", "").ToLowerInvariant();

static public byte[] HashSHA256(byte[] input)
{
Expand Down Expand Up @@ -55,12 +56,12 @@ static public byte[] Deflate(byte[] input)
return deflatedStream.ToArray();
}

static public byte[] Inflate(byte[] input)
static public byte[] Inflate(IReadOnlyList<byte> input)
{
using var inflatedStream = new System.IO.MemoryStream();

using var deflateStream = new System.IO.Compression.DeflateStream(
new System.IO.MemoryStream(input), System.IO.Compression.CompressionMode.Decompress);
new System.IO.MemoryStream(input as byte[] ?? input.ToArray()), System.IO.Compression.CompressionMode.Decompress);

deflateStream.CopyTo(inflatedStream);

Expand Down
Loading

0 comments on commit 289b468

Please sign in to comment.