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