Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Knobs to populate AppContext switches #86883

Merged
merged 5 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,11 @@ The .NET Foundation licenses this file to you under the MIT license.
<IlcArg Condition="'$(CustomNativeMain)' == 'true'" Include="--splitinit" />
<IlcArg Condition="$(ExportsFile) != ''" Include="--exportsfile:$(ExportsFile)" />
<IlcArg Include="@(AutoInitializedAssemblies->'--initassembly:%(Identity)')" />
<IlcArg Include="@(RuntimeHostConfigurationOption->'--appcontextswitch:%(Identity)=%(Value)')" />
<IlcArg Include="--appcontextswitch:RUNTIME_IDENTIFIER=$(RuntimeIdentifier)" />
<IlcArg Include="@(DirectPInvoke->'--directpinvoke:%(Identity)')" />
<IlcArg Include="@(DirectPInvokeList->'--directpinvokelist:%(Identity)')" />
<IlcArg Include="@(_TrimmerFeatureSettings->'--feature:%(Identity)=%(Value)')" />
<IlcArg Include="@(RuntimeHostConfigurationOption->'--runtimeknob:%(Identity)=%(Value)')" />
<IlcArg Include="--runtimeknob:RUNTIME_IDENTIFIER=$(RuntimeIdentifier)" />
<IlcArg Condition="$(ServerGarbageCollection) == 'true'" Include="--runtimeopt:gcServer=1" />
<IlcArg Condition="$(IlcGenerateCompleteTypeMetadata) == 'true' and $(IlcDisableReflection) != 'true'" Include="--completetypemetadata" />
<IlcArg Condition="$(IlcGenerateStackTraceData) == 'true'" Include="--stacktracedata" />
Expand Down
23 changes: 23 additions & 0 deletions src/coreclr/nativeaot/Runtime/MiscHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "GCMemoryHelpers.h"
#include "GCMemoryHelpers.inl"
#include "yieldprocessornormalized.h"
#include "RhConfig.h"

COOP_PINVOKE_HELPER(void, RhDebugBreak, ())
{
Expand Down Expand Up @@ -422,6 +423,28 @@ COOP_PINVOKE_HELPER(int32_t, RhGetProcessCpuCount, ())
return PalGetProcessCpuCount();
}

COOP_PINVOKE_HELPER(uint32_t, RhGetKnobValues, (Array * pResultKeyArray, Array * pResultValueArray))
{
// Note that we depend on the fact that this is a COOP helper to make writing into an unpinned array safe.

// If a result array is passed then it should be an array type with pointer-sized components that are not
// GC-references.
ASSERT(!pResultKeyArray || pResultKeyArray->get_EEType()->IsArray());
ASSERT(!pResultKeyArray || !pResultKeyArray->get_EEType()->HasReferenceFields());
ASSERT(!pResultKeyArray || pResultKeyArray->get_EEType()->RawGetComponentSize() == sizeof(void*));
ASSERT(!pResultKeyArray || pResultValueArray->get_EEType()->IsArray());
ASSERT(!pResultKeyArray || !pResultValueArray->get_EEType()->HasReferenceFields());
ASSERT(!pResultKeyArray || pResultValueArray->get_EEType()->RawGetComponentSize() == sizeof(void*));

if (pResultKeyArray)
{
g_pRhConfig->GetKnobNames((const char**)pResultKeyArray->GetArrayData(), pResultKeyArray->GetArrayLength());
g_pRhConfig->GetKnobValues((const char**)pResultValueArray->GetArrayData(), pResultValueArray->GetArrayLength());
}

return g_pRhConfig->GetKnobCount();
}

#if defined(TARGET_X86) || defined(TARGET_AMD64)
EXTERN_C NATIVEAOT_API void __cdecl RhCpuIdEx(int* cpuInfo, int functionId, int subFunctionId)
{
Expand Down
58 changes: 46 additions & 12 deletions src/coreclr/nativeaot/Runtime/RhConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ bool RhConfig::Environment::TryGetStringValue(const char* name, char** value)

struct CompilerEmbeddedSettingsBlob
{
uint32_t Size;
uint32_t Count;
char Data[1];
};

Expand Down Expand Up @@ -169,6 +169,41 @@ bool RhConfig::ReadKnobBooleanValue(_In_z_ const char *name, bool* pValue)
return false;
}

