The attached patch implements 3 "Network Interface" performance category counters. The counters are "Bytes Received/sec", "Bytes Sent/sec", and "Bytes Total/sec". A sample program using these counters and sample output is attached as well.

This information is obtained by reading /proc/net/dev.

The patch changes the following files:

mono/metadata/ChangeLog
mono/metadata/mono-perfcounters-def.h
mono/metadata/mono-perfcounters.c
mono/utils/ChangeLog
mono/utils/mono-proclib.c
mono/utils/mono-proclib.h

jr


diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog
index a954bee..4094799 100644
--- a/mono/metadata/ChangeLog
+++ b/mono/metadata/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-25  Joel W. Reed <joelwr...@gmail.com>
+
+	* mono-perfcounters.c, mono-perfcounters-def.h: Add
+	network performance counters for bytes sent per second, bytes
+	received per second, and bytes total per second.
+
 2009-09-22  Zoltan Varga  <var...@gmail.com>
 
 	* image.c (mono_image_close): Atomically decrement the reference count and
diff --git a/mono/metadata/mono-perfcounters-def.h b/mono/metadata/mono-perfcounters-def.h
index 1a7cbab..367d12e 100644
--- a/mono/metadata/mono-perfcounters-def.h
+++ b/mono/metadata/mono-perfcounters-def.h
@@ -119,3 +119,7 @@ PERFCTR_COUNTER(SECURITY_LCHECKS, "# Link Time Checks", "", NumberOfItems32, sec
 PERFCTR_COUNTER(SECURITY_PERCTIME, "% Time in RT checks", "", RawFraction, security_time)
 PERFCTR_COUNTER(SECURITY_SWDEPTH, "Stack Walk Depth", "", NumberOfItems32, security_depth)
 
+PERFCTR_CAT(NETWORK, "Network Interface", "", MultiInstance, NetworkInterface, NETWORK_BYTESRECSEC)
+PERFCTR_COUNTER(NETWORK_BYTESRECSEC, "Bytes Received/sec", "", RateOfCountsPerSecond64, unused)
+PERFCTR_COUNTER(NETWORK_BYTESSENTSEC, "Bytes Sent/sec", "", RateOfCountsPerSecond64, unused)
+PERFCTR_COUNTER(NETWORK_BYTESTOTALSEC, "Bytes Total/sec", "", RateOfCountsPerSecond64, unused)
diff --git a/mono/metadata/mono-perfcounters.c b/mono/metadata/mono-perfcounters.c
index 8451091..e5ccca2 100644
--- a/mono/metadata/mono-perfcounters.c
+++ b/mono/metadata/mono-perfcounters.c
@@ -98,6 +98,7 @@ enum {
 	ThreadInstance,
 	CPUInstance,
 	MonoInstance,
+	NetworkInterfaceInstance,
 	CustomInstance
 };
 
@@ -283,6 +284,11 @@ struct _ImplVtable {
 };
 
 typedef struct {
+	int id;
+	char *name;
+} NetworkVtableArg;
+
+typedef struct {
 	ImplVtable vtable;
 	MonoPerfCounters *counters;
 	int pid;
@@ -686,6 +692,60 @@ cpu_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean
 }
 
 static MonoBoolean
+get_network_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
+{
+	MonoNetworkError error = MONO_NETWORK_ERROR_OTHER;
+	NetworkVtableArg *narg = (NetworkVtableArg*) vtable->arg;
+	if (!only_value) {
+		fill_sample (sample);
+	}
+
+	sample->counterType = predef_counters [predef_categories [CATEGORY_NETWORK].first_counter + narg->id].type;
+	switch (narg->id) {
+	case COUNTER_NETWORK_BYTESRECSEC:
+		sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESREC, &error);
+		break;
+	case COUNTER_NETWORK_BYTESSENTSEC:
+		sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESSENT, &error);
+		break;
+	case COUNTER_NETWORK_BYTESTOTALSEC:
+		sample->rawValue = mono_network_get_data (narg->name, MONO_NETWORK_BYTESTOTAL, &error);
+		break;
+	}
+
+	if (error == MONO_NETWORK_ERROR_NONE)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static void
+network_cleanup (ImplVtable *vtable)
+{
+	if (vtable->arg) 
+		g_free(vtable->arg);
+}
+
+static void*
+network_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+{
+	const CounterDesc *cdesc;
+	NetworkVtableArg *narg;
+	ImplVtable *vtable;
+	*custom = FALSE;
+	if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
+		narg = g_new0 (NetworkVtableArg, 1);
+		narg->id = cdesc->id;
+		narg->name = mono_string_to_utf8 (instance);
+		*type = cdesc->type;
+		vtable = create_vtable (narg, get_network_counter, NULL);
+		vtable->cleanup = network_cleanup;
+		return vtable;
+	}
+	return NULL;
+}
+
+static MonoBoolean
 get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *sample)
 {
 	int id = GPOINTER_TO_INT (vtable->arg);
@@ -1033,6 +1093,8 @@ mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString
 		return process_get_impl (counter, instance, type, custom);
 	case CATEGORY_MONO_MEM:
 		return mono_mem_get_impl (counter, instance, type, custom);
+	case CATEGORY_NETWORK:
+		return network_get_impl (counter, instance, type, custom);
 	case CATEGORY_JIT:
 	case CATEGORY_EXC:
 	case CATEGORY_GC:
@@ -1343,6 +1405,21 @@ get_string_array (void **array, int count, gboolean is_process)
 }
 
 static MonoArray*
