Navigation Menu

Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
bench: add thread pool I/O benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
bnoordhuis committed Jun 21, 2012
1 parent da59427 commit 5dc024f
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 0 deletions.
164 changes: 164 additions & 0 deletions test/benchmark-fs-stat.c
@@ -0,0 +1,164 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "task.h"
#include "uv.h"

#include <stdio.h>
#include <stdlib.h>

#define NUM_SYNC_REQS (10 * 1e6)
#define NUM_ASYNC_REQS (1 * 1e6)
#define MAX_CONCURRENT_REQS 32

#define sync_stat(req, path) \
do { \
uv_fs_stat(uv_default_loop(), (req), (path), NULL); \
uv_fs_req_cleanup((req)); \
} \
while (0)

struct async_req {
const char* path;
uv_fs_t fs_req;
int* count;
};


static const char* fmt(double d) {
uint64_t v;
char* p;

p = (char *) calloc(1, 32) + 31; /* leaks memory */
v = d;

#if 0 /* works but we don't care about fractional precision */
if (d - v >= 0.01) {
*--p = '0' + (uint64_t) (d * 100) % 10;
*--p = '0' + (uint64_t) (d * 10) % 10;
*--p = '.';
}
#endif

if (v == 0)
*--p = '0';

while (v) {
if (v) *--p = '0' + (v % 10), v /= 10;
if (v) *--p = '0' + (v % 10), v /= 10;
if (v) *--p = '0' + (v % 10), v /= 10;
if (v) *--p = ',';
}

return p;
}


static void warmup(const char* path) {
uv_fs_t reqs[MAX_CONCURRENT_REQS];
int i;

/* warm up the thread pool */
for (i = 0; i < ARRAY_SIZE(reqs); i++)
uv_fs_stat(uv_default_loop(), reqs + i, path, uv_fs_req_cleanup);

uv_run(uv_default_loop());

/* warm up the OS dirent cache */
for (i = 0; i < 16; i++)
sync_stat(reqs + 0, path);
}


static void sync_bench(const char* path) {
uint64_t before;
uint64_t after;
uv_fs_t req;
int i;

/* do the sync benchmark */
before = uv_hrtime();

for (i = 0; i < NUM_SYNC_REQS; i++)
sync_stat(&req, path);

after = uv_hrtime();

printf("%s stats (sync): %.2fs (%s/s)\n",
fmt(1.0 * NUM_SYNC_REQS),
(after - before) / 1e9,
fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9)));
fflush(stdout);
}


static void stat_cb(uv_fs_t* fs_req) {
struct async_req* req = container_of(fs_req, struct async_req, fs_req);
uv_fs_req_cleanup(&req->fs_req);
if (*req->count == 0) return;
uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
(*req->count)--;
}


static void async_bench(const char* path) {
struct async_req reqs[MAX_CONCURRENT_REQS];
struct async_req* req;
uint64_t before;
uint64_t after;
int count;
int i;

for (i = 1; i <= MAX_CONCURRENT_REQS; i++) {
count = NUM_ASYNC_REQS;

for (req = reqs; req < reqs + i; req++) {
req->path = path;
req->count = &count;
uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
}

before = uv_hrtime();
uv_run(uv_default_loop());
after = uv_hrtime();

printf("%s stats (%d concurrent): %.2fs (%s/s)\n",
fmt(1.0 * NUM_ASYNC_REQS),
i,
(after - before) / 1e9,
fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9)));
fflush(stdout);
}
}


/* This benchmark aims to measure the overhead of doing I/O syscalls from
* the thread pool. The stat() syscall was chosen because its results are
* easy for the operating system to cache, taking the actual I/O overhead
* out of the equation.
*/
BENCHMARK_IMPL(fs_stat) {
const char path[] = ".";
warmup(path);
sync_bench(path);
async_bench(path);
return 0;
}
3 changes: 3 additions & 0 deletions test/benchmark-list.h
Expand Up @@ -44,6 +44,7 @@ BENCHMARK_DECLARE (udp_packet_storm_100v1000)
BENCHMARK_DECLARE (udp_packet_storm_1000v1000)
BENCHMARK_DECLARE (gethostbyname)
BENCHMARK_DECLARE (getaddrinfo)
BENCHMARK_DECLARE (fs_stat)
BENCHMARK_DECLARE (spawn)
BENCHMARK_DECLARE (thread_create)
BENCHMARK_DECLARE (million_timers)
Expand Down Expand Up @@ -105,6 +106,8 @@ TASK_LIST_START

BENCHMARK_ENTRY (getaddrinfo)

BENCHMARK_ENTRY (fs_stat)

BENCHMARK_ENTRY (spawn)
BENCHMARK_ENTRY (thread_create)
BENCHMARK_ENTRY (million_timers)
Expand Down
1 change: 1 addition & 0 deletions uv.gyp
Expand Up @@ -404,6 +404,7 @@
'dependencies': [ 'uv' ],
'sources': [
'test/benchmark-ares.c',
'test/benchmark-fs-stat.c',
'test/benchmark-getaddrinfo.c',
'test/benchmark-list.h',
'test/benchmark-loop-count.c',
Expand Down

0 comments on commit 5dc024f

Please sign in to comment.