http://stxxl.sourceforge.net
<beckmann@cs.uni-frankfurt.de>
http://www.boost.org/LICENSE_1_0.txt
#include <iomanip>
#include <vector>
#include <cstdio>
#include <stxxl/io>
#include <stxxl/aligned_alloc>
#include <stxxl/timer>
using stxxl::request_ptr;
using stxxl::file;
using stxxl::timer;
using stxxl::uint64;
#ifndef BLOCK_ALIGN
#define BLOCK_ALIGN 4096
#endif
#define MB (1024 * 1024)
#define GB (1024 * 1024 * 1024)
void usage(const char* argv0)
{
std::cout << "Usage: " << argv0 << " num_blocks blocks_per_round block_size file" << std::endl;
std::cout << " 'block_size' in bytes" << std::endl;
std::cout << " 'file' is split into 'num_blocks' files of size 'block_size'," << std::endl;
std::cout << " reading chunks of 'blocks_per_round' blocks starting from end-of-file" << std::endl;
std::cout << " and truncating the input file after each chunk was read," << std::endl;
std::cout << " before writing the chunk to new files" << std::endl;
exit(-1);
}
inline double throughput(stxxl::uint64 bytes, double seconds)
{
if (seconds == 0.0)
return 0.0;
return bytes / (1024 * 1024) / seconds;
}
int main(int argc, char* argv[])
{
if (argc < 5)
usage(argv[0]);
uint64 num_blocks = stxxl::atoint64(argv[1]);
uint64 blocks_per_round = stxxl::atoint64(argv[2]);
uint64 block_size = stxxl::atoint64(argv[3]);
const char* filebase = argv[4];
uint64 num_rounds = stxxl::div_ceil(num_blocks, blocks_per_round);
std::cout << "# Splitting '" << filebase << "' into "
<< num_rounds * blocks_per_round << " blocks of size "
<< block_size << ", reading chunks of "
<< blocks_per_round << " blocks" << std::endl;
char* buffer = (char*)stxxl::aligned_alloc<BLOCK_ALIGN>(block_size * blocks_per_round);
double totaltimeread = 0, totaltimewrite = 0;
stxxl::int64 totalsizeread = 0, totalsizewrite = 0;
double totaltimereadchunk = 0.0, totaltimewritechunk = 0.0;
stxxl::int64 totalsizereadchunk = 0, totalsizewritechunk = 0;
typedef stxxl::syscall_file file_type;
file_type input_file(filebase, file::RDWR | file::DIRECT, 0);
timer t_total(true);
try {
for (stxxl::unsigned_type r = num_rounds; r-- > 0; )
{
timer t_read(true);
for (stxxl::unsigned_type i = blocks_per_round; i-- > 0; )
{
const uint64 offset = (r * blocks_per_round + i) * block_size;
timer t_op(true);
{
input_file.aread(buffer + i * block_size, offset, block_size, stxxl::default_completion_handler())->wait();
}
t_op.stop();
totalsizeread += block_size;
totaltimeread += t_op.seconds();
if (blocks_per_round > 1) {
std::cout << "Offset " << std::setw(8) << offset / MB << " MiB: " << std::fixed;
std::cout << std::setw(8) << std::setprecision(3) << throughput(block_size, t_op.seconds()) << " MiB/s read";
std::cout << std::endl;
}
}
input_file.set_size(r * blocks_per_round * block_size);
t_read.stop();
totalsizereadchunk += blocks_per_round * block_size;
totaltimereadchunk += t_read.seconds();
timer t_write(true);
for (stxxl::unsigned_type i = blocks_per_round; i-- > 0; )
{
const uint64 offset = (r * blocks_per_round + i) * block_size;
timer t_op(true);
{
char cfn[4096];
snprintf(cfn, sizeof(cfn), "%s_%012llX", filebase, offset);
file_type chunk_file(cfn, file::CREAT | file::RDWR | file::DIRECT, 0);
chunk_file.awrite(buffer + i * block_size, 0, block_size, stxxl::default_completion_handler())->wait();
}
t_op.stop();
totalsizewrite += block_size;
totaltimewrite += t_op.seconds();
if (blocks_per_round > 1) {
std::cout << "Offset " << std::setw(8) << offset / MB << " MiB: " << std::fixed;
std::cout << std::setw(8) << std::setprecision(3) << "" << " ";
std::cout << std::setw(8) << std::setprecision(3) << throughput(block_size, t_op.seconds()) << " MiB/s write";
std::cout << std::endl;
}
}
t_write.stop();
totalsizewritechunk += blocks_per_round * block_size;
totaltimewritechunk += t_write.seconds();
const uint64 offset = r * blocks_per_round * block_size;
std::cout << "Input offset " << std::setw(8) << offset / MB << " MiB: " << std::fixed;
std::cout << std::setw(8) << std::setprecision(3) << throughput(block_size * blocks_per_round, t_read.seconds()) << " MiB/s read, ";
std::cout << std::setw(8) << std::setprecision(3) << throughput(block_size * blocks_per_round, t_write.seconds()) << " MiB/s write";
std::cout << std::endl;
}
}
catch (const std::exception& ex)
{
std::cout << std::endl;
STXXL_ERRMSG(ex.what());
}
t_total.stop();
const int ndisks = 1;
std::cout << "=============================================================================================" << std::endl;
std::cout << "# Average over " << std::setw(8) << stxxl::STXXL_MAX(totalsizewrite, totalsizeread) / MB << " MiB: ";
std::cout << std::setw(8) << std::setprecision(3) << (throughput(totalsizeread, totaltimeread)) << " MiB/s read, ";
std::cout << std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite, totaltimewrite)) << " MiB/s write" << std::endl;
if (totaltimeread != 0.0)
std::cout << "# Read time " << std::setw(8) << std::setprecision(3) << totaltimeread << " s" << std::endl;
if (totaltimereadchunk != 0.0)
std::cout << "# ChRd/trnk ti " << std::setw(8) << std::setprecision(3) << totaltimereadchunk << " s" << std::endl;
if (totaltimewrite != 0.0)
std::cout << "# Write time " << std::setw(8) << std::setprecision(3) << totaltimewrite << " s" << std::endl;
if (totaltimewritechunk != 0.0)
std::cout << "# ChWrite time " << std::setw(8) << std::setprecision(3) << totaltimewritechunk << " s" << std::endl;
std::cout << "# Non-I/O time " << std::setw(8) << std::setprecision(3) << (t_total.seconds() - totaltimewrite - totaltimeread) << " s, average throughput "
<< std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite + totalsizeread, t_total.seconds() - totaltimewrite - totaltimeread) * ndisks) << " MiB/s"
<< std::endl;
std::cout << "# Total time " << std::setw(8) << std::setprecision(3) << t_total.seconds() << " s, average throughput "
<< std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite + totalsizeread, t_total.seconds()) * ndisks) << " MiB/s"
<< std::endl;
stxxl::aligned_dealloc<BLOCK_ALIGN>(buffer);
return 0;
}