+get_string_array_of_strings (void **array, int count)
+{
+	int i;
+	MonoDomain *domain = mono_domain_get ();
+	MonoArray * res = mono_array_new (mono_domain_get (), mono_get_string_class (), count);
+	for (i = 0; i < count; ++i) {
+		char* p = array[i];
+		mono_array_setref (res, i, mono_string_new (domain, p));
+		g_free (p);
+	}
+
+	return res;
+}
+
+static MonoArray*
 get_mono_instances (void)
 {
 	int count = 64;
@@ -1389,6 +1466,19 @@ get_processes_instances (void)
 }
 
 static MonoArray*
+get_networkinterface_instances (void)
+{
+	MonoArray *array;
+	int count = 0;
+	void **buf = mono_networkinterface_list (&count);
+	if (!buf)
+		return get_string_array_of_strings (NULL, 0);
+	array = get_string_array_of_strings (buf, count);
+	g_free (buf);
+	return array;
+}
+
+static MonoArray*
 get_custom_instances (MonoString *category)
 {
 	SharedCategory *scat;
@@ -1425,6 +1515,8 @@ mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
 		return get_cpu_instances ();
 	case ProcessInstance:
 		return get_processes_instances ();
+	case NetworkInterfaceInstance:
+		return get_networkinterface_instances ();
 	case ThreadInstance:
 	default:
 		return mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
diff --git a/mono/utils/ChangeLog b/mono/utils/ChangeLog
index 6361561..9c0db40 100644
--- a/mono/utils/ChangeLog
+++ b/mono/utils/ChangeLog
@@ -1,3 +1,8 @@
+2009-09-25  Joel W. Reed <joelwr...@gmail.com>
+
+	* mono-proclib.c, mono-proclib.h: Read
+	network statistics from "/proc/net/dev" for performance counters.
+
 2009-09-02 Rodrigo Kumpera  <rkump...@novell.com>
 
 	* mono-sha1.c: Update documentation.
diff --git a/mono/utils/mono-proclib.c b/mono/utils/mono-proclib.c
index fa5f293..f345db9 100644
--- a/mono/utils/mono-proclib.c
+++ b/mono/utils/mono-proclib.c
@@ -103,6 +103,129 @@ mono_process_list (int *size)
 #endif
 }
 
