[PATCH] Precision timing patch for load.[c|h]

Kannel Neo <[email protected]> Tue, 28 Jun 2016 10:44:23 +0200
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <CACWxDgOJHPStoons-qBMH+soMmi_O-B5e0SmadVpCXTmJMXuWA@mail.gmail.com>
Hi all,

We are running a very high performance Kannel instance (>1000
messages/second at times).

We are finding throttling errors from our upstream suppliers because the
load counters inside Kannel are too imprecise, being that they only update
after 1 second due to the fact that they are using time in seconds.

For example, you set the throughput of your SMPP bind to 200 per second, if
you have a fast machine, your bind can send more than 200 messages in a
second and then only subsequently realise (as the second ticks over) that
it has exceeded the throughput and waiting.

Herewith the attached patch which will allow precision load timers to
update these rates intra-second.

We are using this and find it helps a great deal.

Thanks
precision_timing.patch (application/octet-stream, 2.9 KB)
Index: gw/load.c
===================================================================
--- gw/load.c	(revision 5164)
+++ gw/load.c	(working copy)
@@ -67,7 +67,7 @@
 struct load_entry {
     float prev;
     float curr;
-    time_t last;
+    double last;
     int interval;
     int dirty;
 };
@@ -80,7 +80,25 @@
     RWLock *lock;
 };
 
+double microtime(double *p) {
+    struct timeval tv;
+    struct timezone tz;
+    struct tm *tm;
+    gettimeofday(&tv, &tz);
+    
+    double result = tv.tv_sec + (1e-6 * tv.tv_usec);
+    
+    if(p != NULL) {
+        *p = result;
+    }
+    
+    return result;
+}
 
+double microtime_diff(double end, double start) {
+    return (end - start);
+}
+
 Load* load_create_real(int heuristic)
 {
     struct load *load;
@@ -117,7 +135,7 @@
     entry->prev = entry->curr = 0.0;
     entry->interval = interval;
     entry->dirty = 1;
-    time(&entry->last);
+    microtime(&entry->last);
     
     load->entries = gw_realloc(load->entries, sizeof(struct load*) * (load->len + 1));
     load->entries[load->len] = entry;
@@ -147,17 +165,17 @@
 
 void load_increase_with(Load *load, unsigned long value)
 {
-    time_t now;
+    double now;
     int i;
     
     if (load == NULL)
         return;
     gw_rwlock_wrlock(load->lock);
-    time(&now);
+    microtime(&now);
     for (i = 0; i < load->len; i++) {
         struct load_entry *entry = load->entries[i];
         /* check for special case, load over whole live time */
-        if (entry->interval != -1 && now >= entry->last + entry->interval) {
+        if((entry->interval != -1 && now >= entry->last + entry->interval)) { 
             /* rotate */
             entry->curr /= entry->interval;
             if (entry->prev > 0)
@@ -174,10 +192,10 @@
 }
 
 
-float load_get(Load *load, int pos)
+double load_get(Load *load, int pos)
 {
-    float ret;
-    time_t now;
+    double ret;
+    double now;
     struct load_entry *entry;
 
     if (load == NULL || pos >= load->len) {
@@ -187,13 +205,13 @@
     /* first maybe rotate load */
     load_increase_with(load, 0);
     
-    time(&now);
+    microtime(&now);
     gw_rwlock_rdlock(load->lock);
     entry = load->entries[pos];
     if (load->heuristic && !entry->dirty) {
         ret = entry->prev;
     } else {
-        time_t diff = (now - entry->last);
+        double diff = (now - entry->last);
         if (diff == 0) diff = 1;
         ret = entry->curr/diff;
     }
Index: gw/load.h
===================================================================
--- gw/load.h	(revision 5164)
+++ gw/load.h	(working copy)
@@ -102,7 +102,7 @@
 /**
  * Get measured load value at position @pos.
  */
-float load_get(Load *load, int pos);
+double load_get(Load *load, int pos);
 
 /**
  * Get length of intervals.
@@ -109,4 +109,8 @@
  */
 int load_len(Load *load);
 
+/* Times with microseconds */
+double microtime(double *p);
+double microtime_diff(double end, double start);
+
 #endif