2 // SystemInformation.cs
4 // Copyright (C) 2004-2006 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
28 using System
.Collections
;
29 using System
.Diagnostics
;
30 using System
.Globalization
;
32 using System
.Reflection
;
33 using System
.Runtime
.CompilerServices
;
34 using System
.Runtime
.InteropServices
;
36 using System
.Text
.RegularExpressions
;
38 namespace Beagle
.Util
{
40 public class SystemInformation
{
42 [DllImport ("libc", SetLastError
=true)]
43 static extern int getloadavg (double[] loadavg
, int nelem
);
45 const double loadavg_poll_delay
= 3;
46 private static DateTime proc_loadavg_time
= DateTime
.MinValue
;
47 private static double cached_loadavg_1min
= -1;
48 private static double cached_loadavg_5min
= -1;
49 private static double cached_loadavg_15min
= -1;
51 private static void CheckLoadAverage ()
53 // Only call getloadavg() at most once every 10 seconds
54 if ((DateTime
.Now
- proc_loadavg_time
).TotalSeconds
< loadavg_poll_delay
)
57 double [] loadavg
= new double [3];
58 int retval
= getloadavg (loadavg
, 3);
61 throw new IOException ("Could not get system load average: " + Mono
.Unix
.Native
.Stdlib
.strerror (Mono
.Unix
.Native
.Stdlib
.GetLastError ()));
63 throw new IOException ("Could not get system load average: getloadavg() returned an unexpected number of samples");
65 cached_loadavg_1min
= loadavg
[0];
66 cached_loadavg_5min
= loadavg
[1];
67 cached_loadavg_15min
= loadavg
[2];
69 proc_loadavg_time
= DateTime
.Now
;
72 public static double LoadAverageOneMinute
{
75 return cached_loadavg_1min
;
79 public static double LoadAverageFiveMinute
{
82 return cached_loadavg_5min
;
86 public static double LoadAverageFifteenMinute
{
89 return cached_loadavg_15min
;
93 ///////////////////////////////////////////////////////////////
95 private static bool use_screensaver
= false;
96 const double screensaver_poll_delay
= 1;
97 private static DateTime screensaver_time
= DateTime
.MinValue
;
98 private static bool cached_screensaver_running
= false;
99 private static double cached_screensaver_idle_time
= 0;
101 private enum ScreenSaverState
{
108 private enum ScreenSaverKind
{
114 [DllImport ("libbeagleglue.so")]
115 extern static unsafe int screensaver_glue_init ();
117 public static bool XssInit ()
119 return XssInit (false);
122 public static bool XssInit (bool actually_init_xss
)
124 int has_xss
= screensaver_glue_init ();
125 use_screensaver
= (has_xss
== 1);
126 return use_screensaver
;
129 [DllImport ("libbeagleglue.so")]
130 extern static unsafe int screensaver_info (ScreenSaverState
*state
,
131 ScreenSaverKind
*kind
,
135 private static void CheckScreenSaver ()
137 if (! use_screensaver
)
140 if ((DateTime
.Now
- screensaver_time
).TotalSeconds
< screensaver_poll_delay
)
143 ScreenSaverState state
;
144 ScreenSaverKind kind
;
145 ulong til_or_since
= 0, idle
= 0;
149 retval
= screensaver_info (&state
, &kind
, &til_or_since
, &idle
);
153 cached_screensaver_running
= (state
== ScreenSaverState
.On
);
154 cached_screensaver_idle_time
= idle
/ 1000.0;
156 cached_screensaver_running
= false;
157 cached_screensaver_idle_time
= 0;
160 screensaver_time
= DateTime
.Now
;
163 public static bool ScreenSaverRunning
{
166 return cached_screensaver_running
;
170 // returns number of seconds since input was received
171 // from the user on any input device
172 public static double InputIdleTime
{
175 return cached_screensaver_idle_time
;
179 ///////////////////////////////////////////////////////////////
181 const double acpi_poll_delay
= 30;
182 const string ac_present_string
= "on-line";
184 private static readonly string[] proc_ac_state_filenames
= new string[] {
185 "/proc/acpi/ac_adapter/AC/state",
186 "/proc/acpi/ac_adapter/AC0/state",
187 "/proc/acpi/ac_adapter/ADp1/state"
190 private static string proc_ac_state_filename
= null;
191 private static bool proc_ac_state_exists
= true;
192 private static DateTime using_battery_time
= DateTime
.MinValue
;
193 private static bool using_battery
;
195 public static void CheckAcpi ()
197 if (! proc_ac_state_exists
)
200 if ((DateTime
.Now
- using_battery_time
).TotalSeconds
< acpi_poll_delay
)
203 if (proc_ac_state_filename
== null) {
204 foreach (string s
in proc_ac_state_filenames
) {
205 if (File
.Exists (s
)) {
206 proc_ac_state_filename
= s
;
212 if (proc_ac_state_filename
== null || ! File
.Exists (proc_ac_state_filename
)) {
213 proc_ac_state_exists
= false;
214 using_battery
= false;
218 Stream stream
= new FileStream (proc_ac_state_filename
,
219 System
.IO
.FileMode
.Open
,
222 TextReader reader
= new StreamReader (stream
);
224 string line
= reader
.ReadLine ();
225 using_battery
= (line
!= null) && (line
.IndexOf (ac_present_string
) == -1);
230 using_battery_time
= DateTime
.Now
;
233 public static bool UsingBattery
{
236 return using_battery
;
240 ///////////////////////////////////////////////////////////////
242 [DllImport ("libbeagleglue")]
243 extern static int get_vmsize ();
245 [DllImport ("libbeagleglue")]
246 extern static int get_vmrss ();
248 public static int VmSize
{
249 get { return get_vmsize (); }
252 public static int VmRss
{
253 get { return get_vmrss (); }
256 public static void LogMemoryUsage ()
258 int vm_size
= VmSize
;
261 Logger
.Log
.Debug ("Memory usage: VmSize={0:.0} MB, VmRSS={1:.0} MB, GC.GetTotalMemory={2}",
262 vm_size
/1024.0, vm_rss
/1024.0, GC
.GetTotalMemory (false));
265 ///////////////////////////////////////////////////////////////
267 // Internal calls have to be installed before mono accesses the
268 // class that uses them. That's why we have this retarded extra
269 // class and initializer function. Paolo says this is a *HUGE*
270 // unsupported hack and not to be surprised if it doesn't work.
271 public class InternalCallInitializer
{
272 [DllImport ("libbeagleglue", EntryPoint
="mono_glue_install_icall")]
273 public extern static void Init ();
276 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
277 public extern static int GetObjectSizeIcall (object o
);
279 public static int GetObjectSize (object o
)
282 return GetObjectSizeIcall (o
);
283 } catch (MissingMethodException
) {
288 [MethodImplAttribute (MethodImplOptions
.InternalCall
)]
289 public extern static int GetObjectPointerIcall (object o
);
291 public static long GetObjectPointer (object o
)
294 return GetObjectPointerIcall (o
);
295 } catch (MissingMethodException
) {
300 ///////////////////////////////////////////////////////////////
302 private static int disk_stats_read_reqs
;
303 private static int disk_stats_write_reqs
;
304 private static int disk_stats_read_bytes
;
305 private static int disk_stats_write_bytes
;
307 private static DateTime disk_stats_time
= DateTime
.MinValue
;
308 private static double disk_stats_delay
= 1.0;
310 private static uint major
, minor
;
312 // Update the disk statistics with data for block device on the (major,minor) pair.
313 private static void UpdateDiskStats ()
320 // We only refresh the stats once per second
321 if ((DateTime
.Now
- disk_stats_time
).TotalSeconds
< disk_stats_delay
)
324 // Read in all of the disk stats
325 using (StreamReader stream
= new StreamReader ("/proc/diskstats"))
326 buffer
= stream
.ReadToEnd ();
328 // Find our partition and parse it
329 const string REGEX
= "[\\s]+{0}[\\s]+{1}[\\s]+[a-zA-Z0-9]+[\\s]+([0-9]+)[\\s]+([0-9]+)[\\s]+([0-9]+)[\\s]+([0-9]+)";
330 string regex
= String
.Format (REGEX
, major
, minor
);
331 Regex r
= new Regex (regex
, RegexOptions
.IgnoreCase
| RegexOptions
.Compiled
);
332 for (System
.Text
.RegularExpressions
.Match m
= r
.Match (buffer
); m
.Success
; m
= m
.NextMatch ()) {
333 disk_stats_read_reqs
= Convert
.ToInt32 (m
.Groups
[1].ToString ());
334 disk_stats_read_bytes
= Convert
.ToInt32 (m
.Groups
[2].ToString ());
335 disk_stats_write_reqs
= Convert
.ToInt32 (m
.Groups
[3].ToString ());
336 disk_stats_write_bytes
= Convert
.ToInt32 (m
.Groups
[4].ToString ());
339 disk_stats_time
= DateTime
.Now
;
342 // Get the (major,minor) pair for the block device from which the index is mounted.
343 private static void GetIndexDev ()
345 Mono
.Unix
.Native
.Stat stat
;
346 if (Mono
.Unix
.Native
.Syscall
.stat (PathFinder
.StorageDir
, out stat
) != 0)
349 major
= (uint) stat
.st_dev
>> 8;
350 minor
= (uint) stat
.st_dev
& 0xff;
353 public static int DiskStatsReadReqs
{
358 return disk_stats_read_reqs
;
362 public static int DiskStatsReadBytes
{
367 return disk_stats_read_bytes
;
371 public static int DiskStatsWriteReqs
{
376 return disk_stats_write_reqs
;
380 public static int DiskStatsWriteBytes
{
385 return disk_stats_write_bytes
;
389 public static bool IsPathOnBlockDevice (string path
)
391 Mono
.Unix
.Native
.Stat stat
;
392 if (Mono
.Unix
.Native
.Syscall
.stat (path
, out stat
) != 0)
395 return (stat
.st_dev
>> 8 != 0);
398 ///////////////////////////////////////////////////////////////
401 private static extern int prctl (int option
, byte [] arg2
, ulong arg3
, ulong arg4
, ulong arg5
);
403 // From /usr/include/linux/prctl.h
404 private const int PR_SET_NAME
= 15;
406 public static void SetProcessName(string name
)
409 if (prctl (PR_SET_NAME
, Encoding
.ASCII
.GetBytes (name
+ '\0'), 0, 0, 0) < 0) {
410 Logger
.Log
.Warn ("Couldn't set process name to '{0}': {1}", name
,
411 Mono
.Unix
.Native
.Stdlib
.GetLastError ());
416 ///////////////////////////////////////////////////////////////
418 public static string MonoRuntimeVersion
{
420 Type t
= typeof (object).Assembly
.GetType ("Mono.Runtime");
422 string ver
= (string) t
.InvokeMember ("GetDisplayName",
423 BindingFlags
.InvokeMethod
424 | BindingFlags
.NonPublic
425 | BindingFlags
.Static
426 | BindingFlags
.DeclaredOnly
427 | BindingFlags
.ExactBinding
,
434 ///////////////////////////////////////////////////////////////
437 public static void Main ()
440 Console
.WriteLine ("{0} {1} {2} {3} {4} {5} {6} {7}",
441 LoadAverageOneMinute
,
442 LoadAverageFiveMinute
,
443 LoadAverageFifteenMinute
,
449 System
.Threading
.Thread
.Sleep (1000);