Re: sms-rate-refresh feature

Alexander Malysh <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi,

too much time passed since this post, but thanks to Stipe who pointed me 
to this post.

Attached is a patch that implements simple bandwidth meter with 
heuristic and needed changes to bearerbox status.

Bearerbox status show now 3 speeds: 1 minute sample, 5 minute sample, 
and over livetime.

Example:
SMS: inbound (0.00,0.00,0.00) msg/sec, outbound (0.00,0.00,0.00) msg/sec

Comments please...

Thanks,
Alex

Alexander Malysh schrieb:
> Hi,
> 
> I already implemented this in my tree, just give me some time to extract
> this...
> 
> Rafael Alfaro wrote:
> 
>> Hello Alex,
>>
>> First of all, thanks  for your time,
>> Could you explain me a little bit about: "Simple bandwidth meter should do
>> it"? How is the best way to implement this?
>>
>> Thanks in advance.
>>
>> Rafael Alfaro.
>>
>> On Tue, Mar 25, 2008 at 4:06 AM, Alexander Malysh <[email protected]>
>> wrote:
>>> Hi Rafael,
>>>
>>>  -1 for this patch. You don't need yet another thread to do this. Simple
>>>  bandwidth meter should do it...
>>>
>>>
>>>  Rafael Alfaro wrote:
>>>
>>>  > Hello Everybody,
>>>  >
>>>  > I did this patch with the following purpose:
>>>  > Provide the bearerbox status web page with an online incoming and
>>>  > outgoing sms rate display (msg/sec).
>>>  >
>>>  > For example, if you take a look to the current bearerbox status web
>>>  > page, you will see that the sms rate is the average since the
>>>  > bearerbox is online, because the current code is:
>>>  >
>>>  >         (float) counter_value(incoming_sms_counter)/t,
>>>  >         (float) counter_value(outgoing_sms_counter)/t,
>>>  >
>>>  > So, I added a new feature to the core group cfg: "sms-rate-refresh".
>>>  > This will launch a thread that will be sampling the
>>>  > "counter_value(incoming_sms_counter)" and
>>>  > "counter_value(outgoing_sms_counter)" every "sms_rate_refresh"
>>>  > seconds, and with this information we can calculate the current sms
>>>  > rate (msg/sec).
>>>  >
>>>  > If the "sms-rate-refresh" feature is not used at the configuration
>>>  > file, by default, the average since bearerbox is online will be
>>>  > displayed (like right now is coded).
>>>  >
>>>  > Best Regards,
>>>
>>>  --
>>>  Thanks,
>>>  Alex
>>>
>>>
>>>
>
bb-bandwidth.path (text/plain, 16.9 KB)
Index: gw/load.c
===================================================================
RCS file: gw/load.c
diff -N gw/load.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gw/load.c	12 Sep 2008 12:32:28 -0000
@@ -0,0 +1,215 @@
+/* ==================================================================== 
+ * The Kannel Software License, Version 1.0 
+ * 
+ * Copyright (c) 2001-2008 Kannel Group  
+ * Copyright (c) 1998-2001 WapIT Ltd.   
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * 3. The end-user documentation included with the redistribution, 
+ *    if any, must include the following acknowledgment: 
+ *       "This product includes software developed by the 
+ *        Kannel Group (http://www.kannel.org/)." 
+ *    Alternately, this acknowledgment may appear in the software itself, 
+ *    if and wherever such third-party acknowledgments normally appear. 
+ * 
+ * 4. The names "Kannel" and "Kannel Group" must not be used to 
+ *    endorse or promote products derived from this software without 
+ *    prior written permission. For written permission, please  
+ *    contact [email protected]. 
+ * 
+ * 5. Products derived from this software may not be called "Kannel", 
+ *    nor may "Kannel" appear in their name, without prior written 
+ *    permission of the Kannel Group. 
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * ==================================================================== 
+ * 
+ * This software consists of voluntary contributions made by many 
+ * individuals on behalf of the Kannel Group.  For more information on  
+ * the Kannel Group, please see <http://www.kannel.org/>. 
+ * 
+ * Portions of this software are based upon software originally written at  
+ * WapIT Ltd., Helsinki, Finland for the Kannel project.  
+ */ 
+
+/**
+ * load.c
+ *
+ * Alexander Malysh <amalysh at kannel.org> 2008 for project Kannel
+ */
+
+#include "gwlib/gwlib.h"
+#include "load.h"
+
+
+struct load_entry {
+    float prev;
+    float curr;
+    time_t last;
+    int interval;
+    int dirty;
+};
+
+
+struct load {
+    struct load_entry **entries;
+    int len;
+    int heuristic;
+    RWLock *lock;
+};
+
+
+Load* load_create_real(int heuristic)
+{
+    struct load *load;
+    
+    load = gw_malloc(sizeof(*load));
+    load->len = 0;
+    load->entries = NULL;
+    load->heuristic = heuristic;
+    load->lock = gw_rwlock_create();
+    
+    return load;
+}
+
+
+int load_add_interval(Load *load, int interval)
+{
+    int i;
+    struct load_entry *entry;
+    
+    if (load == NULL)
+        return -1;
+    
+    gw_rwlock_wrlock(load->lock);
+    
+    /* first look if we have equal interval added already */
+    for (i = 0; i < load->len; i++) {
+        if (load->entries[i]->interval == interval) {
+            gw_rwlock_unlock(load->lock);
+            return -1;
+        }
+    }
+    /* so no equal interval there, add new one */
+    entry = gw_malloc(sizeof(struct load_entry));
+    entry->prev = entry->curr = 0.0;
+    entry->interval = interval;
+    entry->dirty = 1;
+    time(&entry->last);
+    
+    load->entries = gw_realloc(load->entries, sizeof(struct load*) * (load->len + 1));
+    load->entries[load->len] = entry;
+    load->len++;
+    
+    gw_rwlock_unlock(load->lock);
+    
+    return 0;
+}
+
+    
+void load_destroy(Load *load)
+{
+    int i;
+
+    if (load == NULL)
+        return;
+
+    for (i = 0; i < load->len; i++) {
+        gw_free(load->entries[i]);
+    }
+    gw_free(load->entries);
+    gw_rwlock_destroy(load->lock);
+    gw_free(load);
+}
+
+
+void load_increase_with(Load *load, unsigned long value)
+{
+    time_t now;
+    int i;
+    
+    if (load == NULL)
+        return;
+    gw_rwlock_wrlock(load->lock);
+    time(&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) {
+            /* rotate */
+            entry->curr /= entry->interval;
+            if (entry->prev > 0)
+                entry->prev = (2*entry->curr + entry->prev)/3;
+            else
+                entry->prev = entry->curr;
+            entry->last = now;
+            entry->curr = 0.0;
+            entry->dirty = 0;
+        }
+        entry->curr += value;
+    }
+    gw_rwlock_unlock(load->lock);
+}
+
+
+float load_get(Load *load, int pos)
+{
+    float ret;
+    time_t now;
+    struct load_entry *entry;
+
+    if (load == NULL || pos >= load->len) {
+        return -1.0;
+    }
+
+    /* first maybe rotate load */
+    load_increase_with(load, 0);
+    
+    time(&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);
+        if (diff == 0) diff = 1;
+        ret = entry->curr/diff;
+    }
+    gw_rwlock_unlock(load->lock);
+
+    return ret;
+}
+
+
+int load_len(Load *load)
+{
+    int ret;
+    if (load == NULL)
+        return 0;
+    gw_rwlock_rdlock(load->lock);
+    ret = load->len;
+    gw_rwlock_unlock(load->lock);
+    return ret;
+}
Index: gw/load.h
===================================================================
RCS file: gw/load.h
diff -N gw/load.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gw/load.h	12 Sep 2008 12:32:28 -0000
@@ -0,0 +1,112 @@
+/* ==================================================================== 
+ * The Kannel Software License, Version 1.0 
+ * 
+ * Copyright (c) 2001-2008 Kannel Group  
+ * Copyright (c) 1998-2001 WapIT Ltd.   
+ * All rights reserved. 
+ * 
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions 
+ * are met: 
+ * 
+ * 1. Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer. 
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright 
+ *    notice, this list of conditions and the following disclaimer in 
+ *    the documentation and/or other materials provided with the 
+ *    distribution. 
+ * 
+ * 3. The end-user documentation included with the redistribution, 
+ *    if any, must include the following acknowledgment: 
+ *       "This product includes software developed by the 
+ *        Kannel Group (http://www.kannel.org/)." 
+ *    Alternately, this acknowledgment may appear in the software itself, 
+ *    if and wherever such third-party acknowledgments normally appear. 
+ * 
+ * 4. The names "Kannel" and "Kannel Group" must not be used to 
+ *    endorse or promote products derived from this software without 
+ *    prior written permission. For written permission, please  
+ *    contact [email protected]. 
+ * 
+ * 5. Products derived from this software may not be called "Kannel", 
+ *    nor may "Kannel" appear in their name, without prior written 
+ *    permission of the Kannel Group. 
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+ * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ * ==================================================================== 
+ * 
+ * This software consists of voluntary contributions made by many 
+ * individuals on behalf of the Kannel Group.  For more information on  
+ * the Kannel Group, please see <http://www.kannel.org/>. 
+ * 
+ * Portions of this software are based upon software originally written at  
+ * WapIT Ltd., Helsinki, Finland for the Kannel project.  
+ */ 
+
+/**
+ * load.h
+ *
+ * Alexander Malysh <amalysh at kannel.org> 2008 for project Kannel
+ */
+
+#ifndef LOAD_H
+#define LOAD_H 1
+
+#include <time.h>
+ 
+/**
+ * Anonymos Load typedef.
+ */
+typedef struct load Load;
+
+/**
+ * Create new Load object.
+ * @heuristic - 0 disable heuristic (means get always current load); 1 enable
+ */
+Load* load_create_real(int heuristic);
+#define load_create() load_create_real(1)
+
+/**
+ * Add load measure interval.
+ * @load - load object
+ * @interval - measure interval in seconds
+ * @return -1 if error occurs (e.g. interval already exists); 0 if all was fine
+ */
+int load_add_interval(Load *load, int interval);
+
+/**
+ * Increase load values with @value.
+ * @load - load object
+ * @valu - how much to increase
+ */
+void load_increase_with(Load *load, unsigned long value);
+#define load_increase(load) load_increase_with(load, 1)
+
+/**
+ * Destroy load object.
+ * @load - load object
+ */
+void load_destroy(Load *load);
+
+/**
+ * Get measured load value at position @pos.
+ */
+float load_get(Load *load, int pos);
+
+/**
+ * Get length of intervals.
+ */
+int load_len(Load *load);
+
+#endif
Index: gw/bb_smscconn.c
===================================================================
RCS file: /home/cvs/gateway/gw/bb_smscconn.c,v
retrieving revision 1.96
diff -a -u -p -r1.96 bb_smscconn.c
--- gw/bb_smscconn.c	9 Jan 2008 20:06:56 -0000	1.96
+++ gw/bb_smscconn.c	12 Sep 2008 12:32:28 -0000
@@ -87,6 +87,7 @@
 #include "numhash.h"
 #include "smscconn.h"
 #include "dlr.h"
