static pj_highprec_t elapsed_usec( const pj_timestamp *start, const pj_timestamp *stop ) { pj_timestamp ts_freq; pj_highprec_t freq, elapsed; if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS) return 0; /* Convert frequency timestamp */ #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 freq = u64tohighprec(ts_freq.u64); #else freq = ts_freq.u32.hi; pj_highprec_mul(freq, U32MAX); freq += ts_freq.u32.lo; #endif /* Avoid division by zero. */ if (freq == 0) freq = 1; /* Get elapsed time in cycles. */ elapsed = get_elapsed(start, stop); /* usec = elapsed * USEC / freq */ pj_highprec_mul(elapsed, USEC); pj_highprec_div(elapsed, freq); return elapsed; }
int echo_srv_common_loop(pj_atomic_t *bytes_counter) { pj_highprec_t last_received, avg_bw, highest_bw; pj_time_val last_print; unsigned count; const char *ioqueue_name; last_received = 0; pj_gettimeofday(&last_print); avg_bw = highest_bw = 0; count = 0; ioqueue_name = pj_ioqueue_name(); for (;;) { pj_highprec_t received, cur_received, bw; unsigned msec; pj_time_val now, duration; pj_thread_sleep(1000); received = cur_received = pj_atomic_get(bytes_counter); cur_received = cur_received - last_received; pj_gettimeofday(&now); duration = now; PJ_TIME_VAL_SUB(duration, last_print); msec = PJ_TIME_VAL_MSEC(duration); bw = cur_received; pj_highprec_mul(bw, 1000); pj_highprec_div(bw, msec); last_print = now; last_received = received; avg_bw = avg_bw + bw; count++; PJ_LOG(3,("", "%s UDP (%d threads): %u KB/s (avg=%u KB/s) %s", ioqueue_name, ECHO_SERVER_MAX_THREADS, (unsigned)(bw / 1000), (unsigned)(avg_bw / count / 1000), (count==20 ? "<ses avg>" : ""))); if (count==20) { if (avg_bw/count > highest_bw) highest_bw = avg_bw/count; count = 0; avg_bw = 0; PJ_LOG(3,("", "Highest average bandwidth=%u KB/s", (unsigned)(highest_bw/1000))); } } PJ_UNREACHED(return 0;) }
static pj_highprec_t get_elapsed( const pj_timestamp *start, const pj_timestamp *stop ) { #if defined(PJ_HAS_INT64) && PJ_HAS_INT64!=0 return u64tohighprec(stop->u64 - start->u64); #else pj_highprec_t elapsed_hi, elapsed_lo; elapsed_hi = stop->u32.hi - start->u32.hi; elapsed_lo = stop->u32.lo - start->u32.lo; /* elapsed_hi = elapsed_hi * U32MAX */ pj_highprec_mul(elapsed_hi, U32MAX); return elapsed_hi + elapsed_lo; #endif }
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) { pj_highprec_t ticks; pj_thread_t *thread = pj_thread_this(); PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG); /* Use high precision calculation to make sure we don't * crop values: * * ticks = HZ * msec / 1000 */ ticks = HZ; pj_highprec_mul(ticks, msec); pj_highprec_div(ticks, 1000); TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks)); interruptible_sleep_on_timeout( &thread->queue, ticks); return PJ_SUCCESS; }
/* Calculate the bandwidth for the specific test configuration. * The test is simple: * - create sockpair_cnt number of producer-consumer socket pair. * - create thread_cnt number of worker threads. * - each producer will send buffer_size bytes data as fast and * as soon as it can. * - each consumer will read buffer_size bytes of data as fast * as it could. * - measure the total bytes received by all consumers during a * period of time. */ static int perform_test(pj_bool_t allow_concur, int sock_type, const char *type_name, unsigned thread_cnt, unsigned sockpair_cnt, pj_size_t buffer_size, pj_size_t *p_bandwidth) { enum { MSEC_DURATION = 5000 }; pj_pool_t *pool; test_item *items; pj_thread_t **thread; pj_ioqueue_t *ioqueue; pj_status_t rc; pj_ioqueue_callback ioqueue_callback; pj_uint32_t total_elapsed_usec, total_received; pj_highprec_t bandwidth; pj_timestamp start, stop; unsigned i; TRACE_((THIS_FILE, " starting test..")); ioqueue_callback.on_read_complete = &on_read_complete; ioqueue_callback.on_write_complete = &on_write_complete; thread_quit_flag = 0; pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); if (!pool) return -10; items = (test_item*) pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item)); thread = (pj_thread_t**) pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*)); TRACE_((THIS_FILE, " creating ioqueue..")); rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create ioqueue", rc); return -15; } rc = pj_ioqueue_set_default_concurrency(ioqueue, allow_concur); if (rc != PJ_SUCCESS) { app_perror("...error: pj_ioqueue_set_default_concurrency()", rc); return -16; } /* Initialize each producer-consumer pair. */ for (i=0; i<sockpair_cnt; ++i) { pj_ssize_t bytes; items[i].ioqueue = ioqueue; items[i].buffer_size = buffer_size; items[i].outgoing_buffer = (char*) pj_pool_alloc(pool, buffer_size); items[i].incoming_buffer = (char*) pj_pool_alloc(pool, buffer_size); items[i].bytes_recv = items[i].bytes_sent = 0; /* randomize outgoing buffer. */ pj_create_random_string(items[i].outgoing_buffer, buffer_size); /* Create socket pair. */ TRACE_((THIS_FILE, " calling socketpair..")); rc = app_socketpair(pj_AF_INET(), sock_type, 0, &items[i].server_fd, &items[i].client_fd); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create socket pair", rc); return -20; } /* Register server socket to ioqueue. */ TRACE_((THIS_FILE, " register(1)..")); rc = pj_ioqueue_register_sock(pool, ioqueue, items[i].server_fd, &items[i], &ioqueue_callback, &items[i].server_key); if (rc != PJ_SUCCESS) { app_perror("...error: registering server socket to ioqueue", rc); return -60; } /* Register client socket to ioqueue. */ TRACE_((THIS_FILE, " register(2)..")); rc = pj_ioqueue_register_sock(pool, ioqueue, items[i].client_fd, &items[i], &ioqueue_callback, &items[i].client_key); if (rc != PJ_SUCCESS) { app_perror("...error: registering server socket to ioqueue", rc); return -70; } /* Start reading. */ TRACE_((THIS_FILE, " pj_ioqueue_recv..")); bytes = items[i].buffer_size; rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op, items[i].incoming_buffer, &bytes, 0); if (rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_recv", rc); return -73; } /* Start writing. */ TRACE_((THIS_FILE, " pj_ioqueue_write..")); bytes = items[i].buffer_size; rc = pj_ioqueue_send(items[i].client_key, &items[i].send_op, items[i].outgoing_buffer, &bytes, 0); if (rc != PJ_SUCCESS && rc != PJ_EPENDING) { app_perror("...error: pj_ioqueue_write", rc); return -76; } items[i].has_pending_send = (rc==PJ_EPENDING); } /* Create the threads. */ for (i=0; i<thread_cnt; ++i) { struct thread_arg *arg; arg = (struct thread_arg*) pj_pool_zalloc(pool, sizeof(*arg)); arg->id = i; arg->ioqueue = ioqueue; arg->counter = 0; rc = pj_thread_create( pool, NULL, &worker_thread, arg, PJ_THREAD_DEFAULT_STACK_SIZE, PJ_THREAD_SUSPENDED, &thread[i] ); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create thread", rc); return -80; } } /* Mark start time. */ rc = pj_get_timestamp(&start); if (rc != PJ_SUCCESS) return -90; /* Start the thread. */ TRACE_((THIS_FILE, " resuming all threads..")); for (i=0; i<thread_cnt; ++i) { rc = pj_thread_resume(thread[i]); if (rc != 0) return -100; } /* Wait for MSEC_DURATION seconds. * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually, * but unfortunately it doesn't work when system doesn't employ * timeslicing for threads. */ TRACE_((THIS_FILE, " wait for few seconds..")); do { pj_thread_sleep(1); /* Mark end time. */ rc = pj_get_timestamp(&stop); if (thread_quit_flag) { TRACE_((THIS_FILE, " transfer limit reached..")); break; } if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) { TRACE_((THIS_FILE, " time limit reached..")); break; } } while (1); /* Terminate all threads. */ TRACE_((THIS_FILE, " terminating all threads..")); thread_quit_flag = 1; for (i=0; i<thread_cnt; ++i) { TRACE_((THIS_FILE, " join thread %d..", i)); pj_thread_join(thread[i]); } /* Close all sockets. */ TRACE_((THIS_FILE, " closing all sockets..")); for (i=0; i<sockpair_cnt; ++i) { pj_ioqueue_unregister(items[i].server_key); pj_ioqueue_unregister(items[i].client_key); } /* Destroy threads */ for (i=0; i<thread_cnt; ++i) { pj_thread_destroy(thread[i]); } /* Destroy ioqueue. */ TRACE_((THIS_FILE, " destroying ioqueue..")); pj_ioqueue_destroy(ioqueue); /* Calculate actual time in usec. */ total_elapsed_usec = pj_elapsed_usec(&start, &stop); /* Calculate total bytes received. */ total_received = 0; for (i=0; i<sockpair_cnt; ++i) { total_received = (pj_uint32_t)items[i].bytes_recv; } /* bandwidth = total_received*1000/total_elapsed_usec */ bandwidth = total_received; pj_highprec_mul(bandwidth, 1000); pj_highprec_div(bandwidth, total_elapsed_usec); *p_bandwidth = (pj_uint32_t)bandwidth; PJ_LOG(3,(THIS_FILE, " %.4s %2d %2d %8d KB/s", type_name, thread_cnt, sockpair_cnt, *p_bandwidth)); /* Done. */ pj_pool_release(pool); TRACE_((THIS_FILE, " done..")); return 0; }
static int uri_benchmark(unsigned *p_parse, unsigned *p_print, unsigned *p_cmp) { unsigned i, loop; pj_status_t status = PJ_SUCCESS; pj_timestamp zero; pj_time_val elapsed; pj_highprec_t avg_parse, avg_print, avg_cmp, kbytes; pj_bzero(&var, 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) { for (i=0; i<PJ_ARRAY_SIZE(uri_test_array); ++i) { pj_pool_t *pool; pool = pjsip_endpt_create_pool(endpt, "", POOL_SIZE, POOL_SIZE); status = do_uri_test(pool, &uri_test_array[i]); pjsip_endpt_release_pool(endpt, pool); if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " error %d when testing entry %d", status, i)); pjsip_endpt_release_pool(endpt, pool); goto on_return; } } } kbytes = var.parse_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); 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, var.parse_len); if (avg_parse == 0) avg_parse = 1; avg_parse = 1000000 / avg_parse; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls parsed in %d.%03ds (avg=%d urls/sec)", (unsigned)(var.parse_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_parse)); *p_parse = (unsigned)avg_parse; kbytes = var.print_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); 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, var.parse_len); if (avg_print == 0) avg_print = 1; avg_print = 1000000 / avg_print; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls printed in %d.%03ds (avg=%d urls/sec)", (unsigned)(var.print_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_print)); *p_print = (unsigned)avg_print; kbytes = var.cmp_len; pj_highprec_mod(kbytes, 1000000); pj_highprec_div(kbytes, 100000); 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, var.cmp_len); if (avg_cmp == 0) avg_cmp = 1; avg_cmp = 1000000 / avg_cmp; PJ_LOG(3,(THIS_FILE, " %u.%u MB of urls compared in %d.%03ds (avg=%d urls/sec)", (unsigned)(var.cmp_len/1000000), (unsigned)kbytes, elapsed.sec, elapsed.msec, (unsigned)avg_cmp)); *p_cmp = (unsigned)avg_cmp; on_return: return status; }
/* * sock_producer_consumer() * * Simple producer-consumer benchmarking. Send loop number of * buf_size size packets as fast as possible. */ static int sock_producer_consumer(int sock_type, unsigned buf_size, unsigned loop, unsigned *p_bandwidth) { pj_sock_t consumer, producer; pj_pool_t *pool; char *outgoing_buffer, *incoming_buffer; pj_timestamp start, stop; unsigned i; pj_highprec_t elapsed, bandwidth; pj_size_t total_received; pj_status_t rc; /* Create pool. */ pool = pj_pool_create(mem, NULL, 4096, 4096, NULL); if (!pool) return -10; /* Create producer-consumer pair. */ rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer); if (rc != PJ_SUCCESS) { app_perror("...error: create socket pair", rc); return -20; } /* Create buffers. */ outgoing_buffer = pj_pool_alloc(pool, buf_size); incoming_buffer = pj_pool_alloc(pool, buf_size); /* Start loop. */ pj_get_timestamp(&start); total_received = 0; for (i=0; i<loop; ++i) { pj_ssize_t sent, part_received, received; pj_time_val delay; sent = buf_size; rc = pj_sock_send(producer, outgoing_buffer, &sent, 0); if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) { app_perror("...error: send()", rc); return -61; } /* Repeat recv() until all data is part_received. * This applies only for non-UDP of course, since for UDP * we would expect all data to be part_received in one packet. */ received = 0; do { part_received = buf_size-received; rc = pj_sock_recv(consumer, incoming_buffer+received, &part_received, 0); if (rc != PJ_SUCCESS) { app_perror("...recv error", rc); return -70; } if (part_received <= 0) { PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!", part_received)); return -73; } if ((pj_size_t)part_received != buf_size-received) { if (sock_type != PJ_SOCK_STREAM) { PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes", buf_size-received, part_received)); return -76; } } received += part_received; } while ((pj_size_t)received < buf_size); total_received += received; /* Stop test if it's been runnign for more than 10 secs. */ pj_get_timestamp(&stop); delay = pj_elapsed_time(&start, &stop); if (delay.sec > 10) break; } /* Stop timer. */ pj_get_timestamp(&stop); elapsed = pj_elapsed_usec(&start, &stop); /* bandwidth = total_received * 1000 / elapsed */ bandwidth = total_received; pj_highprec_mul(bandwidth, 1000); pj_highprec_div(bandwidth, elapsed); *p_bandwidth = (pj_uint32_t)bandwidth; /* Close sockets. */ pj_sock_close(consumer); pj_sock_close(producer); /* Done */ pj_pool_release(pool); return 0; }