void RhConfig::GetKnobNames(const char** pBuffer, uint32_t count)
{
// Read the config if we haven't yet
if (g_embeddedKnobs == NULL)
{
ReadEmbeddedSettings(&g_embeddedKnobs, &g_compilerEmbeddedKnobsBlob);
}

const ConfigPair* configPairs = (const ConfigPair*)g_embeddedKnobs;
for (uint32_t i = 0; i < count && i < ((CompilerEmbeddedSettingsBlob*)&g_compilerEmbeddedKnobsBlob)->Count; i++)
{
pBuffer[i] = configPairs[i].Key;
}
}

void RhConfig::GetKnobValues(const char** pBuffer, uint32_t count)
{
// Read the config if we haven't yet
if (g_embeddedKnobs == NULL)
{
ReadEmbeddedSettings(&g_embeddedKnobs, &g_compilerEmbeddedKnobsBlob);
}

const ConfigPair* configPairs = (const ConfigPair*)g_embeddedKnobs;
for (uint32_t i = 0; i < count && i < ((CompilerEmbeddedSettingsBlob*)&g_compilerEmbeddedKnobsBlob)->Count; i++)
{
pBuffer[i] = configPairs[i].Value;
}
}

uint32_t RhConfig::GetKnobCount()
{
return ((CompilerEmbeddedSettingsBlob*)&g_compilerEmbeddedKnobsBlob)->Count;
}