+#include "load.h"
 
 #include "bb_smscconn_cb.h"    /* callback functions for connections */
 #include "smscconn_p.h"        /* to access counters */
@@ -100,6 +101,9 @@ extern List *outgoing_sms;
 extern Counter *incoming_sms_counter;
 extern Counter *outgoing_sms_counter;
 
+extern Load *outgoing_sms_load;
+extern Load *incoming_sms_load;
+
 extern List *flow_threads;
 extern List *suspended;
 extern List *isolated;
@@ -251,6 +255,7 @@ void bb_smscconn_sent(SMSCConn *conn, Ms
     }
     
     counter_increase(outgoing_sms_counter);
+    load_increase(outgoing_sms_load);
     if (conn) counter_increase(conn->sent);
 
     /* write ACK to store file */
@@ -424,6 +429,7 @@ long bb_smscconn_receive(SMSCConn *conn,
             switch(ret) {
             case concat_pending:
                 counter_increase(incoming_sms_counter); /* ?? */
+                load_increase(incoming_sms_load);
                 if (conn != NULL)
                     counter_increase(conn->received);
                 msg_destroy(sms);
@@ -476,6 +482,7 @@ long bb_smscconn_receive(SMSCConn *conn,
 	bb_alog_sms(conn, sms, "Receive DLR");
 
     counter_increase(incoming_sms_counter);
+    load_increase(incoming_sms_load);
     if (conn != NULL) counter_increase(conn->received);
 
     msg_destroy(sms);
Index: gw/bearerbox.c
===================================================================
RCS file: /home/cvs/gateway/gw/bearerbox.c,v
retrieving revision 1.167
diff -a -u -p -r1.167 bearerbox.c
--- gw/bearerbox.c	24 Apr 2008 14:44:59 -0000	1.167
+++ gw/bearerbox.c	12 Sep 2008 12:32:28 -0000
@@ -77,6 +77,7 @@
 #include "bearerbox.h"
 #include "shared.h"
 #include "dlr.h"
+#include "load.h"
 
 /* global variables; included to other modules as needed */
 
@@ -96,6 +97,10 @@ long max_incoming_sms_qlength;
 long max_outgoing_sms_qlength;
 
 
+Load *outgoing_sms_load;
+Load *incoming_sms_load;
+
+
 /* this is not a list of items; instead it is used as
  * indicator to note how many threads we have.
  * ALL flow threads must exit before we may safely change
@@ -454,6 +459,17 @@ static Cfg *init_bearerbox(Cfg *cfg)
 
     status_mutex = mutex_create();
 
+    outgoing_sms_load = load_create();
+    /* add 60,300,-1 entries */
+    load_add_interval(outgoing_sms_load, 60);
+    load_add_interval(outgoing_sms_load, 300);
+    load_add_interval(outgoing_sms_load, -1);
+    incoming_sms_load = load_create();
+    /* add 60,300,-1 entries */
+    load_add_interval(incoming_sms_load, 60);
+    load_add_interval(incoming_sms_load, 300);
+    load_add_interval(incoming_sms_load, -1);
+
     setup_signal_handlers();
     
     /* http-admin is REQUIRED */
@@ -544,6 +560,9 @@ static void empty_msg_lists(void)
     
     counter_destroy(incoming_sms_counter);
     counter_destroy(outgoing_sms_counter);
+
+    load_destroy(incoming_sms_load);
+    load_destroy(outgoing_sms_load);
 }
 
 
@@ -816,7 +835,6 @@ Octstr *bb_print_status(int status_type)
 {
     char *s, *lb;
     char *frmt, *footer;
-    char buf[1024];
     Octstr *ret, *str, *version;
     time_t t;
 
@@ -845,7 +863,7 @@ Octstr *bb_print_status(int status_type)
                "(%ld queued)</p>\n\n"
                " <p>SMS: received %ld (%ld queued), sent %ld "
                "(%ld queued), store size %ld</p>\n"
-               " <p>SMS: inbound %.2f msg/sec, outbound %.2f msg/sec</p>\n\n"
+               " <p>SMS: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec</p>\n\n"
                " <p>DLR: %ld queued, using %s storage</p>\n\n";
         footer = "<p>";
     } else if (status_type == BBSTATUS_WML) {
@@ -856,8 +874,8 @@ Octstr *bb_print_status(int status_type)
                "   <p>SMS: received %ld (%ld queued)<br/>\n"
                "      SMS: sent %ld (%ld queued)<br/>\n"
                "      SMS: store size %ld<br/>\n"
-               "      SMS: inbound %.2f msg/sec<br/>\n"
-               "      SMS: outbound %.2f msg/sec</p>\n\n"
+               "      SMS: inbound (%.2f,%.2f,%.2f) msg/sec<br/>\n"
+               "      SMS: outbound (%.2f,%.2f,%.2f) msg/sec</p>\n\n"
                "   <p>DLR: %ld queued<br/>\n"
                "      DLR: using %s storage</p>\n\n";
         footer = "<p>";
@@ -870,19 +888,19 @@ Octstr *bb_print_status(int status_type)
                "\t<sms>\n\t\t<received><total>%ld</total><queued>%ld</queued>"
                "</received>\n\t\t<sent><total>%ld</total><queued>%ld</queued>"
                "</sent>\n\t\t<storesize>%ld</storesize>\n\t\t"
-               "<inbound>%.2f</inbound>\n\t\t<outbound>%.2f</outbound>\n\t</sms>\n"
+               "<inbound>%.2f,%.2f,%.2f</inbound>\n\t\t<outbound>%.2f,%.2f,%.2f</outbound>\n\t</sms>\n"
                "\t<dlr>\n\t\t<queued>%ld</queued>\n\t\t<storage>%s</storage>\n\t</dlr>\n";
         footer = "";
     } else {
         frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n"
                "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n"
                "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n"
-               "SMS: inbound %.2f msg/sec, outbound %.2f msg/sec\n\n"
+               "SMS: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec\n\n"
                "DLR: %ld queued, using %s storage\n\n";
         footer = "";
     }
     
-    sprintf(buf, frmt,
+    ret = octstr_format(frmt,
         octstr_get_cstr(version),
         s, t/3600/24, t/3600%24, t/60%60, t%60,
         counter_value(incoming_wdp_counter),
@@ -891,12 +909,11 @@ Octstr *bb_print_status(int status_type)
         counter_value(incoming_sms_counter), gwlist_len(incoming_sms),
         counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms),
         store_messages(),
-        (float) counter_value(incoming_sms_counter)/t,
-        (float) counter_value(outgoing_sms_counter)/t,
+        load_get(incoming_sms_load,0), load_get(incoming_sms_load,1), load_get(incoming_sms_load,2),
+        load_get(outgoing_sms_load,0), load_get(outgoing_sms_load,1), load_get(outgoing_sms_load,2),
         dlr_messages(), dlr_type());
 
     octstr_destroy(version);
-    ret = octstr_create(buf);
     
     append_status(ret, str, boxc_status, status_type);
     append_status(ret, str, smsc2_status, status_type);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.