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);