Example #1
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.");
        }
Example #2
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);
        }