Mercurial > hg > freeDiameter
changeset 572:b1b56d4682d0
Added benchmark mode in test_app
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Fri, 08 Oct 2010 15:30:36 +0900 |
parents | 1770d3df4140 |
children | 5f8e0fbf62c0 |
files | doc/test_app.conf.sample extensions/test_app/CMakeLists.txt extensions/test_app/ta_bench.c extensions/test_app/ta_conf.l extensions/test_app/ta_conf.y extensions/test_app/ta_serv.c extensions/test_app/test_app.c extensions/test_app/test_app.h |
diffstat | 8 files changed, 407 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/test_app.conf.sample Thu Oct 07 18:54:48 2010 +0900 +++ b/doc/test_app.conf.sample Fri Oct 08 15:30:36 2010 +0900 @@ -37,6 +37,12 @@ # - both: acts as client and server # mode = both; +# The behavior can be changed by specifying additional "benchmark;" keyword. +# When this keyword appears, it changes the behavior as follow: +# - server is silent on message reception, only the activity summary is displayed every 30 seconds +# - client attempts to send as many messages as possible during 10 seconds and counts them. +# benchmark; + ####################### # Client-specific configuration
--- a/extensions/test_app/CMakeLists.txt Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/CMakeLists.txt Fri Oct 08 15:30:36 2010 +0900 @@ -15,6 +15,7 @@ ta_conf.tab.h ta_dict.c ta_cli.c + ta_bench.c ta_serv.c )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/test_app/ta_bench.c Fri Oct 08 15:30:36 2010 +0900 @@ -0,0 +1,294 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * 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. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR 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. * +*********************************************************************************************************/ + +/* Create and send a message, and receive it */ + +#include "test_app.h" + +#include <semaphore.h> + +/* The number of messages that can be sent before waiting for a corresponding answer */ +#define NB_CONCURRENT_MESSAGES 100 + +#include <stdio.h> + +struct ta_mess_info { + int32_t randval; /* a random value to store in Test-AVP */ + struct timespec ts; /* Time of sending the message */ +}; + +static sem_t ta_sem; + +/* Cb called when an answer is received */ +static void ta_cb_ans(void * data, struct msg ** msg) +{ + struct ta_mess_info * mi = (struct ta_mess_info *)data; + struct timespec ts; + struct avp * avp; + struct avp_hdr * hdr; + unsigned long dur; + + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return ); + + /* Value of Result Code */ + CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_res_code, &avp), return ); + if (avp) { + CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return ); + } + if (!avp || !hdr || hdr->avp_value->i32 != 2001) { + /* error */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + ta_conf->stats.nb_errs++; + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + goto end; + } + + /* Check value of Test-AVP */ + CHECK_FCT_DO( fd_msg_search_avp ( *msg, ta_avp, &avp), return ); + if (avp) { + CHECK_FCT_DO( fd_msg_avp_hdr( avp, &hdr ), return ); + ASSERT(hdr->avp_value->i32 == mi->randval); + } + + /* Compute how long it took */ + dur = ((ts.tv_sec - mi->ts.tv_sec) * 1000000) + ((ts.tv_nsec - mi->ts.tv_nsec) / 1000); + + /* Add this value to the stats */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + + if (ta_conf->stats.nb_recv) { + /* Ponderate in the avg */ + ta_conf->stats.avg = (ta_conf->stats.avg * ta_conf->stats.nb_recv + dur) / (ta_conf->stats.nb_recv + 1); + /* Min, max */ + if (dur < ta_conf->stats.shortest) + ta_conf->stats.shortest = dur; + if (dur > ta_conf->stats.longest) + ta_conf->stats.longest = dur; + } else { + ta_conf->stats.shortest = dur; + ta_conf->stats.longest = dur; + ta_conf->stats.avg = dur; + } + ta_conf->stats.nb_recv++; + + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + +end: + /* Free the message */ + CHECK_FCT_DO(fd_msg_free(*msg), ); + *msg = NULL; + + free(mi); + + /* Post the semaphore */ + CHECK_SYS_DO( sem_post(&ta_sem), ); + + return; +} + +/* Create a test message */ +static void ta_bench_test_message() +{ + struct msg * req = NULL; + struct avp * avp; + union avp_value val; + struct ta_mess_info * mi = NULL; + struct session *sess = NULL; + + TRACE_DEBUG(FULL, "Creating a new message for sending."); + + /* Create the request */ + CHECK_FCT_DO( fd_msg_new( ta_cmd_r, MSGFL_ALLOC_ETEID, &req ), goto out ); + + /* Create a new session */ + CHECK_FCT_DO( fd_sess_new( &sess, fd_g_config->cnf_diamid, "app_test", 8 ), goto out ); + + /* Create the random value to store with the session */ + mi = malloc(sizeof(struct ta_mess_info)); + if (mi == NULL) { + fd_log_debug("malloc failed: %s", strerror(errno)); + goto out; + } + + mi->randval = (int32_t)random(); + + /* Now set all AVPs values */ + + /* Session-Id */ + { + char * sid; + CHECK_FCT_DO( fd_sess_getsid ( sess, &sid ), goto out ); + CHECK_FCT_DO( fd_msg_avp_new ( ta_sess_id, 0, &avp ), goto out ); + val.os.data = (uint8_t *)sid; + val.os.len = strlen(sid); + CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); + CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_FIRST_CHILD, avp ), goto out ); + + } + + /* Set the Destination-Realm AVP */ + { + CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_realm, 0, &avp ), goto out ); + val.os.data = (unsigned char *)(ta_conf->dest_realm); + val.os.len = strlen(ta_conf->dest_realm); + CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); + CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out ); + } + + /* Set the Destination-Host AVP if needed*/ + if (ta_conf->dest_host) { + CHECK_FCT_DO( fd_msg_avp_new ( ta_dest_host, 0, &avp ), goto out ); + val.os.data = (unsigned char *)(ta_conf->dest_host); + val.os.len = strlen(ta_conf->dest_host); + CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); + CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out ); + } + + /* Set Origin-Host & Origin-Realm */ + CHECK_FCT_DO( fd_msg_add_origin ( req, 0 ), goto out ); + + /* Set the User-Name AVP if needed*/ + if (ta_conf->user_name) { + CHECK_FCT_DO( fd_msg_avp_new ( ta_user_name, 0, &avp ), goto out ); + val.os.data = (unsigned char *)(ta_conf->user_name); + val.os.len = strlen(ta_conf->user_name); + CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); + CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out ); + } + + /* Set the Test-AVP AVP */ + { + CHECK_FCT_DO( fd_msg_avp_new ( ta_avp, 0, &avp ), goto out ); + val.i32 = mi->randval; + CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), goto out ); + CHECK_FCT_DO( fd_msg_avp_add( req, MSG_BRW_LAST_CHILD, avp ), goto out ); + } + + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &mi->ts), goto out ); + + /* Send the request */ + CHECK_FCT_DO( fd_msg_send( &req, ta_cb_ans, mi ), goto out ); + + /* Increment the counter */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + ta_conf->stats.nb_sent++; + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + +out: + return; +} + +/* The function called when the signal is received */ +static void ta_bench_start(int sig) { + struct timespec end_time, now; + struct ta_stats start, end; + + /* Save the initial stats */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + memcpy(&start, &ta_conf->stats, sizeof(struct ta_stats)); + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + + /* We will run for 10 seconds */ + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &end_time), ); + end_time.tv_sec += 10; + + /* Now loop until timeout is reached */ + do { + /* Do not create more that NB_CONCURRENT_MESSAGES in paralel */ + int ret = sem_timedwait(&ta_sem, &end_time); + if (ret == -1) { + ret = errno; + if (ret != ETIMEDOUT) { + CHECK_POSIX_DO(ret, ); /* Just to log it */ + } + break; + } + + /* Create and send a new test message */ + ta_bench_test_message(); + + /* Update the current time */ + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), ); + } while (TS_IS_INFERIOR(&now, &end_time)); + + /* Save the stats now */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), ); /* Re-read the time because we might have spent some time wiating for the mutex */ + memcpy(&end, &ta_conf->stats, sizeof(struct ta_stats)); + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + + /* Now, display the statistics */ + fd_log_debug( "------- app_test Benchmark result ---------\n"); + if (now.tv_nsec >= end_time.tv_nsec) { + fd_log_debug( " Executing for: %d.%06ld sec\n", + (int)(now.tv_sec + 10 - end_time.tv_sec), + (long)(now.tv_nsec - end_time.tv_nsec) / 1000); + } else { + fd_log_debug( " Executing for: %d.%06ld sec\n", + (int)(now.tv_sec + 9 - end_time.tv_sec), + (long)(now.tv_nsec + 1000000000 - end_time.tv_nsec) / 1000); + } + fd_log_debug( " %llu messages sent\n", end.nb_sent - start.nb_sent); + fd_log_debug( " %llu errors received\n", end.nb_errs - start.nb_errs); + fd_log_debug( " %llu answers received\n", end.nb_recv - start.nb_recv); + fd_log_debug( " Overall:\n"); + fd_log_debug( " fastest: %ld.%06ld sec.\n", end.shortest / 1000000, end.shortest % 1000000); + fd_log_debug( " slowest: %ld.%06ld sec.\n", end.longest / 1000000, end.longest % 1000000); + fd_log_debug( " Average: %ld.%06ld sec.\n", end.avg / 1000000, end.avg % 1000000); + fd_log_debug( " Throughput: %llu message / sec\n", (end.nb_recv - start.nb_recv) / (( now.tv_sec + 10 - end_time.tv_sec ) + ((now.tv_nsec - end_time.tv_nsec) / 1000000000))); + + + fd_log_debug( "-------------------------------------\n"); + +} + + +int ta_bench_init(void) +{ + CHECK_SYS( sem_init( &ta_sem, 0, NB_CONCURRENT_MESSAGES) ); + + CHECK_FCT( fd_sig_register(ta_conf->signal, "test_app.bench", ta_bench_start ) ); + + return 0; +} + +void ta_bench_fini(void) +{ + CHECK_FCT_DO( fd_sig_unregister(ta_conf->signal), /* continue */ ); + + CHECK_SYS_DO( sem_destroy(&ta_sem), ); + + return; +};
--- a/extensions/test_app/ta_conf.l Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/ta_conf.l Fri Oct 08 15:30:36 2010 +0900 @@ -152,6 +152,10 @@ return SIGNAL; } +(?i:"Benchmark") { + return BENCH; + } + /* Valid single characters for yyparse */ [=;] { return yytext[0]; }
--- a/extensions/test_app/ta_conf.y Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/ta_conf.y Fri Oct 08 15:30:36 2010 +0900 @@ -125,6 +125,7 @@ %token DEST_HOST %token USER_NAME %token SIGNAL +%token BENCH /* Tokens and types for routing table definition */ /* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */ @@ -149,6 +150,7 @@ | conffile dsthost | conffile usrname | conffile signal + | conffile bench ; vendor: VENDOR_ID '=' INTEGER ';' @@ -177,7 +179,13 @@ mode: MODE '=' INTEGER ';' { - ta_conf->mode = $3; + ta_conf->mode = $3 | (ta_conf->mode & ~3); /* overwrite the 2 lsb */ + } + ; + +bench: BENCH ';' + { + ta_conf->mode |= MODE_BENCH; } ;
--- a/extensions/test_app/ta_serv.c Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/ta_serv.c Fri Oct 08 15:30:36 2010 +0900 @@ -63,16 +63,18 @@ return EINVAL; /* Value of Origin-Host */ - fprintf(stderr, "ECHO Test-Request received from "); - CHECK_FCT( fd_msg_search_avp ( *msg, ta_origin_host, &a) ); - if (a) { - struct avp_hdr * hdr; - CHECK_FCT( fd_msg_avp_hdr( a, &hdr ) ); - fprintf(stderr, "'%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data); - } else { - fprintf(stderr, "no_Origin-Host"); + if (! (ta_conf->mode & MODE_BENCH)) { + fprintf(stderr, "ECHO Test-Request received from "); + CHECK_FCT( fd_msg_search_avp ( *msg, ta_origin_host, &a) ); + if (a) { + struct avp_hdr * hdr; + CHECK_FCT( fd_msg_avp_hdr( a, &hdr ) ); + fprintf(stderr, "'%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + fprintf(stderr, "no_Origin-Host"); + } + fprintf(stderr, ", replying...\n"); } - fprintf(stderr, ", replying...\n"); /* Create answer header */ qry = *msg;
--- a/extensions/test_app/test_app.c Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/test_app.c Fri Oct 08 15:30:36 2010 +0900 @@ -42,6 +42,7 @@ /* Initialize the configuration */ struct ta_conf * ta_conf = NULL; static struct ta_conf _conf; +static pthread_t ta_stats_th = (pthread_t)NULL; static int ta_conf_init(void) { @@ -58,6 +59,9 @@ ta_conf->dest_host = NULL; ta_conf->signal = TEST_APP_DEFAULT_SIGNAL; + /* Initialize the mutex */ + CHECK_POSIX( pthread_mutex_init(&ta_conf->stats_lock, NULL) ); + return 0; } @@ -70,13 +74,65 @@ fd_log_debug( " Application Id ..... : %u\n", ta_conf->appli_id); fd_log_debug( " Command Id ......... : %u\n", ta_conf->cmd_id); fd_log_debug( " AVP Id ............. : %u\n", ta_conf->avp_id); - fd_log_debug( " Mode ............... : %s%s\n", ta_conf->mode & MODE_SERV ? "Serv" : "", ta_conf->mode & MODE_CLI ? "Cli" : "" ); + fd_log_debug( " Mode ............... : %s%s%s\n", ta_conf->mode & MODE_SERV ? "Serv" : "", ta_conf->mode & MODE_CLI ? "Cli" : "", ta_conf->mode & MODE_BENCH ? " (Benchmark)" : ""); fd_log_debug( " Destination Realm .. : %s\n", ta_conf->dest_realm ?: "- none -"); fd_log_debug( " Destination Host ... : %s\n", ta_conf->dest_host ?: "- none -"); fd_log_debug( " Signal ............. : %i\n", ta_conf->signal); fd_log_debug( "------- /app_test configuration dump ---------\n"); } +/* Function to display statistics every 10 seconds */ +static void * ta_stats(void * arg) { + + struct timespec start, now; + struct ta_stats copy; + + /* Get the start time */ + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &start), ); + + /* Now, loop until canceled */ + while (1) { + /* Display statistics every 30 seconds */ + sleep(30); + + /* Now, get the current stats */ + CHECK_POSIX_DO( pthread_mutex_lock(&ta_conf->stats_lock), ); + memcpy(©, &ta_conf->stats, sizeof(struct ta_stats)); + CHECK_POSIX_DO( pthread_mutex_unlock(&ta_conf->stats_lock), ); + + /* Get the current execution time */ + CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), ); + + /* Now, display everything */ + fd_log_debug( "------- app_test statistics ---------\n"); + if (now.tv_nsec >= start.tv_nsec) { + fd_log_debug( " Executing for: %d.%06ld sec\n", + (int)(now.tv_sec - start.tv_sec), + (long)(now.tv_nsec - start.tv_nsec) / 1000); + } else { + fd_log_debug( " Executing for: %d.%06ld sec\n", + (int)(now.tv_sec - 1 - start.tv_sec), + (long)(now.tv_nsec + 1000000000 - start.tv_nsec) / 1000); + } + + if (ta_conf->mode & MODE_SERV) { + fd_log_debug( " Server: %llu messages echoed\n", copy.nb_echoed); + } + if (ta_conf->mode & MODE_CLI) { + fd_log_debug( " Client:\n"); + fd_log_debug( " %llu messages sent\n", copy.nb_sent); + fd_log_debug( " %llu errors received\n", copy.nb_errs); + fd_log_debug( " %llu answers received\n", copy.nb_recv); + fd_log_debug( " fastest: %ld.%06ld sec.\n", copy.shortest / 1000000, copy.shortest % 1000000); + fd_log_debug( " slowest: %ld.%06ld sec.\n", copy.longest / 1000000, copy.longest % 1000000); + fd_log_debug( " Average: %ld.%06ld sec.\n", copy.avg / 1000000, copy.avg % 1000000); + } + fd_log_debug( "-------------------------------------\n"); + } + + return NULL; /* never called */ +} + /* entry point */ static int ta_entry(char * conffile) { @@ -103,12 +159,19 @@ /* Start the signal handler thread */ if (ta_conf->mode & MODE_CLI) { - CHECK_FCT( ta_cli_init() ); + if (ta_conf->mode & MODE_BENCH) { + CHECK_FCT( ta_bench_init() ); + } else { + CHECK_FCT( ta_cli_init() ); + } } /* Advertise the support for the test application in the peer */ CHECK_FCT( fd_disp_app_support ( ta_appli, ta_vendor, 1, 0 ) ); + /* Start the statistics thread */ + CHECK_POSIX( pthread_create(&ta_stats_th, NULL, ta_stats, NULL) ); + return 0; } @@ -119,6 +182,8 @@ ta_cli_fini(); if (ta_conf->mode & MODE_SERV) ta_serv_fini(); + CHECK_FCT_DO( fd_thr_term(&ta_stats_th), ); + CHECK_POSIX_DO( pthread_mutex_destroy(&ta_conf->stats_lock), ); } EXTENSION_ENTRY("test_app", ta_entry);
--- a/extensions/test_app/test_app.h Thu Oct 07 18:54:48 2010 +0900 +++ b/extensions/test_app/test_app.h Fri Oct 08 15:30:36 2010 +0900 @@ -51,6 +51,7 @@ /* Mode for the extension */ #define MODE_SERV 0x1 #define MODE_CLI 0x2 +#define MODE_BENCH 0x4 /* The module configuration */ struct ta_conf { @@ -63,6 +64,16 @@ char * dest_host; /* default NULL */ char * user_name; /* default NULL */ int signal; /* default TEST_APP_DEFAULT_SIGNAL */ + struct ta_stats { + unsigned long long nb_echoed; /* server */ + unsigned long long nb_sent; /* client */ + unsigned long long nb_recv; /* client */ + unsigned long long nb_errs; /* client */ + unsigned long shortest; /* fastest answer, in microseconds */ + unsigned long longest; /* slowest answer, in microseconds */ + unsigned long avg; /* average answer time, in microseconds */ + } stats; + pthread_mutex_t stats_lock; }; extern struct ta_conf * ta_conf; @@ -77,6 +88,10 @@ int ta_cli_init(void); void ta_cli_fini(void); +/* Benchmark flavour */ +int ta_bench_init(void); +void ta_bench_fini(void); + /* Initialize dictionary definitions */ int ta_dict_init(void);