public static void Main(string[] args) { // TODO: use some proper arg parser. For now let's keep it simple. // string executableFilePath = null; string modelsDatabaseConnectionDetailsFile = null; foreach (string arg in args) { if (Path.GetExtension(arg) == ".exe") { executableFilePath = arg; } else if (Path.GetExtension(arg) == ".json") { modelsDatabaseConnectionDetailsFile = arg; } } Console.WriteLine("Mlos.Agent.Server"); TargetProcessManager targetProcessManager = null; // Since the models database and optimizer factory are part of the "intelligence" it belongs to the Mlos.Agent.Server. // ModelsDatabase modelsDatabase = new ModelsDatabase(modelsDatabaseConnectionDetailsFile); SimpleBayesianOptimizerFactory optimizerFactory = new SimpleBayesianOptimizerFactory(modelsDatabase); // Since component assemblies need to use the optimizerFactory (at least for now) we put it in the GlobalProperties. // MlosContext.OptimizerFactory = optimizerFactory; // Create circular buffer shared memory before running the target process. // MainAgent.InitializeSharedChannel(); // Active learning, almost done. In active learning the MlosAgentServer controls the workload against the target component. // if (executableFilePath != null) { targetProcessManager = new TargetProcessManager(executableFilePath: executableFilePath); targetProcessManager.StartTargetProcess(); } var cancelationTokenSource = new CancellationTokenSource(); Task grpcServerTask = CreateHostBuilder(Array.Empty <string>()).Build().RunAsync(cancelationTokenSource.Token); Console.WriteLine("Starting Mlos.Agent"); Task mlosAgentTask = Task.Factory.StartNew( () => MainAgent.RunAgent(), TaskCreationOptions.LongRunning); if (targetProcessManager != null) { targetProcessManager.WaitForTargetProcessToExit(); targetProcessManager.Dispose(); MainAgent.UninitializeSharedChannel(); } Console.WriteLine("Waiting for Mlos.Agent to exit"); mlosAgentTask.Wait(); mlosAgentTask.Dispose(); cancelationTokenSource.Cancel(); grpcServerTask.Wait(); grpcServerTask.Dispose(); cancelationTokenSource.Dispose(); Console.WriteLine("Mlos.Agent exited."); }
/// <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."); }
/// <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); }