예제 #1
0
        /// <summary>
        /// Initialize shared channel.
        /// </summary>
        /// <param name="mlosContext">Mlos context instance.</param>
        public void InitializeSharedChannel(MlosContext mlosContext)
        {
            // #TODO, implement experiment class.
            //
            MlosContext.Instance = mlosContext;
            this.mlosContext     = mlosContext;

            // Initialize callbacks.
            //
            MlosProxyInternal.RegisterSettingsAssemblyRequestMessage.Callback         = RegisterSettingsAssemblyCallback;
            MlosProxyInternal.RegisterSharedConfigMemoryRegionRequestMessage.Callback = RegisterSharedConfigMemoryRegionRequestMessageCallback;
            MlosProxy.TerminateReaderThreadRequestMessage.Callback = TerminateReaderThreadRequestMessageCallback;

            // Register Mlos.Core assembly.
            //
            RegisterAssembly(typeof(MlosContext).Assembly, dispatchTableBaseIndex: 0);

            // Register shared config memory regions.
            //
            for (uint index = 1; index < mlosContext.GlobalMemoryRegion.TotalMemoryRegionCount; index++)
            {
                // Skip first one as this is global memory region, and it does not require registration.
                //
                RegisterSharedConfigMemoryRegion(sharedMemoryRegionIndex: index + 1);
            }

            // Register assemblies from the shared config.
            // Assembly Mlos.NetCore does not have a config, as it is always registered first.
            //
            for (uint index = 1; index < mlosContext.GlobalMemoryRegion.RegisteredSettingsAssemblyCount.Load(); index++)
            {
                RegisterSettingsAssembly(assemblyIndex: index);
            }
        }
예제 #2
0
        /// <summary>
        /// Initialize shared channel.
        /// </summary>
        /// <param name="mlosContext">Mlos context instance.</param>
        public void InitializeSharedChannel(MlosContext mlosContext)
        {
            this.mlosContext = mlosContext;

            // Set SharedConfig memory region.
            //
            sharedConfigManager.SetMemoryRegion(new MlosProxyInternal.SharedConfigMemoryRegion {
                Buffer = mlosContext.SharedConfigMemoryRegion.Buffer
            });

            // Setup MlosContext.
            //
            MlosContext.SharedConfigManager = sharedConfigManager;

            // Initialize callbacks.
            //
            MlosProxyInternal.RegisterAssemblyRequestMessage.Callback                 = RegisterAssemblyCallback;
            MlosProxyInternal.RegisterMemoryRegionRequestMessage.Callback             = RegisterMemoryRegionMessageCallback;
            MlosProxyInternal.RegisterSharedConfigMemoryRegionRequestMessage.Callback = RegisterSharedConfigMemoryRegionRequestMessageCallback;
            MlosProxy.TerminateReaderThreadRequestMessage.Callback = TerminateReaderThreadRequestMessageCallback;

            // Register Mlos.Core assembly.
            //
            RegisterAssembly(typeof(MlosContext).Assembly, dispatchTableBaseIndex: 0);

            // Register assemblies from the shared config.
            // Assembly Mlos.NetCore does not have a config, as it is always registered first.
            //
            for (uint index = 1; index < mlosContext.GlobalMemoryRegion.RegisteredSettingsAssemblyCount.Load(); index++)
            {
                RegisterSettingsAssembly(assemblyIndex: index);
            }
        }
예제 #3
0
        protected virtual void Dispose(bool disposing)
        {
            if (isDisposed || !disposing)
            {
                return;
            }

            // Dispose MlosContext.
            //
            mlosContext?.Dispose();
            mlosContext = null;

            isDisposed = true;
        }
예제 #4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ExperimentSession"/> class.
 /// </summary>
 /// <param name="mlosContext"></param>
 public ExperimentSession(MlosContext mlosContext)
 {
     this.mlosContext = mlosContext;
 }