+/**
+ * mono_networkinterface_list:
+ * @size: a pointer to a location where the size of the returned array is stored
+ *
+ * Return an array of names for the interfaces currently on the system.
+ * The size of the array is stored in @size.
+ */
+gpointer*
+mono_networkinterface_list (int *size)
+{
+	int i = 0, count = 0;
+	void **nilist = NULL;
+	char buf[512];
+	char name[256];
+	FILE *f;
+
+	f = fopen ("/proc/net/dev", "r");
+	if (!f) 
+		return NULL;
+
+	if (! fgets (buf, sizeof(buf)/sizeof(char), f))
+		goto out;
+
+	if (!fgets (buf, sizeof(buf)/sizeof(char), f))
+		goto out;
+
+	while (fgets (buf, sizeof(buf), f) != NULL) {
+
+		char *ptr;
+		buf[sizeof(buf) - 1] = 0;
+		if ((ptr = strchr(buf, ':')) == NULL ||
+				(*ptr++ = 0, sscanf(buf, "%s", name) != 1))
+			goto out;
+
+		if (i >= count) {
+			if (!count)
+				count = 16;
+			else
+				count *= 2;
+		}
+
+		nilist = g_realloc (nilist, count * sizeof (void*));
+		nilist [i++] = g_strdup(name);
+	}
+
+ out:
+	if (f) fclose(f);
+	if (size)
+		*size = i;
+	return nilist;
+}
+
+/**
+ * mono_network_get_data:
+ * @name: name of the interface
+ * @data: description of data to return
+ *
+ * Return a data item of a network adapter like bytes sent per sec, etc
+ * according to the @data argumet.
+ */
+gint64
+mono_network_get_data (char* name, MonoNetworkData data, MonoNetworkError *error)
+{
+	gint64 val = 0;
+	char buf[512];
+	char cname[256];
+	FILE *f;
+
+	unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
+		rx_fifo, rx_frame, tx_bytes, tx_packets, tx_errs, tx_drops,
+		tx_fifo, tx_colls, tx_carrier, rx_multi;
+
+	if (error)
+		*error = MONO_NETWORK_ERROR_OTHER;
+
+	f = fopen ("/proc/net/dev", "r");
+	if (!f) 
+		return -1;
+
+	if (! fgets (buf, sizeof(buf)/sizeof(char), f))
+		goto out;
+
+	if (!fgets (buf, sizeof(buf)/sizeof(char), f))
+		goto out;
+
+	while (fgets (buf, sizeof(buf), f) != NULL) {
+
+		char *ptr;
+		buf[sizeof(buf) - 1] = 0;
+		if ((ptr = strchr(buf, ':')) == NULL ||
+				(*ptr++ = 0, sscanf(buf, "%s", cname) != 1))
+			goto out;
+
+		if (strcmp(name, cname) != 0) continue;
+
+		if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
+							 &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
+							 &rx_fifo, &rx_frame, &rx_multi,
+							 &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
+							 &tx_fifo, &tx_colls, &tx_carrier) != 14) 
+			goto out;
+
+		switch (data) {
+		case MONO_NETWORK_BYTESSENT:
+			val = tx_bytes;
+			*error = MONO_NETWORK_ERROR_NONE;
+			goto out;
+		case MONO_NETWORK_BYTESREC:
+			val = rx_bytes;
+			*error = MONO_NETWORK_ERROR_NONE;
+			goto out;
+		case MONO_NETWORK_BYTESTOTAL:
+			val = rx_bytes + tx_bytes;
+			*error = MONO_NETWORK_ERROR_NONE;
+			goto out;
+		}
+	}
+
+ out:
+	if (f) fclose(f);
+	return val;
+}
+
 static char*
 get_pid_status_item_buf (int pid, const char *item, char *rbuf, int blen, MonoProcessError *error)
 {
diff --git a/mono/utils/mono-proclib.h b/mono/utils/mono-proclib.h
index 710aefe..5569475 100644
--- a/mono/utils/mono-proclib.h
+++ b/mono/utils/mono-proclib.h
@@ -40,6 +40,18 @@ typedef enum {
 	MONO_PROCESS_ERROR_OTHER
 } MonoProcessError;
 
+typedef enum {
+	MONO_NETWORK_BYTESREC,
+	MONO_NETWORK_BYTESSENT,
+	MONO_NETWORK_BYTESTOTAL
+} MonoNetworkData;
+
+typedef enum {
+	MONO_NETWORK_ERROR_NONE, /* no error happened */
+	MONO_NETWORK_ERROR_NOT_FOUND, /* adapter name invalid */
+	MONO_NETWORK_ERROR_OTHER
+} MonoNetworkError;
+
 gpointer* mono_process_list     (int *size) MONO_INTERNAL;
 
 char*     mono_process_get_name (gpointer pid, char *buf, int len) MONO_INTERNAL;
@@ -50,5 +62,8 @@ gint64    mono_process_get_data_with_error (gpointer pid, MonoProcessData data,
 int       mono_cpu_count    (void) MONO_INTERNAL;
 gint64    mono_cpu_get_data (int cpu_id, MonoCpuData data, MonoProcessError *error) MONO_INTERNAL;
 
+gpointer* mono_networkinterface_list     (int *size) MONO_INTERNAL;
+gint64    mono_network_get_data (char* name, MonoNetworkData data, MonoNetworkError *error) MONO_INTERNAL;
+
 #endif /* __MONO_PROC_LIB_H__ */
 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace PerfMon
{
    class NetworkInterface
    {
        private PerformanceCounter pcr;
        private PerformanceCounter pcs;
        private PerformanceCounter pct;

        public NetworkInterface(string name)
        {
            Name = name;

            pcr = new PerformanceCounter("Network Interface", "Bytes Received/sec", name);
						pcr.NextValue();

            pcs = new PerformanceCounter("Network Interface", "Bytes Sent/sec", name);
						pcs.NextValue();

            pct = new PerformanceCounter("Network Interface", "Bytes Total/sec", name);
						pct.NextValue();
        }

        public string Name { get; set; }

        public double BytesReceivedPerSec
        {
            get
            {
                return pcr.NextValue();
            }
        }

        public double BytesSentPerSec
        {
            get
            {
							return pcs.NextValue();
            }
        }

        public double BytesTotalPerSec
        {
            get
            {
							return pct.NextValue();
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            PerformanceCounterCategory category = new PerformanceCounterCategory("Network Interface");

            List<NetworkInterface> networkInterfaces = new List<NetworkInterface>();
            foreach (string name in category.GetInstanceNames())
            {
                Console.WriteLine(name);
                networkInterfaces.Add(new NetworkInterface(name));
            }

            while (true)
            {
                foreach (NetworkInterface ni in networkInterfaces)
                {
									Console.WriteLine("{0}: Bytes Received/sec: {1}, Bytes Sent/sec: {2}, Bytes Total/sec: {3}", ni.Name, ni.BytesReceivedPerSec, ni.BytesSentPerSec, ni.BytesTotalPerSec);
                }

                Console.WriteLine();
                System.Threading.Thread.Sleep(2000);
            }

            Console.ReadKey();
        }
    }
}


lo
eth0
lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 83.6617126464844, Bytes Sent/sec: 97.6053314208984, 
Bytes Total/sec: 181.267044067383

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 83.8287048339844, Bytes Sent/sec: 97.8001556396484, 
Bytes Total/sec: 181.628860473633

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 83.8287048339844, Bytes Sent/sec: 97.8001556396484, 
Bytes Total/sec: 181.628860473633

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 83.9963531494141, Bytes Sent/sec: 97.9957504272461, 
Bytes Total/sec: 181.992095947266

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 127159.9921875, Bytes Sent/sec: 22947.109375, Bytes 
Total/sec: 149591.140625

lo: Bytes Received/sec: 0, Bytes Sent/sec: 0, Bytes Total/sec: 0
eth0: Bytes Received/sec: 1277.33508300781, Bytes Sent/sec: 929.101501464844, 
Bytes Total/sec: 2176.90551757813



_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to