diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-06-28 16:46:49 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-06-28 16:46:49 +0000 |
commit | 72a1098e21f5b7d797655afe7ddb275969a192bd (patch) | |
tree | 2d6444a4660696829f4ac3c1f436e0d9f3d16310 /pjsip/src/test-pjsip | |
parent | df5395ea5cff6c902f8a1d79bd2874a6b279288c (diff) |
Major improvements in PJSIP to support TCP. The changes fall into these categories: (1) the TCP transport implementation itself (*.[hc]), (2) bug-fix in SIP transaction when using reliable transports, (3) support for TCP transport in PJSUA-LIB/PJSUA, and (4) changes in PJSIP-TEST to support TCP testing.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@563 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/test-pjsip')
-rw-r--r-- | pjsip/src/test-pjsip/main.c | 15 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/msg_logger.c | 12 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/msg_test.c | 191 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/test.c | 195 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/test.h | 37 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_loop_test.c | 29 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_tcp_test.c | 143 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_test.c | 13 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/transport_udp_test.c | 16 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/tsx_basic_test.c | 19 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/tsx_bench.c | 273 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/tsx_uac_test.c | 210 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/tsx_uas_test.c | 168 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/txdata_test.c | 323 | ||||
-rw-r--r-- | pjsip/src/test-pjsip/uri_test.c | 185 |
15 files changed, 1600 insertions, 229 deletions
diff --git a/pjsip/src/test-pjsip/main.c b/pjsip/src/test-pjsip/main.c index 7994504d..ddfb1e7d 100644 --- a/pjsip/src/test-pjsip/main.c +++ b/pjsip/src/test-pjsip/main.c @@ -21,6 +21,8 @@ #include <string.h> #include <stdlib.h> +extern const char *system_name; + static void usage() { puts("Usage: test-pjsip"); @@ -57,6 +59,15 @@ int main(int argc, char *argv[]) return 1; } log_level = atoi(*opt_arg); + } else if (strcmp(*opt_arg, "-s") == 0 || + strcmp(*opt_arg, "--system") == 0) + { + ++opt_arg; + if (!opt_arg) { + usage(); + return 1; + } + system_name = *opt_arg; } else { usage(); return 1; @@ -67,9 +78,9 @@ int main(int argc, char *argv[]) retval = test_main(); - if (argc != 1) { + if (interractive) { char s[10]; - printf("<Press ENTER to quit>\n"); + printf("<Press ENTER to quit>\n"); fflush(stdout); fgets(s, sizeof(s), stdin); } diff --git a/pjsip/src/test-pjsip/msg_logger.c b/pjsip/src/test-pjsip/msg_logger.c index a4eac0da..e517ae05 100644 --- a/pjsip/src/test-pjsip/msg_logger.c +++ b/pjsip/src/test-pjsip/msg_logger.c @@ -27,13 +27,15 @@ static pj_bool_t msg_log_enabled; static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) { if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n" - "%s\n" + PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%s:%d:\n" + "%.*s\n" "--end msg--", rdata->msg_info.len, pjsip_rx_data_get_info(rdata), + rdata->tp_info.transport->type_name, rdata->pkt_info.src_name, rdata->pkt_info.src_port, + rdata->msg_info.len, rdata->msg_info.msg_buf)); } @@ -43,13 +45,15 @@ static pj_bool_t on_rx_msg(pjsip_rx_data *rdata) static pj_status_t on_tx_msg(pjsip_tx_data *tdata) { if (msg_log_enabled) { - PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n" - "%s\n" + PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%s:%d:\n" + "%.*s\n" "--end msg--", (tdata->buf.cur - tdata->buf.start), pjsip_tx_data_get_info(tdata), + tdata->tp_info.transport->type_name, tdata->tp_info.dst_name, tdata->tp_info.dst_port, + (tdata->buf.cur - tdata->buf.start), tdata->buf.start)); } return PJ_SUCCESS; diff --git a/pjsip/src/test-pjsip/msg_test.c b/pjsip/src/test-pjsip/msg_test.c index f5debe84..ebe43025 100644 --- a/pjsip/src/test-pjsip/msg_test.c +++ b/pjsip/src/test-pjsip/msg_test.c @@ -21,7 +21,11 @@ #include <pjlib.h> #define POOL_SIZE 8000 -#define LOOP 10000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif #define AVERAGE_MSG_LEN 800 #define THIS_FILE "msg_test.c" @@ -35,8 +39,6 @@ static pjsip_msg *create_msg1(pj_pool_t *pool); #define FLAG_PARSE_ONLY 4 #define FLAG_PRINT_ONLY 8 -static int flag = 0; - struct test_msg { char msg[1024]; @@ -101,8 +103,12 @@ struct test_msg } }; -static pj_highprec_t detect_len, parse_len, print_len; -static pj_timestamp detect_time, parse_time, print_time; +static struct +{ + int flag; + pj_highprec_t detect_len, parse_len, print_len; + pj_timestamp detect_time, parse_time, print_time; +} var; static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) { @@ -121,17 +127,17 @@ static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) entry->len = pj_native_strlen(entry->msg); - if (flag & FLAG_PARSE_ONLY) + if (var.flag & FLAG_PARSE_ONLY) goto parse_msg; - if (flag & FLAG_PRINT_ONLY) { + if (var.flag & FLAG_PRINT_ONLY) { if (print_msg == NULL) print_msg = entry->creator(pool); goto print_msg; } /* Detect message. */ - detect_len = detect_len + entry->len; + var.detect_len = var.detect_len + entry->len; pj_get_timestamp(&t1); status = pjsip_find_msg(entry->msg, entry->len, PJ_FALSE, &msg_size); if (status != PJ_SUCCESS) { @@ -148,14 +154,14 @@ static pj_status_t test_entry( pj_pool_t *pool, struct test_msg *entry ) } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&detect_time, &t2); + pj_add_timestamp(&var.detect_time, &t2); - if (flag & FLAG_DETECT_ONLY) + if (var.flag & FLAG_DETECT_ONLY) return PJ_SUCCESS; /* Parse message. */ parse_msg: - parse_len = parse_len + entry->len; + var.parse_len = var.parse_len + entry->len; pj_get_timestamp(&t1); pj_list_init(&err_list); parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, &err_list); @@ -171,9 +177,9 @@ parse_msg: } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&parse_time, &t2); + pj_add_timestamp(&var.parse_time, &t2); - if (flag & FLAG_PARSE_ONLY) + if (var.flag & FLAG_PARSE_ONLY) return PJ_SUCCESS; /* Create reference message. */ @@ -306,9 +312,9 @@ parse_msg: /* Print message. */ print_msg: - print_len = print_len + entry->len; + var.print_len = var.print_len + entry->len; pj_get_timestamp(&t1); - if (flag && FLAG_PRINT_ONLY) + if (var.flag && FLAG_PRINT_ONLY) ref_msg = print_msg; len = pjsip_msg_print(ref_msg, msgbuf1, PJSIP_MAX_PKT_LEN); if (len < 1) { @@ -317,7 +323,7 @@ print_msg: } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&print_time, &t2); + pj_add_timestamp(&var.print_time, &t2); status = PJ_SUCCESS; @@ -674,17 +680,14 @@ static pjsip_msg *create_msg1(pj_pool_t *pool) /*****************************************************************************/ -int msg_test(void) +static pj_status_t simple_test(void) { + unsigned i; pj_status_t status; - pj_pool_t *pool; - int i, loop; - pj_timestamp zero; - pj_time_val elapsed; - pj_highprec_t avg_detect, avg_parse, avg_print, kbytes; PJ_LOG(3,(THIS_FILE, " simple test..")); for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) { + pj_pool_t *pool; pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE); status = test_entry( pool, &test_array[i] ); pjsip_endpt_release_pool(endpt, pool); @@ -693,10 +696,24 @@ int msg_test(void) return status; } - PJ_LOG(3,(THIS_FILE, " benchmarking..")); - detect_len = parse_len = print_len = 0; - zero.u64 = detect_time.u64 = parse_time.u64 = print_time.u64 = 0; - + return PJ_SUCCESS; +} + + +static int msg_benchmark(unsigned *p_detect, unsigned *p_parse, + unsigned *p_print) +{ + pj_status_t status; + pj_pool_t *pool; + int i, loop; + pj_timestamp zero; + pj_time_val elapsed; + pj_highprec_t avg_detect, avg_parse, avg_print, kbytes; + + + pj_memset(&var, 0, sizeof(var)); + zero.u64 = 0; + for (loop=0; loop<LOOP; ++loop) { for (i=0; i<PJ_ARRAY_SIZE(test_array); ++i) { pool = pjsip_endpt_create_pool(endpt, NULL, POOL_SIZE, POOL_SIZE); @@ -708,52 +725,144 @@ int msg_test(void) } } - kbytes = detect_len; + kbytes = var.detect_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &detect_time); - avg_detect = pj_elapsed_usec(&zero, &detect_time); + elapsed = pj_elapsed_time(&zero, &var.detect_time); + avg_detect = pj_elapsed_usec(&zero, &var.detect_time); pj_highprec_mul(avg_detect, AVERAGE_MSG_LEN); - pj_highprec_div(avg_detect, detect_len); + pj_highprec_div(avg_detect, var.detect_len); avg_detect = 1000000 / avg_detect; PJ_LOG(3,(THIS_FILE, " %u.%u MB detected in %d.%03ds (avg=%d msg detection/sec)", - (unsigned)(detect_len/1000000), (unsigned)kbytes, + (unsigned)(var.detect_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_detect)); + *p_detect = (unsigned)avg_detect; - kbytes = parse_len; + kbytes = var.parse_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &parse_time); - avg_parse = pj_elapsed_usec(&zero, &parse_time); + elapsed = pj_elapsed_time(&zero, &var.parse_time); + avg_parse = pj_elapsed_usec(&zero, &var.parse_time); pj_highprec_mul(avg_parse, AVERAGE_MSG_LEN); - pj_highprec_div(avg_parse, parse_len); + pj_highprec_div(avg_parse, var.parse_len); avg_parse = 1000000 / avg_parse; PJ_LOG(3,(THIS_FILE, " %u.%u MB parsed in %d.%03ds (avg=%d msg parsing/sec)", - (unsigned)(parse_len/1000000), (unsigned)kbytes, + (unsigned)(var.parse_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_parse)); + *p_parse = (unsigned)avg_parse; - kbytes = print_len; + kbytes = var.print_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &print_time); - avg_print = pj_elapsed_usec(&zero, &print_time); + elapsed = pj_elapsed_time(&zero, &var.print_time); + avg_print = pj_elapsed_usec(&zero, &var.print_time); pj_highprec_mul(avg_print, AVERAGE_MSG_LEN); - pj_highprec_div(avg_print, print_len); + pj_highprec_div(avg_print, var.print_len); avg_print = 1000000 / avg_print; PJ_LOG(3,(THIS_FILE, " %u.%u MB printed in %d.%03ds (avg=%d msg print/sec)", - (unsigned)(print_len/1000000), (unsigned)kbytes, + (unsigned)(var.print_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_print)); + *p_print = (unsigned)avg_print; return status; } /*****************************************************************************/ + +int msg_test(void) +{ + enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 }; + struct { + unsigned detect; + unsigned parse; + unsigned print; + } run[COUNT]; + unsigned i, max, avg_len; + char desc[250]; + pj_status_t status; + + + status = simple_test(); + if (status != PJ_SUCCESS) + return status; + + for (i=0; i<COUNT; ++i) { + PJ_LOG(3,(THIS_FILE, " benchmarking (%d of %d)..", i+1, COUNT)); + status = msg_benchmark(&run[i].detect, &run[i].parse, &run[i].print); + if (status != PJ_SUCCESS) + return status; + } + + /* Calculate average message length */ + for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(test_array); ++i) { + avg_len += test_array[i].len; + } + avg_len /= PJ_ARRAY_SIZE(test_array); + + + /* Print maximum detect/sec */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].detect > max) max = run[i].detect; + + PJ_LOG(3,("", " Maximum message detection/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be pre-parse by <tt>pjsip_find_msg()</tt> " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-detect-per-sec", max, "msg/sec", desc); + + /* Print maximum parse/sec */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].parse > max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum message parsing/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be <b>parsed</b> by <tt>pjsip_parse_msg()</tt> " + "per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + report_ival("msg-parse-per-sec", max, "msg/sec", desc); + + /* Msg parsing bandwidth */ + report_ival("msg-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message parsing bandwidth in megabytes (number of megabytes" + " worth of SIP messages that can be parsed per second). " + "The value is derived from msg-parse-per-sec above."); + + + /* Print maximum print/sec */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].print > max) max = run[i].print; + + PJ_LOG(3,("", " Maximum message print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP messages " + "can be <b>printed</b> by <tt>pjsip_msg_print()</tt>" + " per second (tested with %d message sets with " + "average message length of " + "%d bytes)", PJ_ARRAY_SIZE(test_array), avg_len); + + report_ival("msg-print-per-sec", max, "msg/sec", desc); + + /* Msg print bandwidth */ + report_ival("msg-printed-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "Message print bandwidth in megabytes (total size of " + "SIP messages printed per second). " + "The value is derived from msg-print-per-sec above."); + + + return PJ_SUCCESS; +} + diff --git a/pjsip/src/test-pjsip/test.c b/pjsip/src/test-pjsip/test.c index b8707332..3ae58daa 100644 --- a/pjsip/src/test-pjsip/test.c +++ b/pjsip/src/test-pjsip/test.c @@ -33,11 +33,24 @@ if (rc!=0) goto on_return; \ } while (0) +#define DO_TSX_TEST(test, param) \ + do { \ + PJ_LOG(3, (THIS_FILE, "Running %s(%s)...", #test, (param)->tp_type)); \ + rc = test(param); \ + PJ_LOG(3, (THIS_FILE, \ + "%s(%d)", \ + (rc ? "..ERROR" : "..success"), rc)); \ + if (rc!=0) goto on_return; \ + } while (0) pjsip_endpoint *endpt; int log_level = 3; +static pj_oshandle_t fd_report; +const char *system_name = "Unknown"; +static char buf[1024]; + void app_perror(const char *msg, pj_status_t rc) { char errbuf[256]; @@ -75,11 +88,142 @@ pj_status_t register_static_modules(pj_size_t *count, pjsip_module **modules) return PJ_SUCCESS; } +static pj_status_t init_report(void) +{ + char tmp[80]; + pj_time_val timestamp; + pj_parsed_time date_time; + pj_ssize_t len; + pj_status_t status; + + pj_ansi_sprintf(tmp, "pjsip-static-bench-%s-%s.htm", PJ_OS_NAME, PJ_CC_NAME); + + status = pj_file_open(NULL, tmp, PJ_O_WRONLY, &fd_report); + if (status != PJ_SUCCESS) + return status; + + /* Title */ + len = pj_ansi_sprintf(buf, "<HTML>\n" + " <HEAD>\n" + " <TITLE>PJSIP %s (%s) - Static Benchmark</TITLE>\n" + " </HEAD>\n" + "<BODY>\n" + "\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + + /* Title */ + len = pj_ansi_sprintf(buf, "<H1>PJSIP %s (%s) - Static Benchmark</H1>\n", + PJ_VERSION, + (PJ_DEBUG ? "Debug" : "Release")); + pj_file_write(fd_report, buf, &len); + + len = pj_ansi_sprintf(buf, "<P>Below is the benchmark result generated " + "by <b>test-pjsip</b> program. The program " + "is single-threaded only.</P>\n"); + pj_file_write(fd_report, buf, &len); + + + /* Write table heading */ + len = pj_ansi_sprintf(buf, "<TABLE border=\"1\" cellpadding=\"4\">\n" + " <TR><TD bgColor=\"aqua\" align=\"center\">Variable</TD>\n" + " <TD bgColor=\"aqua\" align=\"center\">Value</TD>\n" + " <TD bgColor=\"aqua\" align=\"center\">Description</TD>\n" + " </TR>\n"); + pj_file_write(fd_report, buf, &len); + + + /* Write version */ + report_sval("version", PJ_VERSION, "", "PJLIB/PJSIP version"); + + + /* Debug or release */ + report_sval("build-type", (PJ_DEBUG ? "Debug" : "Release"), "", "Build type"); + + + /* Write timestamp */ + pj_gettimeofday(×tamp); + report_ival("timestamp", timestamp.sec, "", "System timestamp of the test"); + + + /* Write time of day */ + pj_time_decode(×tamp, &date_time); + len = pj_ansi_sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", + date_time.year, date_time.mon+1, date_time.day, + date_time.hour, date_time.min, date_time.sec); + report_sval("date-time", tmp, "", "Date/time of the test"); + + + /* Write System */ + report_sval("system", system_name, "", "System description"); + + + /* Write OS type */ + report_sval("os-family", PJ_OS_NAME, "", "Operating system family"); + + + /* Write CC name */ + len = pj_ansi_sprintf(tmp, "%s-%d.%d.%d", PJ_CC_NAME, + PJ_CC_VER_1, PJ_CC_VER_2, PJ_CC_VER_2); + report_sval("cc-name", tmp, "", "Compiler name and version"); + + + return PJ_SUCCESS; +} + +void report_sval(const char *name, const char* value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " <TR><TD><TT>%s</TT></TD>\n" + " <TD align=\"right\"><B>%s %s</B></TD>\n" + " <TD>%s</TD>\n" + " </TR>\n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); +} + + +void report_ival(const char *name, int value, const char *valname, + const char *desc) +{ + pj_ssize_t len; + + len = pj_ansi_sprintf(buf, " <TR><TD><TT>%s</TT></TD>\n" + " <TD align=\"right\"><B>%d %s</B></TD>\n" + " <TD>%s</TD>\n" + " </TR>\n", + name, value, valname, desc); + pj_file_write(fd_report, buf, &len); + +} + +static void close_report(void) +{ + pj_ssize_t len; + + if (fd_report) { + len = pj_ansi_sprintf(buf, "</TABLE>\n</BODY>\n</HTML>\n"); + pj_file_write(fd_report, buf, &len); + + pj_file_close(fd_report); + } +} + + int test_main(void) { pj_status_t rc; pj_caching_pool caching_pool; const char *filename; + unsigned i, tsx_test_cnt=0; + struct tsx_test_param tsx_test[10]; + pj_status_t status; + pjsip_transport *tp; + pjsip_tpfactory *tpfactory; int line; pj_log_set_level(log_level); @@ -93,6 +237,10 @@ int test_main(void) return rc; } + status = init_report(); + if (status != PJ_SUCCESS) + return status; + pj_dump_config(); pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 ); @@ -124,6 +272,11 @@ int test_main(void) rc); goto on_return; } + tsx_test[tsx_test_cnt].port = 5060; + tsx_test[tsx_test_cnt].tp_type = "loop-dgram"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_LOOP_DGRAM; + ++tsx_test_cnt; + #if INCLUDE_URI_TEST DO_TEST(uri_test()); @@ -138,6 +291,10 @@ int test_main(void) DO_TEST(txdata_test()); #endif +#if INCLUDE_TSX_BENCH + DO_TEST(tsx_bench()); +#endif + #if INCLUDE_UDP_TEST DO_TEST(transport_udp_test()); #endif @@ -146,15 +303,43 @@ int test_main(void) DO_TEST(transport_loop_test()); #endif +#if INCLUDE_TCP_TEST + DO_TEST(transport_tcp_test()); +#endif + + #if INCLUDE_TSX_TEST - DO_TEST(tsx_basic_test()); - DO_TEST(tsx_uac_test()); - DO_TEST(tsx_uas_test()); + status = pjsip_udp_transport_start(endpt, NULL, NULL, 1, &tp); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tp->local_name.port; + tsx_test[tsx_test_cnt].tp_type = "udp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_UDP; + ++tsx_test_cnt; + } + + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status == PJ_SUCCESS) { + tsx_test[tsx_test_cnt].port = tpfactory->addr_name.port; + tsx_test[tsx_test_cnt].tp_type = "tcp"; + tsx_test[tsx_test_cnt].type = PJSIP_TRANSPORT_TCP; + ++tsx_test_cnt; + } else { + app_perror("Unable to create TCP", status); + rc = -4; + goto on_return; + } + + + for (i=0; i<tsx_test_cnt; ++i) { + DO_TSX_TEST(tsx_basic_test, &tsx_test[i]); + DO_TSX_TEST(tsx_uac_test, &tsx_test[i]); + DO_TSX_TEST(tsx_uas_test, &tsx_test[i]); + } #endif on_return: - + flush_events(500); pjsip_endpt_destroy(endpt); pj_caching_pool_destroy(&caching_pool); @@ -169,6 +354,8 @@ on_return: else PJ_LOG(3,(THIS_FILE, "Test completed with error(s)")); + report_ival("test-status", rc, "", "Overall test status/result (0==success)"); + close_report(); return rc; } diff --git a/pjsip/src/test-pjsip/test.h b/pjsip/src/test-pjsip/test.h index f2b6b91d..969b341a 100644 --- a/pjsip/src/test-pjsip/test.h +++ b/pjsip/src/test-pjsip/test.h @@ -31,13 +31,22 @@ extern pjsip_endpoint *endpt; #define INCLUDE_TRANSPORT_GROUP 1 #define INCLUDE_TSX_GROUP 1 +/* + * Include tests that normally would fail under certain gcc + * optimization levels. + */ +#ifndef INCLUDE_GCC_TEST +# define INCLUDE_GCC_TEST 0 +#endif #define INCLUDE_URI_TEST INCLUDE_MESSAGING_GROUP #define INCLUDE_MSG_TEST INCLUDE_MESSAGING_GROUP #define INCLUDE_TXDATA_TEST INCLUDE_MESSAGING_GROUP +#define INCLUDE_TSX_BENCH INCLUDE_MESSAGING_GROUP #define INCLUDE_UDP_TEST INCLUDE_TRANSPORT_GROUP #define INCLUDE_LOOP_TEST INCLUDE_TRANSPORT_GROUP +#define INCLUDE_TCP_TEST INCLUDE_TRANSPORT_GROUP #define INCLUDE_TSX_TEST INCLUDE_TSX_GROUP @@ -47,17 +56,28 @@ int uri_test(void); int msg_test(void); int msg_err_test(void); int txdata_test(void); +int tsx_bench(void); int transport_udp_test(void); int transport_loop_test(void); -int tsx_basic_test(void); -int tsx_uac_test(void); -int tsx_uas_test(void); +int transport_tcp_test(void); + +struct tsx_test_param +{ + int type; + int port; + char *tp_type; +}; + +int tsx_basic_test(struct tsx_test_param *param); +int tsx_uac_test(struct tsx_test_param *param); +int tsx_uas_test(struct tsx_test_param *param); /* Transport test helpers (transport_test.c). */ int generic_transport_test(pjsip_transport *tp); int transport_send_recv_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, - char *target_url ); + char *target_url, + int *p_usec_rtt); int transport_rt_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, char *target_url, @@ -68,10 +88,15 @@ int test_main(void); /* Test utilities. */ void app_perror(const char *msg, pj_status_t status); -int init_msg_logger(void); -int msg_logger_set_enabled(pj_bool_t enabled); +int init_msg_logger(void); +int msg_logger_set_enabled(pj_bool_t enabled); void flush_events(unsigned duration); + +void report_ival(const char *name, int value, const char *valname, const char *desc); +void report_sval(const char *name, const char* value, const char *valname, const char *desc); + + /* Settings. */ extern int log_level; diff --git a/pjsip/src/test-pjsip/transport_loop_test.c b/pjsip/src/test-pjsip/transport_loop_test.c index 351fb7b6..3e378832 100644 --- a/pjsip/src/test-pjsip/transport_loop_test.c +++ b/pjsip/src/test-pjsip/transport_loop_test.c @@ -25,10 +25,13 @@ static int datagram_loop_test() { + enum { LOOP = 8 }; pjsip_transport *loop; int i, pkt_lost; pj_sockaddr_in addr; pj_status_t status; + long ref_cnt; + unsigned rtt[LOOP], min_rtt; PJ_LOG(3,(THIS_FILE, "testing datagram loop transport")); @@ -40,19 +43,33 @@ static int datagram_loop_test() return -20; } + /* Get initial reference counter */ + ref_cnt = pj_atomic_get(loop->ref_cnt); + /* Test basic transport attributes */ status = generic_transport_test(loop); if (status != PJ_SUCCESS) return status; /* Basic transport's send/receive loopback test. */ - for (i=0; i<2; ++i) { + for (i=0; i<LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop, - "sip:bob@130.0.0.1;transport=loop-dgram"); + "sip:bob@130.0.0.1;transport=loop-dgram", + &rtt[i]); if (status != 0) return status; } + min_rtt = 0xFFFFFFF; + for (i=0; i<LOOP; ++i) + if (rtt[i] < min_rtt) min_rtt = rtt[i]; + + report_ival("loop-rtt-usec", min_rtt, "usec", + "Best Loopback transport round trip time, in microseconds " + "(time from sending request until response is received. " + "Tests were performed on local machine only)"); + + /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_LOOP_DGRAM, loop, "sip:bob@130.0.0.1;transport=loop-dgram", @@ -84,9 +101,11 @@ static int datagram_loop_test() /* Restore delay. */ pjsip_loop_set_delay(loop, 0); - /* Check that reference counter is one. */ - if (pj_atomic_get(loop->ref_cnt) != 1) { - return -50; + /* Check reference counter. */ + if (pj_atomic_get(loop->ref_cnt) != ref_cnt) { + PJ_LOG(3,(THIS_FILE, " error: ref counter is not %d (%d)", + ref_cnt, pj_atomic_get(loop->ref_cnt))); + return -51; } /* Decrement reference. */ diff --git a/pjsip/src/test-pjsip/transport_tcp_test.c b/pjsip/src/test-pjsip/transport_tcp_test.c new file mode 100644 index 00000000..70f1bc92 --- /dev/null +++ b/pjsip/src/test-pjsip/transport_tcp_test.c @@ -0,0 +1,143 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "test.h" +#include <pjsip.h> +#include <pjlib.h> + +#define THIS_FILE "transport_tcp_test.c" + + +/* + * TCP transport test. + */ +int transport_tcp_test(void) +{ + enum { SEND_RECV_LOOP = 8 }; + pjsip_tpfactory *tpfactory; + pjsip_transport *tcp; + pj_sockaddr_in rem_addr; + pj_status_t status; + char url[64]; + unsigned rtt[SEND_RECV_LOOP], min_rtt; + int i, pkt_lost; + + /* Start TCP listener on arbitrary port. */ + status = pjsip_tcp_transport_start(endpt, NULL, 1, &tpfactory); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to start TCP transport", status); + return -10; + } + + + /* Get the listener address */ + status = pj_sockaddr_in_init(&rem_addr, &tpfactory->addr_name.host, + (pj_uint16_t)tpfactory->addr_name.port); + if (status != PJ_SUCCESS) { + app_perror(" Error: possibly invalid TCP address name", status); + return -14; + } + + pj_ansi_sprintf(url, "sip:alice@%s:%d;transport=tcp", + pj_inet_ntoa(rem_addr.sin_addr), + pj_ntohs(rem_addr.sin_port)); + + + /* Acquire one TCP transport. */ + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_TCP, + &rem_addr, sizeof(rem_addr), + &tcp); + if (status != PJ_SUCCESS || tcp == NULL) { + app_perror(" Error: unable to acquire TCP transport", status); + return -17; + } + + /* After pjsip_endpt_acquire_transport, TCP transport must have + * reference counter 1. + */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -20; + + /* Test basic transport attributes */ + status = generic_transport_test(tcp); + if (status != PJ_SUCCESS) + return status; + + + /* Check again that reference counter is 1. */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -70; + + /* Basic transport's send/receive loopback test. */ + for (i=0; i<SEND_RECV_LOOP; ++i) { + status = transport_send_recv_test(PJSIP_TRANSPORT_TCP, tcp, url, &rtt[i]); + + if (status != 0) { + pjsip_transport_dec_ref(tcp); + flush_events(500); + return -72; + } + } + + min_rtt = 0xFFFFFFF; + for (i=0; i<SEND_RECV_LOOP; ++i) + if (rtt[i] < min_rtt) min_rtt = rtt[i]; + + report_ival("tcp-rtt-usec", min_rtt, "usec", + "Best TCP transport round trip time, in microseconds " + "(time from sending request until response is received. " + "Tests were performed on local machine only, and after " + "TCP socket has been established by previous test)"); + + + /* Multi-threaded round-trip test. */ + status = transport_rt_test(PJSIP_TRANSPORT_TCP, tcp, url, &pkt_lost); + if (status != 0) { + pjsip_transport_dec_ref(tcp); + return status; + } + + if (pkt_lost != 0) + PJ_LOG(3,(THIS_FILE, " note: %d packet(s) was lost", pkt_lost)); + + /* Check again that reference counter is still 1. */ + if (pj_atomic_get(tcp->ref_cnt) != 1) + return -80; + + /* Destroy this transport. */ + pjsip_transport_dec_ref(tcp); + + /* Force destroy this transport. */ + status = pjsip_transport_destroy(tcp); + if (status != PJ_SUCCESS) + return -90; + + /* Unregister factory */ + status = pjsip_tpmgr_unregister_tpfactory(pjsip_endpt_get_tpmgr(endpt), + tpfactory); + if (status != PJ_SUCCESS) + return -95; + + /* Flush events. */ + PJ_LOG(3,(THIS_FILE, " Flushing events, 1 second...")); + flush_events(1000); + + /* Done */ + return 0; +} diff --git a/pjsip/src/test-pjsip/transport_test.c b/pjsip/src/test-pjsip/transport_test.c index 0cd0d225..5aa491a2 100644 --- a/pjsip/src/test-pjsip/transport_test.c +++ b/pjsip/src/test-pjsip/transport_test.c @@ -173,7 +173,8 @@ static void send_msg_callback(pjsip_send_state *stateless_data, /* Test that we receive loopback message. */ int transport_send_recv_test( pjsip_transport_type_e tp_type, pjsip_transport *ref_tp, - char *target_url ) + char *target_url, + int *p_usec_rtt) { pj_bool_t msg_log_enabled; pj_status_t status; @@ -220,6 +221,8 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, pj_get_timestamp(&my_send_time); /* Send the message (statelessly). */ + PJ_LOG(5,(THIS_FILE, "Sending request to %.*s", + (int)target.slen, target.ptr)); status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL, &send_msg_callback); if (status != PJ_SUCCESS) { @@ -228,9 +231,9 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, send_status = status; } - /* Set the timeout (1 second from now) */ + /* Set the timeout (2 seconds from now) */ pj_gettimeofday(&timeout); - timeout.sec += 1; + timeout.sec += 2; /* Loop handling events until we get status */ do { @@ -268,7 +271,10 @@ int transport_send_recv_test( pjsip_transport_type_e tp_type, if (status == PJ_SUCCESS) { unsigned usec_rt; usec_rt = pj_elapsed_usec(&my_send_time, &my_recv_time); + PJ_LOG(3,(THIS_FILE, " round-trip = %d usec", usec_rt)); + + *p_usec_rtt = usec_rt; } /* Restore message logging. */ @@ -516,7 +522,6 @@ int transport_rt_test( pjsip_transport_type_e tp_type, unsigned total_sent; unsigned total_recv; - PJ_LOG(3,(THIS_FILE, " multithreaded round-trip test (%d threads)...", THREADS)); PJ_LOG(3,(THIS_FILE, " this will take approx %d seconds, please wait..", diff --git a/pjsip/src/test-pjsip/transport_udp_test.c b/pjsip/src/test-pjsip/transport_udp_test.c index 4db0a7ca..34bb02c4 100644 --- a/pjsip/src/test-pjsip/transport_udp_test.c +++ b/pjsip/src/test-pjsip/transport_udp_test.c @@ -29,11 +29,12 @@ */ int transport_udp_test(void) { - enum { SEND_RECV_LOOP = 2 }; + enum { SEND_RECV_LOOP = 8 }; pjsip_transport *udp_tp, *tp; pj_sockaddr_in addr, rem_addr; pj_str_t s; pj_status_t status; + unsigned rtt[SEND_RECV_LOOP], min_rtt; int i, pkt_lost; pj_sockaddr_in_init(&addr, NULL, TEST_UDP_PORT); @@ -79,11 +80,22 @@ int transport_udp_test(void) pj_sockaddr_in_init(&rem_addr, pj_cstr(&s, "127.0.0.1"), TEST_UDP_PORT); for (i=0; i<SEND_RECV_LOOP; ++i) { status = transport_send_recv_test(PJSIP_TRANSPORT_UDP, tp, - "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR); + "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR, + &rtt[i]); if (status != 0) return status; } + min_rtt = 0xFFFFFFF; + for (i=0; i<SEND_RECV_LOOP; ++i) + if (rtt[i] < min_rtt) min_rtt = rtt[i]; + + report_ival("udp-rtt-usec", min_rtt, "usec", + "Best UDP transport round trip time, in microseconds " + "(time from sending request until response is received. " + "Tests were performed on local machine only)"); + + /* Multi-threaded round-trip test. */ status = transport_rt_test(PJSIP_TRANSPORT_UDP, tp, "sip:alice@127.0.0.1:"TEST_UDP_PORT_STR, diff --git a/pjsip/src/test-pjsip/tsx_basic_test.c b/pjsip/src/test-pjsip/tsx_basic_test.c index 6be0ea2a..afe72279 100644 --- a/pjsip/src/test-pjsip/tsx_basic_test.c +++ b/pjsip/src/test-pjsip/tsx_basic_test.c @@ -23,6 +23,10 @@ #define THIS_FILE "tsx_basic_test.c" +static char TARGET_URI[128]; +static char FROM_URI[128]; + + /* Test transaction layer. */ static int tsx_layer_test(void) { @@ -33,8 +37,8 @@ static int tsx_layer_test(void) PJ_LOG(3,(THIS_FILE, " transaction layer test")); - target = pj_str("sip:alice@localhost"); - from = pj_str("sip:bob@localhost"); + target = pj_str(TARGET_URI); + from = pj_str(FROM_URI); status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, &from, &target, NULL, NULL, -1, NULL, @@ -77,8 +81,8 @@ static int double_terminate(void) PJ_LOG(3,(THIS_FILE, " double terminate test")); - target = pj_str("sip:alice@localhost;transport=loop-dgram"); - from = pj_str("sip:bob@localhost"); + target = pj_str(TARGET_URI); + from = pj_str(FROM_URI); /* Create request. */ status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, @@ -131,10 +135,15 @@ static int double_terminate(void) return PJ_SUCCESS; } -int tsx_basic_test(void) +int tsx_basic_test(struct tsx_test_param *param) { int status; + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + status = tsx_layer_test(); if (status != 0) return status; diff --git a/pjsip/src/test-pjsip/tsx_bench.c b/pjsip/src/test-pjsip/tsx_bench.c new file mode 100644 index 00000000..53c950cb --- /dev/null +++ b/pjsip/src/test-pjsip/tsx_bench.c @@ -0,0 +1,273 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include <pjsip.h> +#include <pjlib.h> + +#define THIS_FILE "tsx_uas_test.c" + + +static pjsip_module mod_tsx_user; + +static int uac_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) +{ + unsigned i; + pjsip_tx_data *request; + pjsip_transaction **tsx; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + /* Create the request first. */ + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); + pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create transaction array */ + tsx = pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_memset(&mod_tsx_user, 0, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; i<working_set; ++i) { + status = pjsip_tsx_create_uac(&mod_tsx_user, request, &tsx[i]); + if (status != PJ_SUCCESS) + goto on_error; + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + p_elapsed->u64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; i<working_set; ++i) { + if (tsx[i]) { + pjsip_tsx_terminate(tsx[i], 601); + tsx[i] = NULL; + } + } + pjsip_tx_data_dec_ref(request); + flush_events(2000); + return status; +} + + + +static int uas_tsx_bench(unsigned working_set, pj_timestamp *p_elapsed) +{ + unsigned i; + pjsip_tx_data *request; + pjsip_via_hdr *via; + pjsip_rx_data rdata; + pj_sockaddr_in remote; + pjsip_transaction **tsx; + pj_timestamp t1, t2, elapsed; + char branch_buf[80] = PJSIP_RFC3261_BRANCH_ID "0000000000"; + pj_status_t status; + + /* Create the request first. */ + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); + pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create Via */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 1; + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_memset(&rdata, 0, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + pj_sockaddr_in_init(&remote, 0, 0); + status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, + &remote, sizeof(pj_sockaddr_in), + &rdata.tp_info.transport); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to get loop transport", status); + return status; + } + + + /* Create transaction array */ + tsx = pj_pool_zalloc(request->pool, working_set * sizeof(pj_pool_t*)); + + pj_memset(&mod_tsx_user, 0, sizeof(mod_tsx_user)); + mod_tsx_user.id = -1; + + + /* Benchmark */ + elapsed.u64 = 0; + pj_get_timestamp(&t1); + for (i=0; i<working_set; ++i) { + via->branch_param.ptr = branch_buf; + via->branch_param.slen = PJSIP_RFC3261_BRANCH_LEN + + pj_ansi_sprintf(branch_buf+PJSIP_RFC3261_BRANCH_LEN, + "-%d", i); + status = pjsip_tsx_create_uas(&mod_tsx_user, &rdata, &tsx[i]); + if (status != PJ_SUCCESS) + goto on_error; + + } + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + p_elapsed->u64 = elapsed.u64; + status = PJ_SUCCESS; + +on_error: + for (i=0; i<working_set; ++i) { + if (tsx[i]) { + pjsip_tsx_terminate(tsx[i], 601); + tsx[i] = NULL; + } + } + pjsip_tx_data_dec_ref(request); + flush_events(2000); + return status; +} + + + +int tsx_bench(void) +{ + enum { WORKING_SET=PJSIP_MAX_TSX_COUNT, REPEAT = 4 }; + unsigned i, speed; + pj_timestamp usec[REPEAT], min, freq; + char desc[250]; + int status; + + status = pj_get_timestamp_freq(&freq); + if (status != PJ_SUCCESS) + return status; + + + /* + * Benchmark UAC + */ + PJ_LOG(3,(THIS_FILE, " benchmarking UAC transaction creation:")); + for (i=0; i<REPEAT; ++i) { + PJ_LOG(3,(THIS_FILE, " test %d of %d..", + i+1, REPEAT)); + status = uac_tsx_bench(WORKING_SET, &usec[i]); + if (status != PJ_SUCCESS) + return status; + } + + min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); + for (i=0; i<REPEAT; ++i) { + if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; + } + + + /* Report time */ + pj_ansi_sprintf(desc, "Time to create %d UAC transactions, in miliseconds", + WORKING_SET); + report_ival("create-uac-time", (unsigned)(min.u64 * 1000 / freq.u64), "msec", desc); + + + /* Write speed */ + speed = (unsigned)(freq.u64 * WORKING_SET / min.u64); + PJ_LOG(3,(THIS_FILE, " UAC created at %d tsx/sec", speed)); + + pj_ansi_sprintf(desc, "Number of UAC transactions that potentially can be created per second " + "with <tt>pjsip_tsx_create_uac()</tt>, based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uac-tsx-per-sec", + speed, "tsx/sec", desc); + + + + /* + * Benchmark UAS + */ + PJ_LOG(3,(THIS_FILE, " benchmarking UAS transaction creation:")); + for (i=0; i<REPEAT; ++i) { + PJ_LOG(3,(THIS_FILE, " test %d of %d..", + i+1, REPEAT)); + status = uas_tsx_bench(WORKING_SET, &usec[i]); + if (status != PJ_SUCCESS) + return status; + } + + min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); + for (i=0; i<REPEAT; ++i) { + if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; + } + + + /* Report time */ + pj_ansi_sprintf(desc, "Time to create %d UAS transactions, in miliseconds", + WORKING_SET); + report_ival("create-uas-time", (unsigned)(min.u64 * 1000 / freq.u64), "msec", desc); + + + /* Write speed */ + speed = (unsigned)(freq.u64 * WORKING_SET / min.u64); + PJ_LOG(3,(THIS_FILE, " UAS created at %d tsx/sec", speed)); + + pj_ansi_sprintf(desc, "Number of UAS transactions that potentially can be created per second " + "with <tt>pjsip_tsx_create_uas()</tt>, based on the time " + "to create %d simultaneous transactions above.", + WORKING_SET); + + report_ival("create-uas-tsx-per-sec", + speed, "tsx/sec", desc); + + return PJ_SUCCESS; +} + diff --git a/pjsip/src/test-pjsip/tsx_uac_test.c b/pjsip/src/test-pjsip/tsx_uac_test.c index d2717fec..b97b01a9 100644 --- a/pjsip/src/test-pjsip/tsx_uac_test.c +++ b/pjsip/src/test-pjsip/tsx_uac_test.c @@ -91,6 +91,10 @@ static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9"; #define TEST4_RETRANSMIT_CNT 3 #define TEST5_RETRANSMIT_CNT 3 +static char TARGET_URI[128]; +static char FROM_URI[128]; +static unsigned tp_flag; +static struct tsx_test_param *test_param; static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e); static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata); @@ -140,7 +144,12 @@ static pj_bool_t test_complete; static pjsip_transport *loop; /* General timer entry to be used by tests. */ -static pj_timer_entry timer; +static struct my_timer +{ + pj_timer_entry entry; + char key_buf[1024]; + pj_str_t tsx_key; +} timer; /* * This is the handler to receive state changed notification from the @@ -166,6 +175,41 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) tsx->status_code, PJSIP_SC_TSX_TIMEOUT)); test_complete = -710; } + + + /* If transport is reliable, then there must not be any + * retransmissions. + */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + if (recv_count != 1) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -715; + } + } else { + /* Check the number of transmissions, which must be + * 6 for INVITE and 10 for non-INVITE + */ + if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -716; + } else + if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) { + PJ_LOG(3,(THIS_FILE, + " error: there were %d (re)transmissions", + recv_count)); + test_complete = -717; + } else + if (tsx->method.id!=PJSIP_INVITE_METHOD && + tsx->method.id!=PJSIP_OPTIONS_METHOD) + { + PJ_LOG(3,(THIS_FILE, " error: unexpected method")); + test_complete = -718; + } + } } } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) { @@ -515,7 +559,8 @@ static void send_response_callback( pj_timer_heap_t *timer_heap, static void terminate_tsx_callback( pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry) { - pjsip_transaction *tsx = entry->user_data; + struct my_timer *m = (struct my_timer *)entry; + pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE); int status_code = entry->id; if (tsx) { @@ -720,9 +765,9 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); - timer.cb = &send_response_callback; - timer.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); return PJ_TRUE; @@ -768,11 +813,11 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); - timer.id = 301; - timer.cb = &terminate_tsx_callback; + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 301; + timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { @@ -841,9 +886,9 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); - timer.cb = &send_response_callback; - timer.user_data = r; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + timer.entry.cb = &send_response_callback; + timer.entry.user_data = r; + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } else if (method->id == PJSIP_ACK_METHOD) { @@ -859,11 +904,11 @@ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); - timer.user_data = pjsip_tsx_layer_find_tsx(&key, PJ_FALSE); - timer.id = 302; - timer.cb = &terminate_tsx_callback; + pj_strcpy(&timer.tsx_key, &key); + timer.entry.id = 302; + timer.entry.cb = &terminate_tsx_callback; - pjsip_endpt_schedule_timer(endpt, &timer, &delay); + pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { @@ -980,10 +1025,23 @@ static int perform_tsx_test(int dummy, char *target_uri, char *from_uri, } pjsip_tx_data_dec_ref(tdata); return test_complete; - } - /* Allow transaction to destroy itself */ - flush_events(500); + } else { + pj_time_val now; + + /* Allow transaction to destroy itself */ + flush_events(500); + + /* Wait until test completes */ + pj_gettimeofday(&now); + + if (PJ_TIME_VAL_LT(now, timeout)) { + pj_time_val interval; + interval = timeout; + PJ_TIME_VAL_SUB(interval, now); + flush_events(PJ_TIME_VAL_MSEC(interval)); + } + } /* Make sure transaction has been destroyed. */ if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) { @@ -1052,8 +1110,7 @@ static int tsx_uac_retransmit_test(void) pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL); /* Do the test. */ - status = perform_tsx_test(-500, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-500, TARGET_URI, FROM_URI, TEST1_BRANCH_ID, 35, sub_test[i].method); if (status != 0) @@ -1093,9 +1150,8 @@ static int tsx_resolve_error_test(void) PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error")); status = perform_tsx_test(-800, - "sip:bob@unresolved-host;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, 10, + "sip:bob@unresolved-host", + FROM_URI, TEST2_BRANCH_ID, 10, &pjsip_options_method); if (status != 0) return status; @@ -1105,20 +1161,22 @@ static int tsx_resolve_error_test(void) */ PJ_LOG(3,(THIS_FILE, " variant b: error via callback")); - /* Set loop transport to return delayed error. */ - pjsip_loop_set_failure(loop, 2, NULL); - pjsip_loop_set_send_callback_delay(loop, 10, NULL); + /* This only applies to "loop-dgram" transport */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + /* Set loop transport to return delayed error. */ + pjsip_loop_set_failure(loop, 2, NULL); + pjsip_loop_set_send_callback_delay(loop, 10, NULL); - status = perform_tsx_test(-800, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, 2, - &pjsip_options_method); - if (status != 0) - return status; + status = perform_tsx_test(-800, TARGET_URI, FROM_URI, + TEST2_BRANCH_ID, 2, + &pjsip_options_method); + if (status != 0) + return status; - /* Restore loop transport settings. */ - pjsip_loop_set_failure(loop, 0, NULL); - pjsip_loop_set_send_callback_delay(loop, 0, NULL); + /* Restore loop transport settings. */ + pjsip_loop_set_failure(loop, 0, NULL); + pjsip_loop_set_send_callback_delay(loop, 0, NULL); + } return status; } @@ -1143,8 +1201,7 @@ static int tsx_terminate_resolving_test(void) pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay); /* Start the test. */ - status = perform_tsx_test(-900, "sip:127.0.0.1;transport=loop-dgram", - "sip:127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-900, TARGET_URI, FROM_URI, TEST3_BRANCH_ID, 2, &pjsip_options_method); /* Restore delay. */ @@ -1186,8 +1243,7 @@ static int tsx_retransmit_fail_test(void) pjsip_loop_set_failure(loop, 0, 0); /* Start the test. */ - status = perform_tsx_test(-1000, "sip:127.0.0.1;transport=loop-dgram", - "sip:127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-1000, TARGET_URI, FROM_URI, TEST4_BRANCH_ID, 6, &pjsip_options_method); if (status != 0) @@ -1218,8 +1274,7 @@ static int tsx_terminate_after_retransmit_test(void) PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions")); /* Do the test. */ - status = perform_tsx_test(-1100, "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", + status = perform_tsx_test(-1100, TARGET_URI, FROM_URI, TEST5_BRANCH_ID, 6, &pjsip_options_method); @@ -1249,18 +1304,20 @@ static int perform_generic_test( const char *title, /* Do the test. */ for (i=0; i<PJ_ARRAY_SIZE(delay); ++i) { - PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay", - ('a'+i), delay[i])); + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay", + ('a'+i), delay[i])); - pjsip_loop_set_delay(loop, delay[i]); + pjsip_loop_set_delay(loop, delay[i]); + } - status = perform_tsx_test(-1200, - "sip:bob@127.0.0.1;transport=loop-dgram", - "sip:alice@127.0.0.1;transport=loop-dgram", - branch_id, - 10, method); + status = perform_tsx_test(-1200, TARGET_URI, FROM_URI, + branch_id, 10, method); if (status != 0) return status; + + if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM) + break; } pjsip_loop_set_delay(loop, 0); @@ -1276,11 +1333,23 @@ static int perform_generic_test( const char *title, ** ***************************************************************************** */ -int tsx_uac_test(void) +int tsx_uac_test(struct tsx_test_param *param) { pj_sockaddr_in addr; pj_status_t status; + timer.tsx_key.ptr = timer.key_buf; + + test_param = param; + + /* Get transport flag */ + tp_flag = pjsip_transport_get_flag_from_type(test_param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + /* Check if loop transport is configured. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &addr, sizeof(addr), &loop); @@ -1316,15 +1385,23 @@ int tsx_uac_test(void) if (status != 0) return status; - /* TEST4_BRANCH_ID: Transport failed after several retransmissions */ - status = tsx_retransmit_fail_test(); - if (status != 0) - return status; + /* TEST4_BRANCH_ID: Transport failed after several retransmissions. + * Only applies to loop transport. + */ + if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_retransmit_fail_test(); + if (status != 0) + return status; + } - /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions */ - status = tsx_terminate_after_retransmit_test(); - if (status != 0) - return status; + /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions + * Only applicable to non-reliable transports. + */ + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_terminate_after_retransmit_test(); + if (status != 0) + return status; + } /* TEST6_BRANCH_ID: Successfull non-invite transaction */ status = perform_generic_test("test6: successfull non-invite transaction", @@ -1352,8 +1429,21 @@ int tsx_uac_test(void) if (status != 0) return status; - pjsip_transport_dec_ref(loop); + flush_events(500); + + /* Unregister modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -31; + } + status = pjsip_endpt_unregister_module(endpt, &msg_receiver); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -41; + } + return 0; } diff --git a/pjsip/src/test-pjsip/tsx_uas_test.c b/pjsip/src/test-pjsip/tsx_uas_test.c index 3ff2e18e..42cb075f 100644 --- a/pjsip/src/test-pjsip/tsx_uas_test.c +++ b/pjsip/src/test-pjsip/tsx_uas_test.c @@ -35,6 +35,8 @@ ** TEST1_BRANCH_ID ** Test that non-INVITE transaction returns 2xx response to the correct ** transport and correctly terminates the transaction. + ** This also checks that transaction is destroyed immediately after + ** it sends final response when reliable transport is used. ** ** TEST2_BRANCH_ID ** As above, for non-2xx final response. @@ -53,6 +55,7 @@ ** ** TEST6_BRANCH_ID ** As above, in COMPLETED state, with first sending provisional response. + ** (Only applicable for non-reliable transports). ** ** TEST7_BRANCH_ID ** INVITE transaction MUST retransmit non-2xx final response. @@ -65,6 +68,7 @@ ** ACK is received. (Note: PJSIP also retransmit 2xx final response ** until it's terminated by user). ** Transaction also MUST terminate in T4 seconds. + ** (Only applicable for non-reliable transports). ** ** TEST11_BRANCH_ID ** Test scenario where transport fails before response is sent (i.e. @@ -128,6 +132,12 @@ static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13"; #define TEST6_TITLE "test6: retransmit last response in COMPLETED state" +static char TARGET_URI[128]; +static char FROM_URI[128]; +static struct tsx_test_param *test_param; +static unsigned tp_flag; + + #define TEST_TIMEOUT_ERROR -30 #define MAX_ALLOWED_DIFF 150 @@ -521,7 +531,9 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) /* Check that status code is status_code. */ if (tsx->status_code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: incorrect status code")); + PJ_LOG(3,(THIS_FILE, " error: incorrect status code %d " + "(expecting %d)", tsx->status_code, + TEST6_STATUS_CODE)); test_complete = -140; } @@ -577,6 +589,26 @@ static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e) test_complete = -151; } + /* Check the number of retransmissions */ + if (tp_flag & PJSIP_TRANSPORT_RELIABLE) { + + if (tsx->retransmit_count != 0) { + PJ_LOG(3,(THIS_FILE, " error: should not retransmit")); + test_complete = -1510; + } + + } else { + + if (tsx->retransmit_count != 10) { + PJ_LOG(3,(THIS_FILE, + " error: incorrect retransmit count %d " + "(expecting 10)", + tsx->retransmit_count)); + test_complete = -1510; + } + + } + } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) { /* Check that status code is status_code. */ @@ -814,6 +846,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) /* On received request, create UAS. */ pjsip_transaction *tsx; + PJ_LOG(4,(THIS_FILE, " received request (probably retransmission)")); + status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { app_perror(" error: unable to create transaction", status); @@ -830,13 +864,17 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) send_response(rdata, tsx, TEST5_PROVISIONAL_CODE); } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) { + PJ_LOG(4,(THIS_FILE, " sending provisional response")); send_response(rdata, tsx, TEST6_PROVISIONAL_CODE); + PJ_LOG(4,(THIS_FILE, " sending final response")); send_response(rdata, tsx, TEST6_STATUS_CODE); } } else { /* Verify the response received. */ + PJ_LOG(4,(THIS_FILE, " received response number %d", recv_count)); + ++recv_count; if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) { @@ -869,7 +907,8 @@ static pj_bool_t on_rx_message(pjsip_rx_data *rdata) case 2: case 3: if (code != TEST6_STATUS_CODE) { - PJ_LOG(3,(THIS_FILE, " error: invalid code!")); + PJ_LOG(3,(THIS_FILE, " error: invalid code %d " + "(expecting %d)", code, TEST6_STATUS_CODE)); test_complete = -136; } break; @@ -1183,6 +1222,8 @@ static int perform_test( char *target_uri, char *from_uri, pjsip_tx_data_add_ref(tdata); /* (Re)Send the request. */ + PJ_LOG(4,(THIS_FILE, " (re)sending request %d", sent_cnt)); + status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0); if (status != PJ_SUCCESS) { app_perror(" Error: unable to send request", status); @@ -1255,25 +1296,25 @@ static int perform_test( char *target_uri, char *from_uri, */ static int tsx_basic_final_response_test(void) { + unsigned duration; int status; PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST1_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_options_method, 1, 0, 0); + /* Test duration must be greater than 32 secs if unreliable transport + * is used. + */ + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + + status = perform_test(TARGET_URI, FROM_URI, TEST1_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); if (status != 0) return status; PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST2_BRANCH_ID, - 33, /* Test duration must be greater than 32 secs */ - &pjsip_options_method, 1, 0, 0); + status = perform_test(TARGET_URI, FROM_URI, TEST2_BRANCH_ID, + duration, &pjsip_options_method, 1, 0, 0); if (status != 0) return status; @@ -1289,14 +1330,15 @@ static int tsx_basic_final_response_test(void) */ static int tsx_basic_provisional_response_test(void) { + unsigned duration; int status; PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST3_BRANCH_ID, - 35, + duration = (tp_flag & PJSIP_TRANSPORT_RELIABLE) ? 1 : 33; + duration += 2; + + status = perform_test(TARGET_URI, FROM_URI, TEST3_BRANCH_ID, duration, &pjsip_options_method, 1, 0, 0); return status; @@ -1320,10 +1362,7 @@ static int tsx_retransmit_last_response_test(const char *title, PJ_LOG(3,(THIS_FILE," %s", title)); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - branch_id, - 5, + status = perform_test(TARGET_URI, FROM_URI, branch_id, 5, &pjsip_options_method, request_cnt, 1000, 1); if (status && status != TEST_TIMEOUT_ERROR) @@ -1357,9 +1396,7 @@ static int tsx_final_response_retransmission_test(void) PJ_LOG(3,(THIS_FILE, " test7: INVITE non-2xx final response retransmission")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST7_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST7_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1368,9 +1405,7 @@ static int tsx_final_response_retransmission_test(void) PJ_LOG(3,(THIS_FILE, " test8: INVITE 2xx final response retransmission")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST8_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST8_BRANCH_ID, 33, /* Test duration must be greater than 32 secs */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1394,9 +1429,7 @@ static int tsx_ack_test(void) PJ_LOG(3,(THIS_FILE, " test9: receiving ACK for non-2xx final response")); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - TEST9_BRANCH_ID, + status = perform_test(TARGET_URI, FROM_URI, TEST9_BRANCH_ID, 20, /* allow 5 retransmissions */ &pjsip_invite_method, 1, 0, 0); if (status != 0) @@ -1443,11 +1476,8 @@ static int tsx_transport_failure_test(void) pjsip_loop_set_failure(loop, 0, NULL); pjsip_loop_set_delay(loop, tests[i].transport_delay); - status = perform_test("sip:129.0.0.1;transport=loop-dgram", - "sip:129.0.0.1;transport=loop-dgram", - tests[i].branch_id, - 0, - &pjsip_invite_method, 1, 0, 1); + status = perform_test(TARGET_URI, FROM_URI, tests[i].branch_id, + 0, &pjsip_invite_method, 1, 0, 1); if (status && status != TEST_TIMEOUT_ERROR) return status; if (!status) { @@ -1494,19 +1524,26 @@ static int tsx_transport_failure_test(void) ** ***************************************************************************** */ -int tsx_uas_test(void) +int tsx_uas_test(struct tsx_test_param *param) { pj_sockaddr_in addr; pj_status_t status; + test_param = param; + tp_flag = pjsip_transport_get_flag_from_type(param->type); + + pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s", + param->port, param->tp_type); + /* Check if loop transport is configured. */ status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM, &addr, sizeof(addr), &loop); if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!")); - return -1; + return -10; } - /* Register modules. */ status = pjsip_endpt_register_module(endpt, &tsx_user); if (status != PJ_SUCCESS) { @@ -1550,42 +1587,67 @@ int tsx_uas_test(void) if (status != 0) return status; - /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state + /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state + * This only applies to non-reliable transports, + * since UAS transaction is destroyed as soon + * as final response is sent for reliable transports. */ - status = tsx_retransmit_last_response_test(TEST6_TITLE, - TEST6_BRANCH_ID, - TEST6_REQUEST_COUNT, - TEST6_STATUS_CODE); - if (status != 0) - return status; + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_retransmit_last_response_test(TEST6_TITLE, + TEST6_BRANCH_ID, + TEST6_REQUEST_COUNT, + TEST6_STATUS_CODE); + if (status != 0) + return status; + } /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test */ - status = tsx_final_response_retransmission_test(); if (status != 0) return status; /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must * cease when ACK is received + * Only applicable for non-reliable transports. */ - status = tsx_ack_test(); - if (status != 0) - return status; + if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) { + status = tsx_ack_test(); + if (status != 0) + return status; + } + /* TEST10_BRANCH_ID: test transport failure in TRYING state. * TEST11_BRANCH_ID: test transport failure in PROCEEDING state. * TEST12_BRANCH_ID: test transport failure in CONNECTED state. * TEST13_BRANCH_ID: test transport failure in CONFIRMED state. */ - status = tsx_transport_failure_test(); - if (status != 0) - return status; + /* Only valid for loop-dgram */ + if (param->type == PJSIP_TRANSPORT_LOOP_DGRAM) { + status = tsx_transport_failure_test(); + if (status != 0) + return status; + } - pjsip_transport_dec_ref(loop); - return 0; + /* Register modules. */ + status = pjsip_endpt_unregister_module(endpt, &tsx_user); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -8; + } + status = pjsip_endpt_unregister_module(endpt, &msg_sender); + if (status != PJ_SUCCESS) { + app_perror(" Error: unable to unregister module", status); + return -9; + } + + if (loop) + pjsip_transport_dec_ref(loop); + + return 0; } diff --git a/pjsip/src/test-pjsip/txdata_test.c b/pjsip/src/test-pjsip/txdata_test.c index d39fad42..a7f0fb0b 100644 --- a/pjsip/src/test-pjsip/txdata_test.c +++ b/pjsip/src/test-pjsip/txdata_test.c @@ -21,11 +21,19 @@ #include <pjsip.h> #include <pjlib.h> -#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) #define THIS_FILE "txdata_test.c" +#define HFIND(msg,h,H) ((pjsip_##h##_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_##H, NULL)) + +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP 10000 +#else +# define LOOP 100000 +#endif + + /* * This tests various core message creation functions. */ @@ -323,6 +331,77 @@ static int core_txdata_test(void) return 0; } + + +/* + * This test demonstrate the bug as reported in: + * http://bugzilla.pjproject.net/show_bug.cgi?id=49 + */ +static int gcc_test() +{ + char msgbuf[512]; + pj_str_t target = pj_str("sip:alice@wonderland:5061;x-param=param%201" + "?X-Hdr-1=Header%201" + "&X-Empty-Hdr="); + pjsip_tx_data *tdata; + pjsip_parser_err_report err_list; + pjsip_msg *msg; + int len; + pj_status_t status; + + PJ_LOG(3,(THIS_FILE, " header param in URI to create request")); + + /* Create request with header param in target URI. */ + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &target, + &target, &target, &target, NULL, -1, + NULL, &tdata); + if (status != 0) { + app_perror(" error: Unable to create request", status); + return -200; + } + + /* Print and parse the request. + * We'll check that header params are not present in + */ + len = pjsip_msg_print(tdata->msg, msgbuf, sizeof(msgbuf)); + if (len < 1) { + PJ_LOG(3,(THIS_FILE, " error: printing message")); + pjsip_tx_data_dec_ref(tdata); + return -250; + } + msgbuf[len] = '\0'; + + PJ_LOG(5,(THIS_FILE, "%d bytes request created:--begin-msg--\n" + "%s\n" + "--end-msg--", len, msgbuf)); + + /* Now parse the message. */ + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); + if (msg == NULL) { + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + + pjsip_tx_data_dec_ref(tdata); + return -255; + } + + pjsip_tx_data_dec_ref(tdata); + return 0; +} + + /* This tests the request creating functions against the following * requirements: * - header params in URI creates header in the request. @@ -345,6 +424,8 @@ static int txdata_test_uri_params(void) pjsip_tx_data *tdata; pjsip_sip_uri *uri; pjsip_param *param; + pjsip_via_hdr *via; + pjsip_parser_err_report err_list; pjsip_msg *msg; int len; pj_status_t status; @@ -360,6 +441,11 @@ static int txdata_test_uri_params(void) return -200; } + /* Fill up the Via header to prevent syntax error on parsing */ + via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL); + via->transport = pj_str("TCP"); + via->sent_by.host = pj_str("127.0.0.1"); + /* Print and parse the request. * We'll check that header params are not present in */ @@ -376,11 +462,25 @@ static int txdata_test_uri_params(void) "--end-msg--", len, msgbuf)); /* Now parse the message. */ - msg = pjsip_parse_msg( tdata->pool, msgbuf, len, NULL); + pj_list_init(&err_list); + msg = pjsip_parse_msg( tdata->pool, msgbuf, len, &err_list); if (msg == NULL) { - app_perror(" error: parsing message message", status); + pjsip_parser_err_report *e; + + PJ_LOG(3,(THIS_FILE, " error: parsing message message")); + + e = err_list.next; + while (e != &err_list) { + PJ_LOG(3,(THIS_FILE, " %s in line %d col %d hname=%.*s", + pj_exception_id_name(e->except_code), + e->line, e->col+1, + (int)e->hname.slen, + e->hname.ptr)); + e = e->next; + } + pjsip_tx_data_dec_ref(tdata); - return -250; + return -256; } /* Check the existence of port, other_param, and header param. @@ -512,18 +612,233 @@ static int txdata_test_uri_params(void) return 0; } + +/* + * create request benchmark + */ +static int create_request_bench(pj_timestamp *p_elapsed) +{ + enum { COUNT = 100 }; + unsigned i, j; + pjsip_tx_data *tdata[COUNT]; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); + pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); + pj_str_t str_contact = str_from; + + elapsed.u64 = 0; + + for (i=0; i<LOOP; i+=COUNT) { + pj_memset(tdata, 0, sizeof(tdata)); + + pj_get_timestamp(&t1); + + for (j=0; j<COUNT; ++j) { + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &tdata[j]); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + goto on_error; + } + } + + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + for (j=0; j<COUNT; ++j) + pjsip_tx_data_dec_ref(tdata[j]); + } + + p_elapsed->u64 = elapsed.u64; + return PJ_SUCCESS; + +on_error: + for (i=0; i<COUNT; ++i) { + if (tdata[i]) + pjsip_tx_data_dec_ref(tdata[i]); + } + return -400; +} + + + +/* + * create response benchmark + */ +static int create_response_bench(pj_timestamp *p_elapsed) +{ + enum { COUNT = 100 }; + unsigned i, j; + pjsip_via_hdr *via; + pjsip_rx_data rdata; + pjsip_tx_data *request; + pjsip_tx_data *tdata[COUNT]; + pj_timestamp t1, t2, elapsed; + pj_status_t status; + + /* Create the request first. */ + pj_str_t str_target = pj_str("sip:someuser@someprovider.com"); + pj_str_t str_from = pj_str("\"Local User\" <sip:localuser@serviceprovider.com>"); + pj_str_t str_to = pj_str("\"Remote User\" <sip:remoteuser@serviceprovider.com>"); + pj_str_t str_contact = str_from; + + status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, + &str_target, &str_from, &str_to, + &str_contact, NULL, -1, NULL, + &request); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + return status; + } + + /* Create several Via headers */ + via = pjsip_via_hdr_create(request->pool); + via->sent_by.host = pj_str("192.168.0.7"); + via->sent_by.port = 5061; + via->transport = pj_str("udp"); + via->rport_param = 0; + via->branch_param = pj_str("012345678901234567890123456789"); + via->recvd_param = pj_str("192.168.0.7"); + pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, pjsip_hdr_clone(request->pool, via)); + pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); + + + /* Create "dummy" rdata from the tdata */ + pj_memset(&rdata, 0, sizeof(pjsip_rx_data)); + rdata.tp_info.pool = request->pool; + rdata.msg_info.msg = request->msg; + rdata.msg_info.from = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.to = pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); + rdata.msg_info.cseq = pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); + rdata.msg_info.cid = pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); + rdata.msg_info.via = via; + + /* + * Now benchmark create_response + */ + elapsed.u64 = 0; + + for (i=0; i<LOOP; i+=COUNT) { + pj_memset(tdata, 0, sizeof(tdata)); + + pj_get_timestamp(&t1); + + for (j=0; j<COUNT; ++j) { + status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]); + if (status != PJ_SUCCESS) { + app_perror(" error: unable to create request", status); + goto on_error; + } + } + + pj_get_timestamp(&t2); + pj_sub_timestamp(&t2, &t1); + pj_add_timestamp(&elapsed, &t2); + + for (j=0; j<COUNT; ++j) + pjsip_tx_data_dec_ref(tdata[j]); + } + + p_elapsed->u64 = elapsed.u64; + pjsip_tx_data_dec_ref(request); + return PJ_SUCCESS; + +on_error: + for (i=0; i<COUNT; ++i) { + if (tdata[i]) + pjsip_tx_data_dec_ref(tdata[i]); + } + return -400; +} + + int txdata_test(void) { + enum { REPEAT = 4 }; + unsigned i, msgs; + pj_timestamp usec[REPEAT], min, freq; int status; + status = pj_get_timestamp_freq(&freq); + if (status != PJ_SUCCESS) + return status; + status = core_txdata_test(); if (status != 0) return status; +#if INCLUDE_GCC_TEST + status = gcc_test(); + if (status != 0) + return status; +#endif status = txdata_test_uri_params(); if (status != 0) return status; + + /* + * Benchmark create_request() + */ + PJ_LOG(3,(THIS_FILE, " benchmarking request creation:")); + for (i=0; i<REPEAT; ++i) { + PJ_LOG(3,(THIS_FILE, " test %d of %d..", + i+1, REPEAT)); + status = create_request_bench(&usec[i]); + if (status != PJ_SUCCESS) + return status; + } + + min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); + for (i=0; i<REPEAT; ++i) { + if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; + } + + msgs = (unsigned)(freq.u64 * LOOP / min.u64); + + PJ_LOG(3,(THIS_FILE, " Requests created at %d requests/sec", msgs)); + + report_ival("create-request-per-sec", + msgs, "msg/sec", + "Number of typical request messages that can be created " + "per second with <tt>pjsip_endpt_create_request()</tt>"); + + + /* + * Benchmark create_response() + */ + PJ_LOG(3,(THIS_FILE, " benchmarking response creation:")); + for (i=0; i<REPEAT; ++i) { + PJ_LOG(3,(THIS_FILE, " test %d of %d..", + i+1, REPEAT)); + status = create_response_bench(&usec[i]); + if (status != PJ_SUCCESS) + return status; + } + + min.u64 = PJ_UINT64(0xFFFFFFFFFFFFFFF); + for (i=0; i<REPEAT; ++i) { + if (usec[i].u64 < min.u64) min.u64 = usec[i].u64; + } + + msgs = (unsigned)(freq.u64 * LOOP / min.u64); + + PJ_LOG(3,(THIS_FILE, " Responses created at %d responses/sec", msgs)); + + report_ival("create-response-per-sec", + msgs, "msg/sec", + "Number of typical response messages that can be created " + "per second with <tt>pjsip_endpt_create_response()</tt>"); + + return 0; } + diff --git a/pjsip/src/test-pjsip/uri_test.c b/pjsip/src/test-pjsip/uri_test.c index a221f4ca..916a30f4 100644 --- a/pjsip/src/test-pjsip/uri_test.c +++ b/pjsip/src/test-pjsip/uri_test.c @@ -32,12 +32,19 @@ #define PARAM_CHAR ALPHANUM MARK "[]/:&+$" #define POOL_SIZE 8000 -#define LOOP_COUNT 10000 +#if defined(PJ_DEBUG) && PJ_DEBUG!=0 +# define LOOP_COUNT 10000 +#else +# define LOOP_COUNT 40000 +#endif #define AVERAGE_URL_LEN 80 #define THREAD_COUNT 4 -static pj_highprec_t parse_len, print_len, cmp_len; -static pj_timestamp parse_time, print_time, cmp_time; +static struct +{ + pj_highprec_t parse_len, print_len, cmp_len; + pj_timestamp parse_time, print_time, cmp_time; +} var; /* URI creator functions. */ @@ -686,7 +693,7 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) /* Parse URI text. */ pj_get_timestamp(&t1); - parse_len = parse_len + entry->len; + var.parse_len = var.parse_len + entry->len; parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0); if (!parsed_uri) { /* Parsing failed. If the entry says that this is expected, then @@ -702,7 +709,7 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&parse_time, &t2); + pj_add_timestamp(&var.parse_time, &t2); /* Create the reference URI. */ ref_uri = entry->creator(pool); @@ -720,10 +727,10 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) s1.ptr[len] = '\0'; s1.slen = len; - print_len = print_len + len; + var.print_len = var.print_len + len; pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&print_time, &t2); + pj_add_timestamp(&var.print_time, &t2); len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE); if (len < 1) { @@ -755,10 +762,10 @@ static pj_status_t do_uri_test(pj_pool_t *pool, struct uri_test *entry) } } - cmp_len = cmp_len + len; + var.cmp_len = var.cmp_len + len; pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); - pj_add_timestamp(&cmp_time, &t2); + pj_add_timestamp(&var.cmp_time, &t2); /* Compare text. */ if (entry->printed) { @@ -785,16 +792,12 @@ on_return: return status; } -int uri_test() + +static int simple_uri_test(void) { - unsigned i, loop; + unsigned i; pj_pool_t *pool; pj_status_t status; - pj_timestamp zero; - pj_time_val elapsed; - pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; - - zero.u32.hi = zero.u32.lo = 0; PJ_LOG(3,(THIS_FILE, " simple test")); pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE); @@ -803,16 +806,31 @@ int uri_test() if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " error %d when testing entry %d", status, i)); - goto on_return; + return status; } } pjsip_endpt_release_pool(endpt, pool); - PJ_LOG(3,(THIS_FILE, " benchmarking...")); - parse_len = print_len = cmp_len = 0; - parse_time.u32.hi = parse_time.u32.lo = 0; - print_time.u32.hi = print_time.u32.lo = 0; - cmp_time.u32.hi = cmp_time.u32.lo = 0; + return 0; +} + +static int uri_benchmark(unsigned *p_parse, unsigned *p_print, unsigned *p_cmp) +{ + unsigned i, loop; + pj_pool_t *pool; + pj_status_t status; + pj_timestamp zero; + pj_time_val elapsed; + pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; + + pj_memset(&var, 0, sizeof(var)); + + zero.u32.hi = zero.u32.lo = 0; + + var.parse_len = var.print_len = var.cmp_len = 0; + var.parse_time.u32.hi = var.parse_time.u32.lo = 0; + var.print_time.u32.hi = var.print_time.u32.lo = 0; + var.cmp_time.u32.hi = var.cmp_time.u32.lo = 0; for (loop=0; loop<LOOP_COUNT; ++loop) { pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE); for (i=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) { @@ -827,55 +845,144 @@ int uri_test() pjsip_endpt_release_pool(endpt, pool); } - kbytes = parse_len; + kbytes = var.parse_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &parse_time); - avg_parse = pj_elapsed_usec(&zero, &parse_time); + elapsed = pj_elapsed_time(&zero, &var.parse_time); + avg_parse = pj_elapsed_usec(&zero, &var.parse_time); pj_highprec_mul(avg_parse, AVERAGE_URL_LEN); - pj_highprec_div(avg_parse, parse_len); + pj_highprec_div(avg_parse, var.parse_len); avg_parse = 1000000 / avg_parse; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls parsed in %d.%03ds (avg=%d urls/sec)", - (unsigned)(parse_len/1000000), (unsigned)kbytes, + (unsigned)(var.parse_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_parse)); - kbytes = print_len; + *p_parse = (unsigned)avg_parse; + + kbytes = var.print_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &print_time); - avg_print = pj_elapsed_usec(&zero, &print_time); + elapsed = pj_elapsed_time(&zero, &var.print_time); + avg_print = pj_elapsed_usec(&zero, &var.print_time); pj_highprec_mul(avg_print, AVERAGE_URL_LEN); - pj_highprec_div(avg_print, parse_len); + pj_highprec_div(avg_print, var.parse_len); avg_print = 1000000 / avg_print; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls printed in %d.%03ds (avg=%d urls/sec)", - (unsigned)(print_len/1000000), (unsigned)kbytes, + (unsigned)(var.print_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_print)); - kbytes = cmp_len; + *p_print = (unsigned)avg_print; + + kbytes = var.cmp_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); - elapsed = pj_elapsed_time(&zero, &cmp_time); - avg_cmp = pj_elapsed_usec(&zero, &cmp_time); + elapsed = pj_elapsed_time(&zero, &var.cmp_time); + avg_cmp = pj_elapsed_usec(&zero, &var.cmp_time); pj_highprec_mul(avg_cmp, AVERAGE_URL_LEN); - pj_highprec_div(avg_cmp, cmp_len); + pj_highprec_div(avg_cmp, var.cmp_len); avg_cmp = 1000000 / avg_cmp; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls compared in %d.%03ds (avg=%d urls/sec)", - (unsigned)(cmp_len/1000000), (unsigned)kbytes, + (unsigned)(var.cmp_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_cmp)); - PJ_LOG(3,(THIS_FILE, " multithreaded test")); - + *p_cmp = (unsigned)avg_cmp; on_return: return status; } + +/*****************************************************************************/ + +int uri_test(void) +{ + enum { COUNT = 4, DETECT=0, PARSE=1, PRINT=2 }; + struct { + unsigned parse; + unsigned print; + unsigned cmp; + } run[COUNT]; + unsigned i, max, avg_len; + char desc[200]; + pj_status_t status; + + status = simple_uri_test(); + if (status != PJ_SUCCESS) + return status; + + for (i=0; i<COUNT; ++i) { + PJ_LOG(3,(THIS_FILE, " benchmarking (%d of %d)...", i+1, COUNT)); + status = uri_benchmark(&run[i].parse, &run[i].print, &run[i].cmp); + if (status != PJ_SUCCESS) + return status; + } + + /* Calculate average URI length */ + for (i=0, avg_len=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) { + avg_len += uri_test_array[i].len; + } + avg_len /= PJ_ARRAY_SIZE(uri_test_array); + + + /* + * Print maximum parse/sec + */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].parse > max) max = run[i].parse; + + PJ_LOG(3,("", " Maximum URI parse/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>parsed</B> with " + "<tt>pjsip_parse_uri()</tt> per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-parse-per-sec", max, "URI/sec", desc); + + /* URI parsing bandwidth */ + report_ival("uri-parse-bandwidth-mb", avg_len*max/1000000, "MB/sec", + "URI parsing bandwidth in megabytes (number of megabytes " + "worth of URI that can be parsed per second)"); + + + /* Print maximum print/sec */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].print > max) max = run[i].print; + + PJ_LOG(3,("", " Maximum URI print/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>printed</B> with " + "<tt>pjsip_uri_print()</tt> per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-print-per-sec", max, "URI/sec", desc); + + /* Print maximum detect/sec */ + for (i=0, max=0; i<COUNT; ++i) + if (run[i].cmp > max) max = run[i].cmp; + + PJ_LOG(3,("", " Maximum URI comparison/sec=%u", max)); + + pj_ansi_sprintf(desc, "Number of SIP/TEL URIs that can be <B>compared</B> with " + "<tt>pjsip_uri_cmp()</tt> per second " + "(tested with %d URI set, with average length of " + "%d chars)", + PJ_ARRAY_SIZE(uri_test_array), avg_len); + + report_ival("uri-cmp-per-sec", max, "URI/sec", desc); + + return PJ_SUCCESS; +} + |