|
|
|
@ -0,0 +1,659 @@
|
|
|
|
|
/*
|
|
|
|
|
* \brief File system stress tester
|
|
|
|
|
* \author Emery Hemingway
|
|
|
|
|
* \date 2015-08-29
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2015 Genode Labs GmbH
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This test populates the VFS as follows:
|
|
|
|
|
*
|
|
|
|
|
* A directory is created at root for each thread with
|
|
|
|
|
* sequential names. For each of these directories, a
|
|
|
|
|
* subtree is generated until the maximum path depth
|
|
|
|
|
* is reached at each branch. The subtree is layed out
|
|
|
|
|
* like this:
|
|
|
|
|
*
|
|
|
|
|
* a
|
|
|
|
|
* |\
|
|
|
|
|
* a b
|
|
|
|
|
* |\ \
|
|
|
|
|
* a b b
|
|
|
|
|
* |\ \ \
|
|
|
|
|
* a b b b
|
|
|
|
|
* |\ \ \ \
|
|
|
|
|
* . . . . .
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
|
#include <vfs/file_system_factory.h>
|
|
|
|
|
#include <vfs/dir_file_system.h>
|
|
|
|
|
#include <timer_session/connection.h>
|
|
|
|
|
#include <base/process.h>
|
|
|
|
|
#include <os/config.h>
|
|
|
|
|
#include <base/printf.h>
|
|
|
|
|
#include <base/snprintf.h>
|
|
|
|
|
#include <base/exception.h>
|
|
|
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
inline void assert_mkdir(Vfs::Directory_service::Mkdir_result r)
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::Directory_service::Mkdir_result Result;
|
|
|
|
|
|
|
|
|
|
switch (r) {
|
|
|
|
|
case Result::MKDIR_OK: return;
|
|
|
|
|
case Result::MKDIR_ERR_EXISTS:
|
|
|
|
|
PERR("MKDIR_ERR_EXISTS"); break;
|
|
|
|
|
case Result::MKDIR_ERR_NO_ENTRY:
|
|
|
|
|
PERR("MKDIR_ERR_NO_ENTRY"); break;
|
|
|
|
|
case Result::MKDIR_ERR_NO_SPACE:
|
|
|
|
|
PERR("MKDIR_ERR_NO_SPACE"); break;
|
|
|
|
|
case Result::MKDIR_ERR_NO_PERM:
|
|
|
|
|
PERR("MKDIR_ERR_NO_PERM"); break;
|
|
|
|
|
case Result::MKDIR_ERR_NAME_TOO_LONG:
|
|
|
|
|
PERR("MKDIR_ERR_NAME_TOO_LONG"); break;
|
|
|
|
|
}
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void assert_open(Vfs::Directory_service::Open_result r)
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::Directory_service::Open_result Result;
|
|
|
|
|
switch (r) {
|
|
|
|
|
case Result::OPEN_OK: return;
|
|
|
|
|
case Result::OPEN_ERR_NAME_TOO_LONG:
|
|
|
|
|
PERR("OPEN_ERR_NAME_TOO_LONG"); break;
|
|
|
|
|
case Result::OPEN_ERR_UNACCESSIBLE:
|
|
|
|
|
PERR("OPEN_ERR_UNACCESSIBLE"); break;
|
|
|
|
|
case Result::OPEN_ERR_NO_SPACE:
|
|
|
|
|
PERR("OPEN_ERR_NO_SPACE"); break;
|
|
|
|
|
case Result::OPEN_ERR_NO_PERM:
|
|
|
|
|
PERR("OPEN_ERR_NO_PERM"); break;
|
|
|
|
|
case Result::OPEN_ERR_EXISTS:
|
|
|
|
|
PERR("OPEN_ERR_EXISTS"); break;
|
|
|
|
|
}
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void assert_write(Vfs::File_io_service::Write_result r)
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::File_io_service::Write_result Result;
|
|
|
|
|
switch (r) {
|
|
|
|
|
case Result::WRITE_OK: return;
|
|
|
|
|
case Result::WRITE_ERR_AGAIN:
|
|
|
|
|
PERR("WRITE_ERR_AGAIN"); break;
|
|
|
|
|
case Result::WRITE_ERR_WOULD_BLOCK:
|
|
|
|
|
PERR("WRITE_ERR_WOULD_BLOCK"); break;
|
|
|
|
|
case Result::WRITE_ERR_INVALID:
|
|
|
|
|
PERR("WRITE_ERR_INVALID"); break;
|
|
|
|
|
case Result::WRITE_ERR_IO:
|
|
|
|
|
PERR("WRITE_ERR_IO"); break;
|
|
|
|
|
case Result::WRITE_ERR_INTERRUPT:
|
|
|
|
|
PERR("WRITE_ERR_INTERRUPT"); break;
|
|
|
|
|
}
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void assert_read(Vfs::File_io_service::Read_result r)
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::File_io_service::Read_result Result;
|
|
|
|
|
switch (r) {
|
|
|
|
|
case Result::READ_OK: return;
|
|
|
|
|
case Result::READ_ERR_AGAIN:
|
|
|
|
|
PERR("READ_ERR_AGAIN"); break;
|
|
|
|
|
case Result::READ_ERR_WOULD_BLOCK:
|
|
|
|
|
PERR("READ_ERR_WOULD_BLOCK"); break;
|
|
|
|
|
case Result::READ_ERR_INVALID:
|
|
|
|
|
PERR("READ_ERR_INVALID"); break;
|
|
|
|
|
case Result::READ_ERR_IO:
|
|
|
|
|
PERR("READ_ERR_IO"); break;
|
|
|
|
|
case Result::READ_ERR_INTERRUPT:
|
|
|
|
|
PERR("READ_ERR_INTERRUPT"); break;
|
|
|
|
|
}
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void assert_unlink(Vfs::Directory_service::Unlink_result r)
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::Directory_service::Unlink_result Result;
|
|
|
|
|
switch (r) {
|
|
|
|
|
case Result::UNLINK_OK: return;
|
|
|
|
|
case Result::UNLINK_ERR_NO_ENTRY:
|
|
|
|
|
PERR("UNLINK_ERR_NO_ENTRY"); break;
|
|
|
|
|
case Result::UNLINK_ERR_NO_PERM:
|
|
|
|
|
PERR("UNLINK_ERR_NO_PERM"); break;
|
|
|
|
|
}
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int MAX_DEPTH;
|
|
|
|
|
|
|
|
|
|
typedef Genode::Path<Vfs::MAX_PATH_LEN> Path;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Stress_thread : public Genode::Thread<4*1024*sizeof(Genode::addr_t)>
|
|
|
|
|
{
|
|
|
|
|
::Path path;
|
|
|
|
|
Vfs::file_size count;
|
|
|
|
|
Vfs::File_system &vfs;
|
|
|
|
|
|
|
|
|
|
Stress_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Thread(parent), path(parent), count(0), vfs(vfs) { }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Mkdir_thread : public Stress_thread
|
|
|
|
|
{
|
|
|
|
|
Mkdir_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Stress_thread(vfs, parent) { start(); }
|
|
|
|
|
|
|
|
|
|
void mkdir_b(int depth)
|
|
|
|
|
{
|
|
|
|
|
if (++depth > MAX_DEPTH) return;
|
|
|
|
|
|
|
|
|
|
path.append("/b");
|
|
|
|
|
assert_mkdir(vfs.mkdir(path.base(), 0));
|
|
|
|
|
++count;
|
|
|
|
|
mkdir_b(depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mkdir_a(int depth)
|
|
|
|
|
{
|
|
|
|
|
if (++depth > MAX_DEPTH) return;
|
|
|
|
|
|
|
|
|
|
size_t path_len = strlen(path.base());
|
|
|
|
|
|
|
|
|
|
path.append("/b");
|
|
|
|
|
assert_mkdir(vfs.mkdir(path.base(), 0));
|
|
|
|
|
++count;
|
|
|
|
|
mkdir_b(depth);
|
|
|
|
|
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
|
|
|
|
|
path.append("/a");
|
|
|
|
|
assert_mkdir(vfs.mkdir(path.base(), 0));
|
|
|
|
|
++count;
|
|
|
|
|
mkdir_a(depth);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
|
{
|
|
|
|
|
try { mkdir_a(1); } catch (...) {
|
|
|
|
|
PERR("failed at %s after %llu directories", path.base(), count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wait()
|
|
|
|
|
{
|
|
|
|
|
join();
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Populate_thread : public Stress_thread
|
|
|
|
|
{
|
|
|
|
|
Populate_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Stress_thread(vfs, parent) { start(); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void populate(int depth)
|
|
|
|
|
{
|
|
|
|
|
if (++depth > MAX_DEPTH) return;
|
|
|
|
|
|
|
|
|
|
using namespace Vfs;
|
|
|
|
|
|
|
|
|
|
size_t path_len = 1+strlen(path.base());
|
|
|
|
|
char dir_type = *(path.base()+(path_len-2));
|
|
|
|
|
|
|
|
|
|
path.append("/c");
|
|
|
|
|
{
|
|
|
|
|
Vfs_handle *handle = nullptr;
|
|
|
|
|
assert_open(vfs.open(
|
|
|
|
|
path.base(), Directory_service::OPEN_MODE_CREATE, &handle));
|
|
|
|
|
Vfs_handle::Guard guard(handle);
|
|
|
|
|
++count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dir_type) {
|
|
|
|
|
case 'a':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("a");
|
|
|
|
|
populate(depth);
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("b");
|
|
|
|
|
populate(depth);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
PERR("bad directory %c at the end of %s", dir_type, path.base());
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
|
{
|
|
|
|
|
::Path start_path(path.base());
|
|
|
|
|
try {
|
|
|
|
|
path.append("/a");
|
|
|
|
|
populate(1);
|
|
|
|
|
|
|
|
|
|
path.import(start_path.base());
|
|
|
|
|
path.append("/b");
|
|
|
|
|
populate(1);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
PERR("failed at %s after %llu files", path.base(), count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wait()
|
|
|
|
|
{
|
|
|
|
|
join();
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Write_thread : public Stress_thread
|
|
|
|
|
{
|
|
|
|
|
Write_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Stress_thread(vfs, parent) { start(); }
|
|
|
|
|
|
|
|
|
|
void write(int depth)
|
|
|
|
|
{
|
|
|
|
|
if (++depth > MAX_DEPTH) return;
|
|
|
|
|
|
|
|
|
|
size_t path_len = 1+strlen(path.base());
|
|
|
|
|
char dir_type = *(path.base()+(path_len-2));
|
|
|
|
|
|
|
|
|
|
using namespace Vfs;
|
|
|
|
|
|
|
|
|
|
path.append("/c");
|
|
|
|
|
{
|
|
|
|
|
Vfs_handle *handle = nullptr;
|
|
|
|
|
assert_open(vfs.open(
|
|
|
|
|
path.base(), Directory_service::OPEN_MODE_WRONLY, &handle));
|
|
|
|
|
Vfs_handle::Guard guard(handle);
|
|
|
|
|
|
|
|
|
|
file_size n;
|
|
|
|
|
assert_write(handle->fs().write(
|
|
|
|
|
handle, path.base(), path_len, n));
|
|
|
|
|
count += n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dir_type) {
|
|
|
|
|
case 'a':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("a");
|
|
|
|
|
write(depth);
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("b");
|
|
|
|
|
write(depth);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
PERR("bad directory %c at the end of %s", dir_type, path.base());
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
|
{
|
|
|
|
|
size_t path_len = strlen(path.base());
|
|
|
|
|
try {
|
|
|
|
|
path.append("/a");
|
|
|
|
|
write(1);
|
|
|
|
|
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("/b");
|
|
|
|
|
write(1);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
PERR("failed at %s after writing %llu bytes", path.base(), count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vfs::file_size wait()
|
|
|
|
|
{
|
|
|
|
|
join();
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Read_thread : public Stress_thread
|
|
|
|
|
{
|
|
|
|
|
Read_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Stress_thread(vfs, parent) { start(); }
|
|
|
|
|
|
|
|
|
|
void read(int depth)
|
|
|
|
|
{
|
|
|
|
|
if (++depth > MAX_DEPTH) return;
|
|
|
|
|
|
|
|
|
|
size_t path_len = 1+strlen(path.base());
|
|
|
|
|
char dir_type = *(path.base()+(path_len-2));
|
|
|
|
|
|
|
|
|
|
using namespace Vfs;
|
|
|
|
|
|
|
|
|
|
path.append("/c");
|
|
|
|
|
{
|
|
|
|
|
Vfs_handle *handle = nullptr;
|
|
|
|
|
assert_open(vfs.open(
|
|
|
|
|
path.base(), Directory_service::OPEN_MODE_RDONLY, &handle));
|
|
|
|
|
Vfs_handle::Guard guard(handle);
|
|
|
|
|
|
|
|
|
|
char tmp[MAX_PATH_LEN];
|
|
|
|
|
file_size n;
|
|
|
|
|
assert_read(handle->fs().read(handle, tmp, sizeof(tmp), n));
|
|
|
|
|
if (strcmp(path.base(), tmp, n))
|
|
|
|
|
PERR("read returned bad data");
|
|
|
|
|
count += n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (dir_type) {
|
|
|
|
|
case 'a':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("a");
|
|
|
|
|
read(depth);
|
|
|
|
|
|
|
|
|
|
case 'b':
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("/b");
|
|
|
|
|
read(depth);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
PERR("bad directory %c at the end of %s", dir_type, path.base());
|
|
|
|
|
throw Exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
|
{
|
|
|
|
|
size_t path_len = strlen(path.base());
|
|
|
|
|
try {
|
|
|
|
|
path.append("/a");
|
|
|
|
|
read(1);
|
|
|
|
|
|
|
|
|
|
path.base()[path_len] = '\0';
|
|
|
|
|
path.append("/b");
|
|
|
|
|
read(1);
|
|
|
|
|
} catch (...) {
|
|
|
|
|
PERR("failed at %s after reading %llu bytes", path.base(), count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vfs::file_size wait()
|
|
|
|
|
{
|
|
|
|
|
join();
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct Unlink_thread : public Stress_thread
|
|
|
|
|
{
|
|
|
|
|
Unlink_thread(Vfs::File_system &vfs, char const *parent)
|
|
|
|
|
: Stress_thread(vfs, parent) { start(); }
|
|
|
|
|
|
|
|
|
|
void empty_dir(char const *path)
|
|
|
|
|
{
|
|
|
|
|
::Path subpath(path);
|
|
|
|
|
subpath.append("/");
|
|
|
|
|
|
|
|
|
|
Vfs::Directory_service::Dirent dirent;
|
|
|
|
|
for (Vfs::file_size i = vfs.num_dirent(path); i;) {
|
|
|
|
|
vfs.dirent(path, --i, dirent);
|
|
|
|
|
subpath.append(dirent.name);
|
|
|
|
|
switch (dirent.type) {
|
|
|
|
|
case Vfs::Directory_service::DIRENT_TYPE_END:
|
|
|
|
|
PERR("reached the end prematurely");
|
|
|
|
|
throw Exception();
|
|
|
|
|
|
|
|
|
|
case Vfs::Directory_service::DIRENT_TYPE_DIRECTORY:
|
|
|
|
|
empty_dir(subpath.base());
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
try {
|
|
|
|
|
assert_unlink(vfs.unlink(subpath.base()));
|
|
|
|
|
} catch (...) {
|
|
|
|
|
PERR("unlink %s failed", subpath.base());
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
subpath.strip_last_element();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry()
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
empty_dir(path.base());
|
|
|
|
|
vfs.unlink(path.base());
|
|
|
|
|
} catch (...) { }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
|
{
|
|
|
|
|
/* look for dynamic linker */
|
|
|
|
|
try {
|
|
|
|
|
static Genode::Rom_connection rom("ld.lib.so");
|
|
|
|
|
Genode::Process::dynamic_linker(rom.dataspace());
|
|
|
|
|
} catch (...) { }
|
|
|
|
|
|
|
|
|
|
static Vfs::Dir_file_system vfs_root(config()->xml_node().sub_node("vfs"),
|
|
|
|
|
Vfs::global_file_system_factory());
|
|
|
|
|
static char path[Vfs::MAX_PATH_LEN];
|
|
|
|
|
|
|
|
|
|
MAX_DEPTH = config()->xml_node().attribute_value("depth", 16U);
|
|
|
|
|
unsigned thread_count =
|
|
|
|
|
config()->xml_node().attribute_value("threads", 6U);
|
|
|
|
|
|
|
|
|
|
unsigned long elapsed_ms;
|
|
|
|
|
Timer::Connection timer;
|
|
|
|
|
|
|
|
|
|
/* populate the directory file system at / */
|
|
|
|
|
vfs_root.num_dirent("/");
|
|
|
|
|
|
|
|
|
|
size_t initial_consumption = env()->ram_session()->used();
|
|
|
|
|
|
|
|
|
|
/**************************
|
|
|
|
|
** Generate directories **
|
|
|
|
|
**************************/
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
Mkdir_thread *threads[thread_count];
|
|
|
|
|
PLOG("generating directory surface...");
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
snprintf(path, 3, "/%lu", i);
|
|
|
|
|
vfs_root.mkdir(path, 0);
|
|
|
|
|
threads[i] = new (Genode::env()->heap())
|
|
|
|
|
Mkdir_thread(vfs_root, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
count += threads[i]->wait();
|
|
|
|
|
destroy(Genode::env()->heap(), threads[i]);
|
|
|
|
|
}
|
|
|
|
|
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
|
|
|
|
|
|
|
|
|
|
vfs_root.sync("/");
|
|
|
|
|
|
|
|
|
|
PINF("created %d empty directories, %luμs/op , %luKB consumed",
|
|
|
|
|
count, (elapsed_ms*1000)/count, env()->ram_session()->used()/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/********************
|
|
|
|
|
** Generate files **
|
|
|
|
|
********************/
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
Populate_thread *threads[thread_count];
|
|
|
|
|
PLOG("generating files...");
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
snprintf(path, 3, "/%lu", i);
|
|
|
|
|
vfs_root.mkdir(path, 0);
|
|
|
|
|
threads[i] = new (Genode::env()->heap())
|
|
|
|
|
Populate_thread(vfs_root, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
count += threads[i]->wait();
|
|
|
|
|
destroy(Genode::env()->heap(), threads[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
|
|
|
|
|
|
|
|
|
|
vfs_root.sync("/");
|
|
|
|
|
|
|
|
|
|
PINF("created %d empty files, %luμs/op, %luKB consumed",
|
|
|
|
|
count, (elapsed_ms*1000)/count, env()->ram_session()->used()/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
|
** Write files **
|
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
|
|
if (!config()->xml_node().attribute_value("write", true)) {
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
PINF("total: %lums, %luK consumed",
|
|
|
|
|
elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Vfs::file_size count = 0;
|
|
|
|
|
Write_thread *threads[thread_count];
|
|
|
|
|
PLOG("writing files...");
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
snprintf(path, 3, "/%lu", i);
|
|
|
|
|
vfs_root.mkdir(path, 0);
|
|
|
|
|
threads[i] = new (Genode::env()->heap())
|
|
|
|
|
Write_thread(vfs_root, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
count += threads[i]->wait();
|
|
|
|
|
destroy(Genode::env()->heap(), threads[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
|
|
|
|
|
|
|
|
|
|
vfs_root.sync("/");
|
|
|
|
|
|
|
|
|
|
PINF("wrote %llu bytes %llukB/s, %luKB consumed",
|
|
|
|
|
count, count/elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
|
** Read files **
|
|
|
|
|
*****************/
|
|
|
|
|
|
|
|
|
|
if (!config()->xml_node().attribute_value("read", true)) {
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
PINF("total: %lums, %luKB consumed",
|
|
|
|
|
elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Vfs::file_size count = 0;
|
|
|
|
|
Read_thread *threads[thread_count];
|
|
|
|
|
PLOG("reading files...");
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
snprintf(path, 3, "/%lu", i);
|
|
|
|
|
vfs_root.mkdir(path, 0);
|
|
|
|
|
threads[i] = new (Genode::env()->heap())
|
|
|
|
|
Read_thread(vfs_root, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
count += threads[i]->wait();
|
|
|
|
|
destroy(Genode::env()->heap(), threads[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
|
|
|
|
|
|
|
|
|
|
vfs_root.sync("/");
|
|
|
|
|
|
|
|
|
|
PINF("read %llu bytes, %llukB/s, %luKB consumed",
|
|
|
|
|
count, count/elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
|
** Unlink files **
|
|
|
|
|
******************/
|
|
|
|
|
|
|
|
|
|
if (!config()->xml_node().attribute_value("unlink", true)) {
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
PINF("total: %lums, %luKB consumed",
|
|
|
|
|
elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
Unlink_thread *threads[thread_count];
|
|
|
|
|
PLOG("unlink files...");
|
|
|
|
|
elapsed_ms = timer.elapsed_ms();
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
snprintf(path, 3, "/%lu", i);
|
|
|
|
|
vfs_root.mkdir(path, 0);
|
|
|
|
|
threads[i] = new (Genode::env()->heap())
|
|
|
|
|
Unlink_thread(vfs_root, path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < thread_count; ++i) {
|
|
|
|
|
threads[i]->join();
|
|
|
|
|
destroy(Genode::env()->heap(), threads[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
|
|
|
|
|
|
|
|
|
|
vfs_root.sync("/");
|
|
|
|
|
|
|
|
|
|
PINF("unlink in %lums, %luKB consumed",
|
|
|
|
|
elapsed_ms, env()->ram_session()->used()/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PINF("total: %lums, %luKB consumed",
|
|
|
|
|
timer.elapsed_ms(), env()->ram_session()->used()/1024);
|
|
|
|
|
|
|
|
|
|
size_t outstanding = env()->ram_session()->used() - initial_consumption;
|
|
|
|
|
if (outstanding) {
|
|
|
|
|
if (outstanding < 1024)
|
|
|
|
|
PERR("%luB not freed after unlink and sync!", outstanding);
|
|
|
|
|
else
|
|
|
|
|
PERR("%luKB not freed after unlink and sync!", outstanding/1024);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|