Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
2482dd7f
Commit
2482dd7f
authored
Jul 13, 2015
by
Nora Shoemaker
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding -r and -C options to h2load
parent
1940413e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
183 additions
and
34 deletions
+183
-34
src/h2load.cc
src/h2load.cc
+170
-34
src/h2load.h
src/h2load.h
+13
-0
No files found.
src/h2load.cc
View file @
2482dd7f
...
...
@@ -75,7 +75,8 @@ Config::Config()
:
data_length
(
-
1
),
addrs
(
nullptr
),
nreqs
(
1
),
nclients
(
1
),
nthreads
(
1
),
max_concurrent_streams
(
-
1
),
window_bits
(
30
),
connection_window_bits
(
30
),
no_tls_proto
(
PROTO_HTTP2
),
data_fd
(
-
1
),
port
(
0
),
default_port
(
0
),
verbose
(
false
)
{}
verbose
(
false
),
nconns
(
0
),
rate
(
0
),
current_worker
(
0
)
{}
Config
::~
Config
()
{
freeaddrinfo
(
addrs
);
...
...
@@ -85,6 +86,10 @@ Config::~Config() {
}
}
bool
Config
::
is_rate_mode
()
{
return
(
this
->
rate
!=
0
);
}
Config
config
;
namespace
{
...
...
@@ -261,7 +266,7 @@ void Client::process_abandoned_streams() {
}
void
Client
::
report_progress
()
{
if
(
worker
->
id
==
0
&&
if
(
!
worker
->
config
->
is_rate_mode
()
&&
worker
->
id
==
0
&&
worker
->
stats
.
req_done
%
worker
->
progress_interval
==
0
)
{
std
::
cout
<<
"progress: "
<<
worker
->
stats
.
req_done
*
100
/
worker
->
stats
.
req_todo
...
...
@@ -962,6 +967,33 @@ std::vector<std::string> read_uri_from_file(std::istream &infile) {
}
}
// namespace
namespace
{
// Called every second when rate mode is being used
void
second_timeout_cb
(
EV_P_
ev_timer
*
w
,
int
revents
)
{
auto
config
=
static_cast
<
Config
*>
(
w
->
data
);
auto
nclients_per_worker
=
config
->
rate
;
auto
nreqs_per_worker
=
config
->
max_concurrent_streams
*
config
->
rate
;
if
(
config
->
current_worker
>=
std
::
max
(
0.
,
(
config
->
seconds
-
1.
)))
{
nclients_per_worker
=
config
->
rate
+
config
->
conns_remainder
;
nreqs_per_worker
=
(
int
)
config
->
max_concurrent_streams
*
(
config
->
rate
+
config
->
conns_remainder
);
ev_timer_stop
(
config
->
rate_loop
,
w
);
}
config
->
workers
.
push_back
(
make_unique
<
Worker
>
(
config
->
current_worker
,
config
->
ssl_ctx
,
nreqs_per_worker
,
nclients_per_worker
,
config
));
config
->
current_worker
++
;
config
->
workers
.
back
()
->
run
();
}
}
// namespace
namespace
{
void
print_version
(
std
::
ostream
&
out
)
{
out
<<
"h2load nghttp2/"
NGHTTP2_VERSION
<<
std
::
endl
;
...
...
@@ -1027,6 +1059,7 @@ Options:
-p, --no-tls-proto=<PROTOID>
Specify ALPN identifier of the protocol to be used when
accessing http URI without SSL/TLS.)"
;
#ifdef HAVE_SPDYLAY
out
<<
R"(
Available protocols: spdy/2, spdy/3, spdy/3.1 and )"
;
...
...
@@ -1039,6 +1072,24 @@ Options:
-d, --data=<FILE>
Post FILE to server. The request method is changed to
POST.
-r, --rate=<N>
Specified the fixed rate at which connections are
created. The rate must be a positive integer,
representing the number of connections to be made per
second. When the rate is 0, the program will run as it
normally does, creating connections at whatever variable
rate it wants. The default value for this option is 0.
-C, --num-conns=<N>
Specifies the total number of connections to create. The
total number of connections must be a positive integer.
On each connection, '-m' requests are made. The test
stops once as soon as the N connections have either
completed or failed. When the number of connections is
0, the program will run as it normally does, creating as
many connections as it needs in order to make the '-n'
requests specified. The defauly value for this option is
0. The '-n' option is not required if the '-C' option
is being used.
-v, --verbose
Output debug information.
--version Display version information and exit.
...
...
@@ -1073,10 +1124,12 @@ int main(int argc, char **argv) {
{
"help"
,
no_argument
,
nullptr
,
'h'
},
{
"version"
,
no_argument
,
&
flag
,
1
},
{
"ciphers"
,
required_argument
,
&
flag
,
2
},
{
"rate"
,
required_argument
,
nullptr
,
'r'
},
{
"num-conns"
,
required_argument
,
nullptr
,
'C'
},
{
nullptr
,
0
,
nullptr
,
0
}};
int
option_index
=
0
;
auto
c
=
getopt_long
(
argc
,
argv
,
"hvW:c:d:m:n:p:t:w:H:i:
"
,
long_options
,
&
option_index
);
auto
c
=
getopt_long
(
argc
,
argv
,
"hvW:c:d:m:n:p:t:w:H:i:
r:C:"
,
long_options
,
&
option_index
);
if
(
c
==
-
1
)
{
break
;
}
...
...
@@ -1170,6 +1223,24 @@ int main(int argc, char **argv) {
exit
(
EXIT_FAILURE
);
}
break
;
case
'r'
:
config
.
rate
=
strtoul
(
optarg
,
nullptr
,
10
);
if
(
config
.
rate
<=
0
)
{
std
::
cerr
<<
"-r: the rate at which connections are made "
<<
"must be positive."
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
break
;
case
'C'
:
config
.
nconns
=
strtoul
(
optarg
,
nullptr
,
10
);
if
(
config
.
nconns
<=
0
)
{
std
::
cerr
<<
"-C: the total number of connections made "
<<
"must be positive."
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
break
;
case
'v'
:
config
.
verbose
=
true
;
break
;
...
...
@@ -1238,6 +1309,25 @@ int main(int argc, char **argv) {
<<
"cores."
<<
std
::
endl
;
}
if
(
config
.
nconns
<
0
)
{
std
::
cerr
<<
"-C: the total number of connections made "
<<
"cannot be negative."
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
if
(
config
.
rate
<
0
)
{
std
::
cerr
<<
"-r: the rate at which connections are made "
<<
"cannot be negative."
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
if
(
config
.
rate
!=
0
&&
config
.
nthreads
!=
1
)
{
std
::
cerr
<<
"-r, -t: warning: the -t option will be ignored when the -r "
<<
"option is in use."
<<
std
::
endl
;
}
if
(
!
datafile
.
empty
())
{
config
.
data_fd
=
open
(
datafile
.
c_str
(),
O_RDONLY
|
O_BINARY
);
if
(
config
.
data_fd
==
-
1
)
{
...
...
@@ -1405,46 +1495,92 @@ int main(int argc, char **argv) {
auto
start
=
std
::
chrono
::
steady_clock
::
now
();
std
::
vector
<
std
::
unique_ptr
<
Worker
>>
workers
;
workers
.
reserve
(
config
.
nthreads
);
// if not in rate mode, continue making workers and clients normally
if
(
!
config
.
is_rate_mode
())
{
config
.
workers
.
reserve
(
config
.
nthreads
);
#ifndef NOTHREADS
std
::
vector
<
std
::
future
<
void
>>
futures
;
for
(
size_t
i
=
0
;
i
<
config
.
nthreads
-
1
;
++
i
)
{
auto
nreqs
=
nreqs_per_thread
+
(
nreqs_rem
--
>
0
);
auto
nclients
=
nclients_per_thread
+
(
nclients_rem
--
>
0
);
std
::
cout
<<
"spawning thread #"
<<
i
<<
": "
<<
nclients
<<
" concurrent clients, "
<<
nreqs
<<
" total requests"
<<
std
::
endl
;
workers
.
push_back
(
make_unique
<
Worker
>
(
i
,
ssl_ctx
,
nreqs
,
nclients
,
&
config
));
auto
&
worker
=
workers
.
back
();
futures
.
push_back
(
std
::
async
(
std
::
launch
::
async
,
[
&
worker
]()
{
worker
->
run
();
}));
}
std
::
vector
<
std
::
future
<
void
>>
futures
;
for
(
size_t
i
=
0
;
i
<
config
.
nthreads
-
1
;
++
i
)
{
auto
nreqs
=
nreqs_per_thread
+
(
nreqs_rem
--
>
0
);
auto
nclients
=
nclients_per_thread
+
(
nclients_rem
--
>
0
);
std
::
cout
<<
"spawning thread #"
<<
i
<<
": "
<<
nclients
<<
" concurrent clients, "
<<
nreqs
<<
" total requests"
<<
std
::
endl
;
config
.
workers
.
push_back
(
make_unique
<
Worker
>
(
i
,
ssl_ctx
,
nreqs
,
nclients
,
&
config
));
auto
&
worker
=
config
.
workers
.
back
();
futures
.
push_back
(
std
::
async
(
std
::
launch
::
async
,
[
&
worker
]()
{
worker
->
run
();
}));
}
#endif // NOTHREADS
auto
nreqs_last
=
nreqs_per_thread
+
(
nreqs_rem
--
>
0
);
auto
nclients_last
=
nclients_per_thread
+
(
nclients_rem
--
>
0
);
std
::
cout
<<
"spawning thread #"
<<
(
config
.
nthreads
-
1
)
<<
": "
<<
nclients_last
<<
" concurrent clients, "
<<
nreqs_last
<<
" total requests"
<<
std
::
endl
;
workers
.
push_back
(
make_unique
<
Worker
>
(
config
.
nthreads
-
1
,
ssl_ctx
,
nreqs_last
,
nclients_last
,
&
config
));
workers
.
back
()
->
run
();
auto
nreqs_last
=
nreqs_per_thread
+
(
nreqs_rem
--
>
0
);
auto
nclients_last
=
nclients_per_thread
+
(
nclients_rem
--
>
0
);
std
::
cout
<<
"spawning thread #"
<<
(
config
.
nthreads
-
1
)
<<
": "
<<
nclients_last
<<
" concurrent clients, "
<<
nreqs_last
<<
" total requests"
<<
std
::
endl
;
config
.
workers
.
push_back
(
make_unique
<
Worker
>
(
config
.
nthreads
-
1
,
ssl_ctx
,
nreqs_last
,
nclients_last
,
&
config
));
config
.
workers
.
back
()
->
run
();
#ifndef NOTHREADS
for
(
auto
&
fut
:
futures
)
{
fut
.
get
();
}
for
(
auto
&
fut
:
futures
)
{
fut
.
get
();
}
#endif // NOTHREADS
}
//!config.is_rate_mode()
// if in rate mode, create a new worker each second
else
{
// set various config values
config
.
seconds
=
std
::
min
(
n_time
,
c_time
);
if
((
int
)
config
.
nreqs
<
config
.
nconns
)
{
config
.
seconds
=
c_time
;
config
.
workers
.
reserve
(
config
.
seconds
);
}
else
if
(
config
.
nconns
==
0
)
{
config
.
seconds
=
n_time
;
}
else
{
config
.
workers
.
reserve
(
config
.
seconds
);
}
config
.
conns_remainder
=
config
.
nconns
%
config
.
rate
;
// config.seconds must be positive or else an exception is thrown
if
(
config
.
seconds
<=
0
)
{
std
::
cerr
<<
"Test cannot be run with current option values."
<<
" Please look at documentation for -r option for"
<<
" more information."
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
config
.
current_worker
=
0
;
config
.
ssl_ctx
=
ssl_ctx
;
// create timer that will go off every second
ev_timer
timeout_watcher
;
// create loop for running the timer
struct
ev_loop
*
rate_loop
=
EV_DEFAULT
;
config
.
rate_loop
=
rate_loop
;
// giving the second_timeout_cb access to config
timeout_watcher
.
data
=
&
config
;
ev_init
(
&
timeout_watcher
,
second_timeout_cb
);
timeout_watcher
.
repeat
=
1.
;
ev_timer_again
(
rate_loop
,
&
timeout_watcher
);
ev_run
(
rate_loop
,
0
);
}
// end rate mode section
auto
end
=
std
::
chrono
::
steady_clock
::
now
();
auto
duration
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
end
-
start
);
Stats
stats
(
0
);
for
(
const
auto
&
w
:
workers
)
{
for
(
const
auto
&
w
:
config
.
workers
)
{
const
auto
&
s
=
w
->
stats
;
stats
.
req_todo
+=
s
.
req_todo
;
...
...
@@ -1463,7 +1599,7 @@ int main(int argc, char **argv) {
}
}
auto
ts
=
process_time_stats
(
workers
);
auto
ts
=
process_time_stats
(
config
.
workers
);
// Requests which have not been issued due to connection errors, are
// counted towards req_failed and req_error.
...
...
@@ -1476,7 +1612,7 @@ int main(int argc, char **argv) {
//
// [1] https://github.com/lighttpd/weighttp
// [2] https://github.com/wg/wrk
size_t
rps
=
0
;
double
rps
=
0
;
int64_t
bps
=
0
;
if
(
duration
.
count
()
>
0
)
{
auto
secd
=
static_cast
<
double
>
(
duration
.
count
())
/
(
1000
*
1000
);
...
...
src/h2load.h
View file @
2482dd7f
...
...
@@ -76,6 +76,10 @@ struct Config {
ssize_t
max_concurrent_streams
;
size_t
window_bits
;
size_t
connection_window_bits
;
// rate at which connections should be made
ssize_t
rate
;
// number of connections made
ssize_t
nconns
;
enum
{
PROTO_HTTP2
,
PROTO_SPDY2
,
PROTO_SPDY3
,
PROTO_SPDY3_1
}
no_tls_proto
;
// file descriptor for upload data
int
data_fd
;
...
...
@@ -83,8 +87,17 @@ struct Config {
uint16_t
default_port
;
bool
verbose
;
ssize_t
current_worker
;
std
::
vector
<
std
::
unique_ptr
<
Worker
>>
workers
;
SSL_CTX
*
ssl_ctx
;
struct
ev_loop
*
rate_loop
;
ssize_t
seconds
;
ssize_t
conns_remainder
;
Config
();
~
Config
();
bool
is_rate_mode
();
};
struct
RequestStat
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment