mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-08-07 08:02:55 +03:00
First real benchmark : raw SSH speed
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
project(libssh-benchmarks C)
|
project(libssh-benchmarks C)
|
||||||
|
|
||||||
set(benchmarks_SRCS
|
set(benchmarks_SRCS
|
||||||
bench_scp.c benchmarks.c latency.c
|
bench_scp.c bench_raw.c benchmarks.c latency.c
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
|
182
tests/benchmarks/bench_raw.c
Normal file
182
tests/benchmarks/bench_raw.c
Normal file
@@ -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;
|
||||||
|
}
|
@@ -35,28 +35,14 @@ const char *argp_program_bug_address = "Aris Adamantiadis <aris@0xbadc0de.be>";
|
|||||||
|
|
||||||
static char **cmdline;
|
static char **cmdline;
|
||||||
|
|
||||||
#define MAX_HOSTS_CONNECT 20
|
|
||||||
|
|
||||||
/* Program documentation. */
|
/* Program documentation. */
|
||||||
static char doc[] = "libssh benchmarks";
|
static char doc[] = "libssh benchmarks";
|
||||||
enum libssh_benchmarks {
|
|
||||||
BENCHMARK_RAW_UPLOAD=1,
|
|
||||||
BENCHMARK_NUMBER
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *libssh_benchmarks_names[]={
|
const char *libssh_benchmarks_names[]={
|
||||||
"null",
|
"null",
|
||||||
"benchmark_raw_upload"
|
"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. */
|
/* The options we understand. */
|
||||||
static struct argp_option options[] = {
|
static struct argp_option options[] = {
|
||||||
{
|
{
|
||||||
@@ -161,10 +147,27 @@ error:
|
|||||||
return NULL;
|
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,
|
static void do_benchmarks(ssh_session session, struct argument_s *arguments,
|
||||||
const char *hostname){
|
const char *hostname){
|
||||||
float ping_rtt=0.0;
|
float ping_rtt=0.0;
|
||||||
float ssh_rtt=0.0;
|
float ssh_rtt=0.0;
|
||||||
|
float bps=0.0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if(arguments->verbose>0)
|
if(arguments->verbose>0)
|
||||||
@@ -177,6 +180,13 @@ static void do_benchmarks(ssh_session session, struct argument_s *arguments,
|
|||||||
if(err==0){
|
if(err==0){
|
||||||
fprintf(stdout, "SSH RTT : %f ms\n",ssh_rtt);
|
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){
|
int main(int argc, char **argv){
|
||||||
@@ -187,7 +197,7 @@ int main(int argc, char **argv){
|
|||||||
arguments_init(&arguments);
|
arguments_init(&arguments);
|
||||||
cmdline_parse(argc, argv, &arguments);
|
cmdline_parse(argc, argv, &arguments);
|
||||||
if (arguments.nhosts==0){
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (arguments.ntests==0){
|
if (arguments.ntests==0){
|
||||||
|
@@ -24,6 +24,24 @@
|
|||||||
|
|
||||||
#include <libssh/libssh.h>
|
#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 */
|
/* latency.c */
|
||||||
|
|
||||||
struct timestamp_struct {
|
struct timestamp_struct {
|
||||||
@@ -36,4 +54,9 @@ int benchmarks_ssh_latency (ssh_session session, float *average);
|
|||||||
void timestamp_init(struct timestamp_struct *ts);
|
void timestamp_init(struct timestamp_struct *ts);
|
||||||
float elapsed_time(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_ */
|
#endif /* BENCHMARKS_H_ */
|
||||||
|
Reference in New Issue
Block a user