aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2010-12-29 00:16:34 +0100
committerAris Adamantiadis <aris@0xbadc0de.be>2010-12-29 00:19:05 +0100
commit530c17e2ef280d3452dd1a5d61d21383d9dec546 (patch)
tree70a1e2ff107ac06672e8aed1c42e3d79152d385f
parent31043334f47b75c5a56a8deccd903f81ac5fd7de (diff)
downloadlibssh-530c17e2ef280d3452dd1a5d61d21383d9dec546.tar.gz
libssh-530c17e2ef280d3452dd1a5d61d21383d9dec546.tar.xz
libssh-530c17e2ef280d3452dd1a5d61d21383d9dec546.zip
First real benchmark : raw SSH speed
-rw-r--r--tests/benchmarks/CMakeLists.txt2
-rw-r--r--tests/benchmarks/bench_raw.c182
-rw-r--r--tests/benchmarks/benchmarks.c40
-rw-r--r--tests/benchmarks/benchmarks.h23
4 files changed, 231 insertions, 16 deletions
diff --git a/tests/benchmarks/CMakeLists.txt b/tests/benchmarks/CMakeLists.txt
index 5b2b808d..02488bd9 100644
--- a/tests/benchmarks/CMakeLists.txt
+++ b/tests/benchmarks/CMakeLists.txt
@@ -1,7 +1,7 @@
project(libssh-benchmarks C)
set(benchmarks_SRCS
- bench_scp.c benchmarks.c latency.c
+ bench_scp.c bench_raw.c benchmarks.c latency.c
)
include_directories(
diff --git a/tests/benchmarks/bench_raw.c b/tests/benchmarks/bench_raw.c
new file mode 100644
index 00000000..c870942a
--- /dev/null
+++ b/tests/benchmarks/bench_raw.c
@@ -0,0 +1,182 @@
+/*
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2010 by Aris Adamantiadis
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "benchmarks.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define PYTHON_PATH "/usr/bin/python"
+
+const char python_eater[]=
+"#!/usr/bin/python\n"
+"import sys\n"
+"print 'go'\n"
+"sys.stdout.flush()\n"
+"toread=XXXXXXXXXX\n"
+"read=0\n"
+"while(read < toread):\n"
+" buffersize=toread-read\n"
+" if(buffersize > 4096):\n"
+" buffersize=4096\n"
+" r=len(sys.stdin.read(buffersize))\n"
+" read+=r\n"
+" if(r<=0):\n"
+" print 'error'\n"
+" exit()\n"
+"print 'done'\n";
+
+static char *get_python_eater(unsigned long bytes){
+ char *eater=malloc(sizeof(python_eater));
+ char *ptr;
+ char buffer[12];
+
+ memcpy(eater,python_eater,sizeof(python_eater));
+ ptr=strstr(eater,"XXXXXXXXXX");
+ if(!ptr){
+ free(eater);
+ return NULL;
+ }
+ sprintf(buffer,"0x%.8lx",bytes);
+ memcpy(ptr,buffer,10);
+ return eater;
+}
+
+/** @internal
+ * @brief uploads a script (python or other) at a specific path on the
+ * remote host
+ * @param[in] session an active SSH session
+ * @param[in] path to copy the file
+ * @param[in] content of the file to copy
+ * @return 0 on success, -1 on error
+ */
+static int upload_script(ssh_session session, const char *path,
+ const char *script){
+ ssh_channel channel;
+ char cmd[128];
+ int err;
+
+ channel=ssh_channel_new(session);
+ if(!channel)
+ goto error;
+ if(ssh_channel_open_session(channel) == SSH_ERROR)
+ goto error;
+ snprintf(cmd,sizeof(cmd),"cat > %s",path);
+ if(ssh_channel_request_exec(channel,cmd) == SSH_ERROR)
+ goto error;
+ err=ssh_channel_write(channel,script,strlen(script));
+ if(err == SSH_ERROR)
+ goto error;
+ if(ssh_channel_send_eof(channel) == SSH_ERROR)
+ goto error;
+ if(ssh_channel_close(channel) == SSH_ERROR)
+ goto error;
+ ssh_channel_free(channel);
+ return 0;
+error:
+ fprintf(stderr,"Error while copying script : %s\n",ssh_get_error(session));
+ return -1;
+}
+
+/** @internal
+ * @brief benchmarks a raw upload (simple upload in a SSH channel) using an
+ * existing SSH session.
+ * @param[in] session Open SSH session
+ * @param[in] args Parsed command line arguments
+ * @param[out] bps The calculated bytes per second obtained via benchmark.
+ * @return 0 on success, -1 on error.
+ */
+int benchmarks_raw_up (ssh_session session, struct argument_s *args,
+ float *bps){
+ unsigned long bytes=0x1000000;
+ char *script=get_python_eater(bytes);
+ char cmd[128];
+ char buffer[1024];
+ int err;
+ ssh_channel channel;
+ struct timestamp_struct ts;
+ float ms=0.0;
+ unsigned long total=0;
+ (void)bps;
+
+ err=upload_script(session,"/tmp/eater.py",script);
+ free(script);
+ if(err<0)
+ return err;
+ channel=ssh_channel_new(session);
+ if(channel == NULL)
+ goto error;
+ if(ssh_channel_open_session(channel)==SSH_ERROR)
+ goto error;
+ snprintf(cmd,sizeof(cmd),"%s /tmp/eater.py", PYTHON_PATH);
+ if(ssh_channel_request_exec(channel,cmd)==SSH_ERROR)
+ goto error;
+ if((err=ssh_channel_read(channel,buffer,sizeof(buffer)-1,0))==SSH_ERROR)
+ goto error;
+ buffer[err]=0;
+ if(!strstr(buffer,"go")){
+ fprintf(stderr,"parse error : %s\n",buffer);
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return -1;
+ }
+ if(args->verbose>0)
+ fprintf(stdout,"Starting upload of %lu bytes now\n",bytes);
+ timestamp_init(&ts);
+ while(total < bytes){
+ unsigned long towrite = bytes - total;
+ int w;
+ if(towrite > 0x1000)
+ towrite = 0x1000;
+ w=ssh_channel_write(channel,buffer,towrite);
+ if(w == SSH_ERROR)
+ goto error;
+ total += w;
+ }
+
+ if(args->verbose>0)
+ fprintf(stdout,"Finished upload, now waiting the ack\n");
+
+ if((err=ssh_channel_read(channel,buffer,sizeof(buffer)-1,0))==SSH_ERROR)
+ goto error;
+ buffer[err]=0;
+ if(!strstr(buffer,"done")){
+ fprintf(stderr,"parse error : %s\n",buffer);
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return -1;
+ }
+ ms=elapsed_time(&ts);
+ *bps=8000 * (float)bytes / ms;
+ if(args->verbose > 0)
+ fprintf(stdout,"Upload took %f ms for %lu bytes, at %f bps\n",ms,
+ bytes,*bps);
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ return 0;
+error:
+ fprintf(stderr,"Error during raw upload : %s\n",ssh_get_error(session));
+ if(channel){
+ ssh_channel_close(channel);
+ ssh_channel_free(channel);
+ }
+ return -1;
+}
diff --git a/tests/benchmarks/benchmarks.c b/tests/benchmarks/benchmarks.c
index 44ddb5d8..e926f920 100644
--- a/tests/benchmarks/benchmarks.c
+++ b/tests/benchmarks/benchmarks.c
@@ -35,28 +35,14 @@ const char *argp_program_bug_address = "Aris Adamantiadis <aris@0xbadc0de.be>";
static char **cmdline;
-#define MAX_HOSTS_CONNECT 20
-
/* Program documentation. */
static char doc[] = "libssh benchmarks";
-enum libssh_benchmarks {
- BENCHMARK_RAW_UPLOAD=1,
- BENCHMARK_NUMBER
-};
const char *libssh_benchmarks_names[]={
"null",
"benchmark_raw_upload"
};
-struct argument_s {
- const char *hosts[MAX_HOSTS_CONNECT];
- char benchmarks[BENCHMARK_NUMBER -1];
- int verbose;
- int nhosts;
- int ntests;
-};
-
/* The options we understand. */
static struct argp_option options[] = {
{
@@ -161,10 +147,27 @@ error:
return NULL;
}
+static char *network_speed(float bps){
+ static char buffer[128];
+ if(bps > 1000*1000*1000){
+ /* Gbps */
+ snprintf(buffer,sizeof(buffer),"%f Gbps",bps/(1000*1000*1000));
+ } else if(bps > 1000*1000){
+ /* Mbps */
+ snprintf(buffer,sizeof(buffer),"%f Mbps",bps/(1000*1000));
+ } else if(bps > 1000){
+ snprintf(buffer,sizeof(buffer),"%f Kbps",bps/1000);
+ } else {
+ snprintf(buffer,sizeof(buffer),"%f bps",bps);
+ }
+ return buffer;
+}
+
static void do_benchmarks(ssh_session session, struct argument_s *arguments,
const char *hostname){
float ping_rtt=0.0;
float ssh_rtt=0.0;
+ float bps=0.0;
int err;
if(arguments->verbose>0)
@@ -177,6 +180,13 @@ static void do_benchmarks(ssh_session session, struct argument_s *arguments,
if(err==0){
fprintf(stdout, "SSH RTT : %f ms\n",ssh_rtt);
}
+ if(arguments->benchmarks[BENCHMARK_RAW_UPLOAD-1]){
+ err=benchmarks_raw_up(session,arguments,&bps);
+ if(err==0){
+ fprintf(stdout, "%s : %s : %s\n",hostname,
+ libssh_benchmarks_names[BENCHMARK_RAW_UPLOAD], network_speed(bps));
+ }
+ }
}
int main(int argc, char **argv){
@@ -187,7 +197,7 @@ int main(int argc, char **argv){
arguments_init(&arguments);
cmdline_parse(argc, argv, &arguments);
if (arguments.nhosts==0){
- fprintf(stderr,"At least one host must be specified");
+ fprintf(stderr,"At least one host (-h) must be specified\n");
return EXIT_FAILURE;
}
if (arguments.ntests==0){
diff --git a/tests/benchmarks/benchmarks.h b/tests/benchmarks/benchmarks.h
index e9979f96..065625ed 100644
--- a/tests/benchmarks/benchmarks.h
+++ b/tests/benchmarks/benchmarks.h
@@ -24,6 +24,24 @@
#include <libssh/libssh.h>
+/* benchmarks.c */
+
+/* maximum number of parallel hosts that may be checked */
+#define MAX_HOSTS_CONNECT 20
+
+enum libssh_benchmarks {
+ BENCHMARK_RAW_UPLOAD=1,
+ BENCHMARK_NUMBER
+};
+
+struct argument_s {
+ const char *hosts[MAX_HOSTS_CONNECT];
+ char benchmarks[BENCHMARK_NUMBER -1];
+ int verbose;
+ int nhosts;
+ int ntests;
+};
+
/* latency.c */
struct timestamp_struct {
@@ -36,4 +54,9 @@ int benchmarks_ssh_latency (ssh_session session, float *average);
void timestamp_init(struct timestamp_struct *ts);
float elapsed_time(struct timestamp_struct *ts);
+/* bench_raw.c */
+
+int benchmarks_raw_up (ssh_session session, struct argument_s *args,
+ float *bps);
+
#endif /* BENCHMARKS_H_ */