public RService() : base() { string RLogFilename = DirectoryHelper.GetLogFileName(); this._log = new RDotNetConsoleLogDevice(); this._log.LogDevice = new Journal() { FileName = RLogFilename }; logService.WriteToLogLevel("R DotNet Server (deepest function call) initialization started.", LogLevelEnum.Info); try { StartupParameter sp = new StartupParameter(); REngine.SetEnvironmentVariables(null, null );//can set R Path and R Home by passing params this._RServer = REngine.GetInstance();//null, true, null, _log); this._RServer.Initialize(); logService.WriteToLogLevel("R DotNet Server initialized.", LogLevelEnum.Info); //writes to ApplicationLog _log.WriteConsole("R.Net Initialized!!!", 1024, RDotNet.Internals.ConsoleOutputType.None); //writes to RLog } catch (Exception ex) { _log.WriteConsole("Unable to initialize R Server.(note: 64bit R must already be present)", 5, RDotNet.Internals.ConsoleOutputType.None);//Added by Anil logService.WriteToLogLevel("Unable to initialize R Server.", LogLevelEnum.Error, ex); throw new Exception(); } logService.WriteToLogLevel("R DotNet Server (deepest function call) initialization ended.", LogLevelEnum.Info); }
/// <summary> /// Gets a reference to the R engine, creating and initializing it if necessary. In most cases users need not provide any parameter to this method. /// </summary> /// <param name="dll">The file name of the library to load, e.g. "R.dll" for Windows. You usually do not need need to provide this optional parameter</param> /// <param name="initialize">Initialize the R engine after its creation. Default is true</param> /// <param name="parameter">If 'initialize' is 'true', you can optionally specify the specific startup parameters for the R native engine</param> /// <param name="device">If 'initialize' is 'true', you can optionally specify a character device for the R engine to use</param> /// <returns>The engine.</returns> /// <example> /// <p>A minimalist approach is to just call GetInstance</p> /// <code> /// REngine.SetEnvironmentVariables(); /// var engine = REngine.GetInstance(); /// engine.Evaluate("letters[1:26]"); /// </code> /// <p>In unusual circumstances you may need to elaborate on the initialization in a separate method call</p> /// <code> /// REngine.SetEnvironmentVariables(rPath=@"c:\my\peculiar\path\to\R\bin\x64"); /// var engine = REngine.GetInstance(initialize=false); /// StartupParameter sParams=new StartupParameter(){NoRenviron=true;}; /// ICharacterDevice device = new YourCustomDevice(); /// engine.Initialize(parameter: sParams, device: device); /// engine.Evaluate("letters[1:26]"); /// </code> /// </example> public static REngine GetInstance(string dll = null, bool initialize = true, StartupParameter parameter = null, ICharacterDevice device = null) { if (!environmentIsSet) // should there be a warning? and how? { SetEnvironmentVariables(); } if (engine == null) { engine = CreateInstance(EngineName, dll); if (initialize) { engine.Initialize(parameter, device); } else { DetermineCompatibility(engine); } } if (engine.Disposed) { throw new InvalidOperationException("The single REngine instance has already been disposed of (i.e. shut down). Multiple engine restart is not possible."); } return(engine); }
[Test, Ignore] // Cannot run this in a batch with the new singleton pattern. public void TestInitParams() { MockDevice device = new MockDevice(); REngine.SetEnvironmentVariables(); using (var engine = REngine.GetInstance()) { ulong maxMemSize = 128 * 1024 * 1024; StartupParameter parameter = new StartupParameter() { MaxMemorySize = maxMemSize, }; engine.Initialize(parameter: parameter, device: device); Assert.AreEqual(engine.Evaluate("memory.limit()").AsNumeric()[0], 128.0); } }
[Fact(Skip = "Cannot run this in a batch with the new singleton pattern")] // Cannot run this in a batch with the new singleton pattern. public void TestInitParams() { MockDevice device = new MockDevice(); REngine.SetEnvironmentVariables(); using (var engine = REngine.GetInstance()) { ulong maxMemSize = 128 * 1024 * 1024; StartupParameter parameter = new StartupParameter() { MaxMemorySize = maxMemSize, }; engine.Initialize(parameter: parameter, device: device); Assert.Equal(engine.Evaluate("memory.limit()").AsNumeric()[0], 128.0); } }
/// <summary> /// Creates the command line arguments corresponding to the specified startup parameters /// </summary> /// <param name="parameter"></param> /// <returns></returns> /// <remarks>While not obvious from the R documentation, it seems that command line arguments need to be passed /// to get the startup parameters taken into account. Passing the StartupParameter to the API seems not to work as expected. /// While this function may appear like an oddity to a reader, it proved necessary to the initialisation of the R engine /// after much trial and error.</remarks> public static string[] BuildRArgv(StartupParameter parameter) { var platform = NativeUtility.GetPlatform(); var argv = new List<string>(); argv.Add("rdotnet_app"); // Not sure whether I should add no-readline //[MarshalAs(UnmanagedType.Bool)] //public bool R_Quiet; if (parameter.Quiet && !parameter.Interactive) argv.Add("--quiet"); // --quite --interactive to R embedded crashed... //[MarshalAs(UnmanagedType.Bool)] //public bool R_Slave; if (parameter.Slave) argv.Add("--slave"); //[MarshalAs(UnmanagedType.Bool)] //public bool R_Interactive; if (platform != PlatformID.Win32NT) // RTerm.exe --help shows no such option; Unix only. if (parameter.Interactive) argv.Add("--interactive"); //[MarshalAs(UnmanagedType.Bool)] //public bool R_Verbose; if (parameter.Verbose) argv.Add("--verbose"); //[MarshalAs(UnmanagedType.Bool)] //public bool LoadSiteFile; if (!parameter.LoadSiteFile) argv.Add("--no-site-file"); //[MarshalAs(UnmanagedType.Bool)] //public bool LoadInitFile; if (!parameter.LoadInitFile) argv.Add("--no-init-file"); //[MarshalAs(UnmanagedType.Bool)] //public bool DebugInitFile; //if (parameter.Quiet) argv.Add("--quiet"); //public StartupRestoreAction RestoreAction; //public StartupSaveAction SaveAction; //internal UIntPtr vsize; //internal UIntPtr nsize; //internal UIntPtr max_vsize; //internal UIntPtr max_nsize; //internal UIntPtr ppsize; //[MarshalAs(UnmanagedType.Bool)] //public bool NoRenviron; if (parameter.NoRenviron) argv.Add("--no-environ"); switch (parameter.SaveAction) { case StartupSaveAction.NoSave: argv.Add("--no-save"); break; case StartupSaveAction.Save: argv.Add("--save"); break; } switch (parameter.RestoreAction) { case StartupRestoreAction.NoRestore: argv.Add("--no-restore-data"); break; case StartupRestoreAction.Restore: argv.Add("--restore"); break; } if (parameter.MaxMemorySize == (Environment.Is64BitProcess ? ulong.MaxValue : uint.MaxValue)) { // This creates a nasty crash if using the default MaxMemorySize. found out in Rdotnet workitem 72 // do nothing } else { if (platform == PlatformID.Win32NT) // On unix, otherwise led to https://rdotnet.codeplex.com/workitem/137 argv.Add("--max-mem-size=" + parameter.MaxMemorySize); } argv.Add("--max-ppsize=" + parameter.StackSize); return argv.ToArray(); }
/// <summary> /// Initialize this REngine object. Only the first call has an effect. Subsequent calls to this function are ignored. /// </summary> /// <param name="parameter">The optional startup parameters</param> /// <param name="device">The optional character device to use for the R engine</param> /// <param name="setupMainLoop">if true, call the functions to initialise the embedded R</param> public void Initialize(StartupParameter parameter = null, ICharacterDevice device = null, bool setupMainLoop = true) { // Console.WriteLine("REngine.Initialize start"); if (this.isRunning) return; // Console.WriteLine("REngine.Initialize, after isRunning checked as false"); this.parameter = parameter ?? new StartupParameter(); this.adapter = new CharacterDeviceAdapter(device ?? DefaultDevice); // Disabling the stack checking here, to try to avoid the issue on Linux. // The disabling used to be here around end Nov 2013. Was moved later in this // function to cater for disabling on Windows, @ rev 305, however this may have // re-broken on Linux. so we may need to call it twice. SetCstackChecking(); // Console.WriteLine("Initialize-SetCstackChecking; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); if (!setupMainLoop) { this.isRunning = true; return; } string[] R_argv = BuildRArgv(this.parameter); //string[] R_argv = new[]{"rdotnet_app", "--interactive", "--no-save", "--no-restore-data", "--max-ppsize=50000"}; //rdotnet_app --quiet --interactive --no-save --no-restore-data --max-mem-size=18446744073709551615 --max-ppsize=50000 GetFunction<R_setStartTime>()(); int R_argc = R_argv.Length; // Console.WriteLine("Initialize-R_setStartTime; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); if (NativeUtility.GetPlatform() == PlatformID.Win32NT) { // Attempted Fix for https://rdotnet.codeplex.com/workitem/110; not working // Tried to make sure that the command line options are taken into account. They are NOT effectively so via Rf_initialize_R only. // The problem is that cmdlineoptions assumes it is called by RGui.exe or RTerm.exe, and overrides R_HOME // GetFunction<R_set_command_line_arguments>()(R_argc, R_argv); // GetFunction<cmdlineoptions>()(R_argc, R_argv); } var status = GetFunction<Rf_initialize_R>()(R_argc, R_argv); if (status != 0) throw new Exception("A call to Rf_initialize_R returned a non-zero; status=" + status); // Console.WriteLine("Initialize-Rf_initialize_R; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); SetCstackChecking(); // following in RInside: may not be needed. //GetFunction<R_ReplDLLinit> () (); //this.parameter.Interactive = true; this.adapter.Install(this, this.parameter); //Console.WriteLine("Initialize-adapter installation; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); switch (NativeUtility.GetPlatform()) { case PlatformID.Win32NT: GetFunction<R_SetParams_Windows>("R_SetParams")(ref this.parameter.start); break; case PlatformID.MacOSX: case PlatformID.Unix: GetFunction<R_SetParams_Unix>("R_SetParams")(ref this.parameter.start.Common); //Console.WriteLine("Initialize-R_SetParams_Unix; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); break; } GetFunction<setup_Rmainloop>()(); //Console.WriteLine("Initialize-after setup_Rmainloop; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); // See comments in the first call to SetCstackChecking in this function as to why we (may) need it twice. SetCstackChecking(); this.isRunning = true; //Console.WriteLine("Initialize-just before leaving; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); // Partial Workaround (hopefully temporary) for https://rdotnet.codeplex.com/workitem/110 if (NativeUtility.GetPlatform() == PlatformID.Win32NT) { Evaluate(string.Format("invisible(memory.limit({0}))", (this.parameter.MaxMemorySize / 1048576UL))); } }
/// <summary> /// Gets a reference to the R engine, creating and initializing it if necessary. In most cases users need not provide any parameter to this method. /// </summary> /// <param name="dll">The file name of the library to load, e.g. "R.dll" for Windows. You usually do not need need to provide this optional parameter</param> /// <param name="initialize">Initialize the R engine after its creation. Default is true</param> /// <param name="parameter">If 'initialize' is 'true', you can optionally specify the specific startup parameters for the R native engine</param> /// <param name="device">If 'initialize' is 'true', you can optionally specify a character device for the R engine to use</param> /// <returns>The engine.</returns> /// <example> /// <p>A minimalist approach is to just call GetInstance</p> /// <code> /// REngine.SetEnvironmentVariables(); /// var engine = REngine.GetInstance(); /// engine.Evaluate("letters[1:26]"); /// </code> /// <p>In unusual circumstances you may need to elaborate on the initialization in a separate method call</p> /// <code> /// REngine.SetEnvironmentVariables(rPath=@"c:\my\peculiar\path\to\R\bin\x64"); /// var engine = REngine.GetInstance(initialize=false); /// StartupParameter sParams=new StartupParameter(){NoRenviron=true;}; /// ICharacterDevice device = new YourCustomDevice(); /// engine.Initialize(parameter: sParams, device: device); /// engine.Evaluate("letters[1:26]"); /// </code> /// </example> public static REngine GetInstance(string dll = null, bool initialize = true, StartupParameter parameter = null, ICharacterDevice device = null) { if (!environmentIsSet) // should there be a warning? and how? SetEnvironmentVariables(); if (engine == null) { engine = CreateInstance(EngineName, dll); if (initialize) engine.Initialize(parameter, device); } if (engine.Disposed) throw new InvalidOperationException("The single REngine instance has already been disposed of (i.e. shut down). Multiple engine restart is not possible."); return engine; }
/// <summary> /// Creates the command line arguments corresponding to the specified startup parameters /// </summary> /// <param name="parameter"></param> /// <returns></returns> /// <remarks>While not obvious from the R documentation, it seems that command line arguments need to be passed /// to get the startup parameters taken into account. Passing the StartupParameter to the API seems not to work as expected. /// While this function may appear like an oddity to a reader, it proved necessary to the initialisation of the R engine /// after much trial and error.</remarks> public static string[] BuildRArgv(StartupParameter parameter) { var platform = NativeUtility.GetPlatform(); var argv = new List <string>(); argv.Add("rdotnet_app"); // Not sure whether I should add no-readline //[MarshalAs(UnmanagedType.Bool)] //public bool R_Quiet; if (parameter.Quiet && !parameter.Interactive) { argv.Add("--quiet"); // --quite --interactive to R embedded crashed... } //[MarshalAs(UnmanagedType.Bool)] //public bool R_Slave; if (parameter.Slave) { argv.Add("--slave"); } //[MarshalAs(UnmanagedType.Bool)] //public bool R_Interactive; if (platform != PlatformID.Win32NT) // RTerm.exe --help shows no such option; Unix only. { if (parameter.Interactive) { argv.Add("--interactive"); } } //[MarshalAs(UnmanagedType.Bool)] //public bool R_Verbose; if (parameter.Verbose) { argv.Add("--verbose"); } //[MarshalAs(UnmanagedType.Bool)] //public bool LoadSiteFile; if (!parameter.LoadSiteFile) { argv.Add("--no-site-file"); } //[MarshalAs(UnmanagedType.Bool)] //public bool LoadInitFile; if (!parameter.LoadInitFile) { argv.Add("--no-init-file"); } //[MarshalAs(UnmanagedType.Bool)] //public bool DebugInitFile; //if (parameter.Quiet) argv.Add("--quiet"); //public StartupRestoreAction RestoreAction; //public StartupSaveAction SaveAction; //internal UIntPtr vsize; //internal UIntPtr nsize; //internal UIntPtr max_vsize; //internal UIntPtr max_nsize; //internal UIntPtr ppsize; //[MarshalAs(UnmanagedType.Bool)] //public bool NoRenviron; if (parameter.NoRenviron) { argv.Add("--no-environ"); } switch (parameter.SaveAction) { case StartupSaveAction.NoSave: argv.Add("--no-save"); break; case StartupSaveAction.Save: argv.Add("--save"); break; } switch (parameter.RestoreAction) { case StartupRestoreAction.NoRestore: argv.Add("--no-restore-data"); break; case StartupRestoreAction.Restore: argv.Add("--restore"); break; } if (parameter.MaxMemorySize == (Environment.Is64BitProcess ? ulong.MaxValue : uint.MaxValue)) { // This creates a nasty crash if using the default MaxMemorySize. found out in Rdotnet workitem 72 // do nothing } else { if (platform == PlatformID.Win32NT) // On unix, otherwise led to https://rdotnet.codeplex.com/workitem/137 { argv.Add("--max-mem-size=" + parameter.MaxMemorySize); } } argv.Add("--max-ppsize=" + parameter.StackSize); return(argv.ToArray()); }
/// <summary> /// Initialize this REngine object. Only the first call has an effect. Subsequent calls to this function are ignored. /// </summary> /// <param name="parameter">The optional startup parameters</param> /// <param name="device">The optional character device to use for the R engine</param> /// <param name="setupMainLoop">if true, call the functions to initialise the embedded R</param> public void Initialize(StartupParameter parameter = null, ICharacterDevice device = null, bool setupMainLoop = true) { // Console.WriteLine("REngine.Initialize start"); if (this.isRunning) { return; } // Console.WriteLine("REngine.Initialize, after isRunning checked as false"); this.parameter = parameter ?? new StartupParameter(); this.adapter = new CharacterDeviceAdapter(device ?? DefaultDevice); // Disabling the stack checking here, to try to avoid the issue on Linux. // The disabling used to be here around end Nov 2013. Was moved later in this // function to cater for disabling on Windows, @ rev 305, however this may have // re-broken on Linux. so we may need to call it twice. SetCstackChecking(); // Console.WriteLine("Initialize-SetCstackChecking; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); if (!setupMainLoop) { this.isRunning = true; return; } string[] R_argv = BuildRArgv(this.parameter); //string[] R_argv = new[]{"rdotnet_app", "--interactive", "--no-save", "--no-restore-data", "--max-ppsize=50000"}; //rdotnet_app --quiet --interactive --no-save --no-restore-data --max-mem-size=18446744073709551615 --max-ppsize=50000 GetFunction <R_setStartTime>()(); int R_argc = R_argv.Length; // Console.WriteLine("Initialize-R_setStartTime; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); if (NativeUtility.GetPlatform() == PlatformID.Win32NT) { // Attempted Fix for https://rdotnet.codeplex.com/workitem/110; not working // Tried to make sure that the command line options are taken into account. They are NOT effectively so via Rf_initialize_R only. // The problem is that cmdlineoptions assumes it is called by RGui.exe or RTerm.exe, and overrides R_HOME // GetFunction<R_set_command_line_arguments>()(R_argc, R_argv); // GetFunction<cmdlineoptions>()(R_argc, R_argv); } var status = GetFunction <Rf_initialize_R>()(R_argc, R_argv); if (status != 0) { throw new Exception("A call to Rf_initialize_R returned a non-zero; status=" + status); } // Console.WriteLine("Initialize-Rf_initialize_R; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); SetCstackChecking(); // following in RInside: may not be needed. //GetFunction<R_ReplDLLinit> () (); //this.parameter.Interactive = true; this.adapter.Install(this, this.parameter); //Console.WriteLine("Initialize-adapter installation; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); switch (NativeUtility.GetPlatform()) { case PlatformID.Win32NT: GetFunction <R_SetParams_Windows>("R_SetParams")(ref this.parameter.start); break; case PlatformID.MacOSX: case PlatformID.Unix: GetFunction <R_SetParams_Unix>("R_SetParams")(ref this.parameter.start.Common); //Console.WriteLine("Initialize-R_SetParams_Unix; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); break; } GetFunction <setup_Rmainloop>()(); //Console.WriteLine("Initialize-after setup_Rmainloop; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); // See comments in the first call to SetCstackChecking in this function as to why we (may) need it twice. SetCstackChecking(); this.isRunning = true; //Console.WriteLine("Initialize-just before leaving; R_CStackLimit value is " + GetDangerousInt32("R_CStackLimit")); // Partial Workaround (hopefully temporary) for https://rdotnet.codeplex.com/workitem/110 if (NativeUtility.GetPlatform() == PlatformID.Win32NT) { Evaluate(string.Format("invisible(memory.limit({0}))", (this.parameter.MaxMemorySize / 1048576UL))); } }