예제 #5
0
        /// <summary>
        /// The main external agent server.
        /// </summary>
        /// <param name="args">command line arguments.</param>
        public static void Main(string[] args)
        {
            string executableFilePath  = null;
            Uri    optimizerAddressUri = null;

            CliOptionsParser.ParseArgs(args, out executableFilePath, out optimizerAddressUri);

            // Check for the executable before setting up any shared memory to
            // reduce cleanup issues.
            //
            if (executableFilePath != null && !File.Exists(executableFilePath))
            {
                throw new FileNotFoundException($"ERROR: --executable '{executableFilePath}' does not exist.");
            }

            Console.WriteLine("Mlos.Agent.Server");
            TargetProcessManager targetProcessManager = null;

            // Connect to gRpc optimizer only if user provided an address in the command line.
            //
            if (optimizerAddressUri != null)
            {
                Console.WriteLine("Connecting to the Mlos.Optimizer");

                // This switch must be set before creating the GrpcChannel/HttpClient.
                //
                AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

                // This populates a variable for the various settings registry
                // callback handlers to use (by means of their individual
                // AssemblyInitializers) to know how they can connect with the
                // optimizer.
                //
                // See Also: AssemblyInitializer.cs within the SettingsRegistry
                // assembly project in question.
                //
                MlosContext.OptimizerFactory = new MlosOptimizer.BayesianOptimizerFactory(optimizerAddressUri);
            }

            // In the active learning mode, create a new shared memory map before running the target process.
            // On Linux, we unlink existing shared memory map, if they exist.
            // If the agent is not in the active learning mode, create new or open existing to communicate with the target process.
            //
            using MlosContext mlosContext = (executableFilePath != null)
                ? InterProcessMlosContext.Create()
                : InterProcessMlosContext.CreateOrOpen();
            using var mainAgent = new MainAgent();
            mainAgent.InitializeSharedChannel(mlosContext);

            // Active learning mode.
            //
            // TODO: In active learning mode the MlosAgentServer can control the
            // workload against the target component.
            //
            if (executableFilePath != null)
            {
                Console.WriteLine($"Starting {executableFilePath}");
                targetProcessManager = new TargetProcessManager(executableFilePath: executableFilePath);
                targetProcessManager.StartTargetProcess();
            }
            else
            {
                Console.WriteLine("No executable given to launch.  Will wait for agent to connect independently.");
            }

            var cancellationTokenSource = new CancellationTokenSource();

            Task grpcServerTask = CreateHostBuilder(Array.Empty <string>()).Build().RunAsync(cancellationTokenSource.Token);

            // Start the MainAgent message processing loop as a background thread.
            //
            // In MainAgent.RunAgent we loop on the shared memory control and
            // telemetry channels looking for messages and dispatching them to

            // their registered callback handlers.
            //
            // The set of recognized messages is dynamically registered using

            // the RegisterSettingsAssembly method which is called through the
            // handler for the RegisterAssemblyRequestMessage.
            //
            // Once registered, the SettingsAssemblyManager uses reflection to

            // search for an AssemblyInitializer inside those assemblies and
            // executes it in order to setup the message handler callbacks
            // within the agent.
            //
            // See Also: AssemblyInitializer.cs within the SettingsRegistry
            // assembly project in question.
            //
            Console.WriteLine("Starting Mlos.Agent");
            Task mlosAgentTask = Task.Factory.StartNew(
                () => mainAgent.RunAgent(),
                CancellationToken.None,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Current);

            Task waitForTargetProcessTask = Task.Factory.StartNew(
                () =>
            {
                if (targetProcessManager != null)
                {
                    targetProcessManager.WaitForTargetProcessToExit();
                    targetProcessManager.Dispose();
                    mainAgent.UninitializeSharedChannel();
                }
            },
                CancellationToken.None,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Current);

            Console.WriteLine("Waiting for Mlos.Agent to exit");

            while (true)
            {
                Task.WaitAny(mlosAgentTask, waitForTargetProcessTask);

                if (mlosAgentTask.IsFaulted && targetProcessManager != null && !waitForTargetProcessTask.IsCompleted)
                {
                    // MlosAgentTask has failed, however the target process is still active.
                    // Terminate the target process and continue shutdown.
                    //
                    targetProcessManager.TerminateTargetProcess();
                    continue;
                }

                if (mlosAgentTask.IsCompleted && waitForTargetProcessTask.IsCompleted)
                {
                    // MlosAgentTask is no longer processing messages, and target process does no longer exist.
                    // Shutdown the agent.
                    //
                    break;
                }
            }

            // Print any exceptions if occurred.
            //
            if (mlosAgentTask.Exception != null)
            {
                Console.WriteLine($"Exception: {mlosAgentTask.Exception}");
            }

            if (waitForTargetProcessTask.Exception != null)
            {
                Console.WriteLine($"Exception: {waitForTargetProcessTask.Exception}");
            }

            // Perform some cleanup.
            //
            waitForTargetProcessTask.Dispose();

            mlosAgentTask.Dispose();

            targetProcessManager?.Dispose();

            cancellationTokenSource.Cancel();
            grpcServerTask.Wait();

            grpcServerTask.Dispose();
            cancellationTokenSource.Dispose();

            Console.WriteLine("Mlos.Agent exited.");
        }