bool RhConfig::GetEmbeddedVariable(void *volatile * embeddedSettings, void* compilerEmbeddedSettingsBlob, _In_z_ const char* configName, bool caseSensitive, _Out_ const char** configValue)
{
// Read the config if we haven't yet
Expand All @@ -186,7 +221,7 @@ bool RhConfig::GetEmbeddedVariable(void *volatile * embeddedSettings, void* comp
const ConfigPair* configPairs = (const ConfigPair*)*embeddedSettings;

// Find the first name which matches
for (uint32_t iSettings = 0; iSettings < ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Size; iSettings++)
for (uint32_t iSettings = 0; iSettings < ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Count; iSettings++)
{
if ((caseSensitive && strcmp(configName, configPairs[iSettings].Key) == 0)
|| (!caseSensitive && _stricmp(configName, configPairs[iSettings].Key) == 0))
Expand All @@ -204,19 +239,19 @@ void RhConfig::ReadEmbeddedSettings(void *volatile * embeddedSettings, void* com
{
if (*embeddedSettings == NULL)
{
uint32_t size = ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Size;
uint32_t count = ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Count;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're treating the size as count incorrectly in rest of the code (missed that in the code review). So this is also a bugfix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up deleting all of this.

It ran into an issue that we had a hard limit on how long a key or value can be and instead of writing more C code, I just deleted it and update the compiler to emit it in a format that we don't need to parse at all and just use as-is.

char* data = ((CompilerEmbeddedSettingsBlob*)compilerEmbeddedSettingsBlob)->Data;

//if reading the file contents failed set embeddedSettings to CONFIG_INI_NOT_AVAIL
if (size == 0)
if (count == 0)
{
//only set if another thread hasn't initialized the buffer yet, otherwise ignore and let the first setter win
PalInterlockedCompareExchangePointer(embeddedSettings, CONFIG_INI_NOT_AVAIL, NULL);

return;
}

ConfigPair* iniBuff = new (nothrow) ConfigPair[size];
ConfigPair* iniBuff = new (nothrow) ConfigPair[count];
if (iniBuff == NULL)
{
//only set if another thread hasn't initialized the buffer yet, otherwise ignore and let the first setter win
Expand All @@ -230,20 +265,19 @@ void RhConfig::ReadEmbeddedSettings(void *volatile * embeddedSettings, void* com
char* currLine;

//while we haven't reached the max number of config pairs, or the end of the file, read the next line
while (iBuff < size)
while (iIniBuff < count)
{
currLine = &data[iBuff];

//find the end of the line
while ((data[iBuff] != '\0') && (iBuff < size))
while ((data[iBuff] != '\0'))
iBuff++;

//parse the line
//only increment iIniBuff if the parsing succeeded otherwise reuse the config struct
if (ParseConfigLine(&iniBuff[iIniBuff], currLine))
{
iIniBuff++;
}
bool success = ParseConfigLine(&iniBuff[iIniBuff], currLine);
ASSERT(success);

iIniBuff++;

//advance to the next line;
iBuff++;
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/nativeaot/Runtime/RhConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class RhConfig
bool ReadKnobUInt64Value(_In_z_ const char* wszName, uint64_t* pValue);
bool ReadKnobBooleanValue(_In_z_ const char* wszName, bool* pValue);

void GetKnobNames(const char** pBuffer, uint32_t count);
void GetKnobValues(const char** pBuffer, uint32_t count);
uint32_t GetKnobCount();

#define DEFINE_VALUE_ACCESSOR(_name, defaultVal) \
uint64_t Get##_name() \
{ \
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Runtime;
using System.Runtime.ExceptionServices;
using System.Text;

namespace System
{
public static partial class AppContext
{
private static unsafe Dictionary<string, object?> InitializeDataStore()
{
uint count = RuntimeImports.RhGetKnobValues(null, null);

byte*[] keys = new byte*[count];
byte*[] values = new byte*[count];
RuntimeImports.RhGetKnobValues(keys, values);

var dataStore = new Dictionary<string, object?>((int)count);
for (int i = 0; i < count; i++)
{
dataStore.Add(
Encoding.UTF8.GetString(keys[i], string.strlen(keys[i])),
Encoding.UTF8.GetString(values[i], string.strlen(values[i])));
}

return dataStore;
}

[RuntimeExport("OnFirstChanceException")]
internal static void OnFirstChanceException(object e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,10 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
[RuntimeImport(RuntimeLibrary, "RhGetLoadedOSModules")]
internal static extern uint RhGetLoadedOSModules(IntPtr[] resultArray);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetKnobValues")]
internal static extern unsafe uint RhGetKnobValues(byte*[] keyArray, byte*[] valueArray);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
[RuntimeImport(RuntimeLibrary, "RhGetOSModuleFromPointer")]
internal static extern IntPtr RhGetOSModuleFromPointer(IntPtr pointerVal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,41 @@ namespace ILCompiler
/// </summary>
public class RuntimeConfigurationRootProvider : ICompilationRootProvider
{
private readonly IEnumerable<string> _runtimeOptions;
private readonly string _blobName;
private readonly IReadOnlyCollection<string> _runtimeOptions;

public RuntimeConfigurationRootProvider(IEnumerable<string> runtimeOptions)
public RuntimeConfigurationRootProvider(string blobName, IReadOnlyCollection<string> runtimeOptions)
{
_blobName = blobName;
_runtimeOptions = runtimeOptions;
}

void ICompilationRootProvider.AddCompilationRoots(IRootingServiceProvider rootProvider)
{
rootProvider.RootReadOnlyDataBlob(GetRuntimeOptionsBlob(), 4, "Runtime configuration information", "g_compilerEmbeddedSettingsBlob");
rootProvider.RootReadOnlyDataBlob(GetRuntimeOptionsBlob(), 4, "Runtime configuration information", _blobName);
}

protected byte[] GetRuntimeOptionsBlob()
private byte[] GetRuntimeOptionsBlob()
{
const int HeaderSize = 4;

ArrayBuilder<byte> options = default(ArrayBuilder<byte>);

// Reserve space for the header
options.ZeroExtend(HeaderSize);
int count = _runtimeOptions.Count;

options.Add((byte)count);
options.Add((byte)(count >> 8));
options.Add((byte)(count >> 0x10));
options.Add((byte)(count >> 0x18));

foreach (string option in _runtimeOptions)
{
byte[] optionBytes = System.Text.Encoding.ASCII.GetBytes(option);
byte[] optionBytes = System.Text.Encoding.UTF8.GetBytes(option);
options.Append(optionBytes);

// Emit a null to separate the next option
options.Add(0);
}

byte[] result = options.ToArray();

int length = options.Count - HeaderSize;

// Encode the size of the blob into the header
result[0] = (byte)length;
result[1] = (byte)(length >> 8);
result[2] = (byte)(length >> 0x10);
result[3] = (byte)(length >> 0x18);

return result;
return options.ToArray();
}
}
}

This file was deleted.

This file was deleted.

Loading