Tip: Mono ASP.NET application burning CPU in idle state - FileSystemWatcher

by grendel 13. May 2009 10:40

Update: added sample code to detect the watcher in use, courtesy of Robert Jordan - thanks!

mod_mono is an Apache module for hosting ASP.NET applications. The module itself doesn't run any .NET code, instead it spawns a backend server (mod-mono-server.exe for ASP.NET 1.1 and mod-mono-server2.exe for ASP.NET 2.0) which is handed all the requests coming in from the client browser and sends back response generated by the application.

If you run Mono on a VPS server (e.g. Xen, OpenVZ) then you don't usually have any control over what Linux kernel version and with what capabilities you run. It may happen that the kernel lacks capabilities used by parts of the Mono runtime and Mono will have to fall back to other methods of doing the same task. One such part is the FileSystemWatcher class which is used to monitor changes to files/directories on disk so that the application can take any steps it deems necessary in reaction to file creation/deletion/modification events.

Mono's FileSystemWatcher does its best to perform its assigned task in various environments, under various operating systems. Part of the effort is selecting the actual filesystem monitoring backend best for the runtime environment. Under Unix the supported backends are as follow:

  • FAM
  • kevent (BSD*/MacOSX only)
  • gamin
  • inotify (Linux only)
  • Managed watcher
Out of those, assuming you run Linux, inotify is the preferred backend mechanism as it requires no polling effort on userland application part, instead the Linux kernel will notify the application (in our case the Mono runtime) whenever interesting events happen. However, it requires the Linux kernel to support the mechanism and, what's more important, for your VPS operator to actually include the support in the kernel your VPS runs on.

If your kernel doesn't support inotify, Mono will attempt to use FAM and Gamin which are userland daemons doing active filesystem polling but outside of the consumer application. The consumer application will use provided FAM/Gamin libraries to receive events and react to them. Performance of this setup is worse than inotify but not tragic.

Should Mono fail to detect inotify, FAM or Gamin support, it will fall back to the last resort option - the managed watcher. This watcher is implemented in managed code and uses a separate thread for filesystem monitoring, polling for changes on selected files/directories. As the application may (and in the case of ASP.NET sometimes does) watch directories recursively, it might be a very expensive situation requiring checking changes to a big set of files. Each change detection run requires checking whether a file/directory exists (in case of the Managed watcher those are two stat (2) calls) and then checking the file metadata for changes (size, modification times etc) and, possibly, generating an event. This happens approximately every 750ms and can generate substantial load on the server's CPU.

If you notice (using top or htop applications) that your copy of mod-mono-server burns several per-cent of CPU but is otherwise in the S (Sleeping) process state, chances are your application is using the managed watcher. You can confirm that by using htop which allows you to watch individual process threads - you will see two threads consuming nearly the same amount of CPU time and one of them waking up every ~750ms.

The cure for the itch is easy, if you can live without filesystem monitoring (that means your application will not auto-restart when you modify Web.config, files won't be recompiled if you modify a code-behind .cs or an .aspx, .ascx etc. files). Mono supports a MONO_MANAGED_WATCHER environment variable which can be set to value disable with the effect of definitely disabling filesystem monitoring (it will use a "dumb" implementation of the watcher backend which does nothing) and relieve your application of the filesystem polling chores described above.

You can set the environment variable for your Apache VirtualHost by using the following mod_mono directive:

MonoSetEnv [server_alias] MONO_MANAGED_WATCHER=disable

Sample program to detect which watcher backend is used:

using System;
using System.Reflection;
using System.IO;

class Program {

	public static void Main()
	{
		object watcher = new FileSystemWatcher()
			.GetType ()
			.GetField ("watcher", BindingFlags.NonPublic | BindingFlags.Static)
			.GetValue (null);
		
		Console.WriteLine (watcher != null
				   ? watcher.GetType ().FullName
				   : "unknown");
	}
}

Tags:

Mono | mod_mono | Tip

Comments (5) -

Orion's Belt Game
Orion's Belt Game
5/15/2009 5:52:37 AM #

Hello,

I'm running the game at orionsbelt.eu with mono. I had that idle/100% problem _sometimes_ as you described. But when I changed to that settings, it got a lot worse!

I'm using mono fastcgi and I only added to the start script:
MONO_MANAGED_WATCHER=disable
export MONO_MANAGED_WATCHER
...
fastcgi-mono-server2

And the process was _always_ 100/300%. Today I commented the disable wather and it's fine... any ideas?


Reply

grendel
grendel
5/15/2009 3:08:45 PM #

It's hard to judge what your issue really is, as I don't know what are your application specifics, but are you sure you're not doing any active monitoring of some files, some periodical operation which requires a lot of CPU? Also, what is the version of Mono you use? To see what your application threads are doing when the situation happens again, please follow the instructions at mono-project.com/Debugging and file a but with that information at http://bugzilla.novell.com/

Reply

sdsdsdo
sdsdsdo
8/11/2010 9:40:59 PM #

I'm using mono fastcgi and I only added to the start script:
MONO_MANAGED_WATCHER=disable

Reply

Berry
Berry
8/17/2010 10:09:10 AM #

Hi Marek,

Are you sure about the 750ms timeframe? Using Powertop we have seen in our linux machine that the machine wakes up 20 times/second (50ms) and that mono is responsible for about 50-60% of these times. With this I would think mono would wakeup every 100ms. Or at least a lot sooner than 750ms.

Regards, Berry.

Reply

grendel
grendel
8/18/2010 4:19:46 AM #

Yes, I'm pretty sure about the 750ms - this is exactly the time the managed watcher's monitor thread spends sleeping between probes. There are other timers throughout Mono, which is what you might be observing with PowerTop.

Reply

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

RecentComments

Comment RSS