예제 #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SmartCacheExperimentSession"/> class.
        /// This is the entry point for setting up the message handlers for the
        /// messages code generated from the (partial) structs defined for this
        /// smart component in the CodeGen/SmartCache.cs.
        /// </summary>
        /// <remarks>
        /// See class comments for further details.
        /// </remarks>
        /// <param name="mlosContext"></param>
        public SmartCacheExperimentSession(MlosContext mlosContext)
            : base(mlosContext)
        {
            // Setup message callbacks.
            //
            // Note: these message properties are code generated from the
            // (partial) structs in CodeGen/SmartCache.cs
            //
            // See out/Mlos.CodeGen.out/SmartCache/*.cs for the C# code
            // generation output from those partial definitions.
            //
            SmartCacheProxy.CacheRequestEventMessage.Callback       = CacheRequestEventMessageHandler;
            SmartCacheProxy.RequestNewConfigurationMessage.Callback = RequestNewConfigurationMessageHandler;

            // Create smart cache parameter search space.
            //
            // These hypergrids define the combination of valid ranges
            // of values for the different tunables.
            // Note that some of these are interdependent.
            //
            // TODO: Eventually this will also be code generated from additional
            // "domain range" attributes on the "ScalarSettings" defined for the
            // component (see also CodeGen/SmartCache.cs)
            //
            Hypergrid cacheSearchSpace = new Hypergrid(
                name: "smart_cache_config",
                dimension: new CategoricalDimension("cache_implementation", CacheEvictionPolicy.LeastRecentlyUsed, CacheEvictionPolicy.MostRecentlyUsed))
                                         .Join(
                subgrid: new Hypergrid(
                    name: "lru_cache_config",
                    dimension: new DiscreteDimension("cache_size", min: 1, max: 1 << 12)),
                onExternalDimension: new CategoricalDimension("cache_implementation", CacheEvictionPolicy.LeastRecentlyUsed))
                                         .Join(
                subgrid: new Hypergrid(
                    name: "mru_cache_config",
                    dimension: new DiscreteDimension("cache_size", min: 1, max: 1 << 12)),
                onExternalDimension: new CategoricalDimension("cache_implementation", CacheEvictionPolicy.MostRecentlyUsed));

            // Create optimization problem.
            //
            // Here we declare to the optimizer what our desired output from the
            // component to optimize is.
            //
            // In this case we declare "hit rate", which will be calculated as a
            // percentage, is the thing we want the optimizer to improve.
            //
            var optimizationProblem = new OptimizationProblem
            {
                ParameterSpace = cacheSearchSpace,
                ContextSpace   = null,
                ObjectiveSpace = new Hypergrid(
                    name: "objectives",
                    dimensions: new ContinuousDimension(name: "HitRate", min: 0.0, max: 1.0)),
            };

            // Define optimization objective.
            //
            optimizationProblem.Objectives.Add(
                new OptimizationObjective
            {
                // Tell the optimizer that we want to maximize hit rate.
                //
                Name     = "HitRate",
                Minimize = false,
            });

            // Get a local reference to the optimizer to reuse when processing messages later on.
            //
            // Note: we read this from a global variable that should have been
            // setup for the Mlos.Agent (e.g. in the Mlos.Agent.Server).
            //
            IOptimizerFactory optimizerFactory = MlosContext.OptimizerFactory;

            optimizerProxy = optimizerFactory?.CreateRemoteOptimizer(optimizationProblem: optimizationProblem);
        }
예제 #7
0
        /// <summary>
        /// The main external agent server.
        /// </summary>
        /// <param name="args">command line arguments.</param>
        /// <returns>Returns exit code.</returns>
        public static int Main(string[] args)
        {
            CliOptionsParser.CliOptions parserOptions = CliOptionsParser.ParseArgs(args);

            if (!string.IsNullOrEmpty(parserOptions.ExperimentFilePath) && !File.Exists(parserOptions.ExperimentFilePath))
            {
                throw new FileNotFoundException($"ERROR: --experiment '{parserOptions.ExperimentFilePath}' does not exist.");
            }

            if (!string.IsNullOrEmpty(parserOptions.SettingsRegistryPath))
            {
                // #TODO temporary hack
                //
                Environment.SetEnvironmentVariable("MLOS_SETTINGS_REGISTRY_PATH", parserOptions.SettingsRegistryPath);
            }

            Console.WriteLine("Mlos.Agent.Server");

            // Active learning mode.
            //
            // TODO: In active learning mode the MlosAgentServer can control the
            // workload against the target component.
            //
            TargetProcessManager targetProcessManager = null;

            if (parserOptions.Executable != null)
            {
                Console.WriteLine($"Starting: '{parserOptions.Executable}'");
                targetProcessManager = new TargetProcessManager(executableFilePath: parserOptions.Executable);
                targetProcessManager.StartTargetProcess();

                Console.WriteLine($"Launched process: '{Path.GetFileName(parserOptions.Executable)}'");
            }
            else
            {
                Console.WriteLine("No executable given to launch.  Will wait for agent to connect independently.");
            }

            // Create a Mlos context.
            //
            using MlosContext mlosContext = MlosContextFactory.Create();

            // Connect to gRpc optimizer only if user provided an address in the command line.
            //
            if (parserOptions.OptimizerUri != null)
            {
                Console.WriteLine("Connecting to the Mlos.Optimizer");

                // This switch must be set before creating the GrpcChannel/HttpClient.
                //
                AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

                // This populates a variable for the various settings registry
                // callback handlers to use (by means of their individual
                // ExperimentSession instances) to know how they can connect with
                // the optimizer.
                //
                // See SmartCacheExperimentSession.cs for an example.
                //
                mlosContext.OptimizerFactory = new MlosOptimizer.BayesianOptimizerFactory(parserOptions.OptimizerUri);
            }

            var experimentSessionManager = new ExperimentSessionManager(mlosContext);

            using var mainAgent = new MainAgent();
            mainAgent.InitializeSharedChannel(mlosContext);

            // If specified, load the experiment assembly.
            //
            if (!string.IsNullOrEmpty(parserOptions.ExperimentFilePath))
            {
                experimentSessionManager.LoadExperiment(parserOptions.ExperimentFilePath);
            }

            var cancellationTokenSource = new CancellationTokenSource();

            Task grpcServerTask = CreateHostBuilder(Array.Empty <string>()).Build().RunAsync(cancellationTokenSource.Token);

            // Start the MainAgent message processing loop as a background thread.
            //
            // In MainAgent.RunAgent we loop on the shared memory control and
            // telemetry channels looking for messages and dispatching them to
            // their registered callback handlers.
            //
            // The set of recognized messages is dynamically registered using
            // the RegisterSettingsAssembly method which is called through the
            // handler for the RegisterAssemblyRequestMessage.
            //
            // Once registered, the ExperimentSessionManager can creates an
            // instance of the requested ExperimentSession in order to setup the
            // message handler callbacks for the components messages within the
            // agent.
            //
            // See SmartCacheExperimentSession.cs for an example.
            //
            Console.WriteLine("Starting Mlos.Agent");
            Task mlosAgentTask = Task.Factory.StartNew(
                () => mainAgent.RunAgent(),
                CancellationToken.None,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Current);

            Task waitForTargetProcessTask = Task.Factory.StartNew(
                () =>
            {
                if (targetProcessManager != null)
                {
                    targetProcessManager.WaitForTargetProcessToExit();
                    targetProcessManager.Dispose();
                    mainAgent.UninitializeSharedChannel();
                }
            },
                CancellationToken.None,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Current);

            Console.WriteLine("Waiting for Mlos.Agent to exit");

            while (true)
            {
                Task.WaitAny(mlosAgentTask, waitForTargetProcessTask);

                if (mlosAgentTask.IsFaulted && targetProcessManager != null && !waitForTargetProcessTask.IsCompleted)
                {
                    // MlosAgentTask has failed, however the target process is still active.
                    // Terminate the target process and continue shutdown.
                    //
                    targetProcessManager.TerminateTargetProcess();
                    continue;
                }

                if (mlosAgentTask.IsCompleted && waitForTargetProcessTask.IsCompleted)
                {
                    // MlosAgentTask is no longer processing messages, and target process does no longer exist.
                    // Shutdown the agent.
                    //
                    break;
                }
            }

            int exitCode = 0;

            // Print any exceptions if occurred.
            //
            if (mlosAgentTask.Exception != null)
            {
                Console.WriteLine($"Exception: {mlosAgentTask.Exception}");
                exitCode |= 1;
            }

            if (waitForTargetProcessTask.Exception != null)
            {
                Console.WriteLine($"Exception: {waitForTargetProcessTask.Exception}");
                exitCode |= 2;
            }

            // Perform some cleanup.
            //
            waitForTargetProcessTask.Dispose();

            mlosAgentTask.Dispose();

            targetProcessManager?.Dispose();

            cancellationTokenSource.Cancel();
            grpcServerTask.Wait();

            grpcServerTask.Dispose();
            cancellationTokenSource.Dispose();

            Console.WriteLine("Mlos.Agent exited.");

            return(exitCode);
        }