initial runs

This commit is contained in:
bronku 2025-11-17 08:26:23 +01:00
parent 9e9260c84d
commit 918c1cba78
18 changed files with 379 additions and 356 deletions

55
src/config.cpp Normal file
View file

@ -0,0 +1,55 @@
#include "../include/config.hpp"
#include <iostream>
#include <stdexcept>
Configuration::Configuration(int argc, char** argv)
{
if (argc <= 1) {
std::cerr << "Please specify input arguments\n";
std::cerr << "Usage: " << argv[0] << " [-g] [-e] [-N count] [-i input] [-o output] [-d dir] [-n buffers] [-b block_size]\n";
throw std::invalid_argument("No input arguments");
}
bool input_set = false;
int opt;
while ((opt = getopt(argc, argv, "i:d:o:geN:n:b:")) != -1) {
switch (opt) {
case 'i':
input_file = optarg;
input_set = true;
break;
case 'o':
output_file = optarg;
break;
case 'd':
tmp_dir = optarg;
break;
case 'g':
generate_data = true;
break;
case 'e':
evaluate_file = true;
break;
case 'N':
N = std::stoi(optarg);
break;
case 'n':
n = std::stoi(optarg);
break;
case 'b':
b = std::stoi(optarg);
break;
case '?':
throw std::invalid_argument("Invalid command line argument");
default:
std::cerr << "Please specify input arguments\n";
}
}
if (generate_data && input_set) {
throw std::invalid_argument("Cannot specify both -g and -i options");
}
if (generate_data && evaluate_file) {
throw std::invalid_argument("Cannot specify both -g and -e options");
}
}

62
src/file_reader.cpp Normal file
View file

@ -0,0 +1,62 @@
#include "../include/file_reader.hpp"
void FileReader::refill_buffer()
{
current_pos_ = 0;
valid_items_ = 0;
for (size_t i = 0; i < buffer_.size(); ++i) {
Record record;
if (!(stream_ >> record)) {
break;
}
buffer_[i] = record;
valid_items_ = i + 1;
}
}
FileReader::FileReader(const std::string& filename, size_t buffer_size)
: stream_(filename)
, buffer_(buffer_size)
, current_pos_(0)
, valid_items_(0)
, total_reads_(0)
{
refill_buffer();
}
std::optional<Record> FileReader::read()
{
if (current_pos_ >= valid_items_) {
refill_buffer();
}
if (valid_items_ == 0) {
return std::nullopt;
}
Record record = buffer_[current_pos_];
current_pos_++;
total_reads_++;
return record;
}
size_t FileReader::read_chunk(std::span<Record>& chunk)
{
size_t count = 0;
for (size_t i = 0; i < chunk.size(); i++) {
auto record = read();
if (!record.has_value()) {
break;
}
chunk[count] = record.value();
count++;
}
return count;
}
size_t FileReader::total_reads() const
{
return total_reads_;
}

47
src/file_writer.cpp Normal file
View file

@ -0,0 +1,47 @@
#include "../include/file_writer.hpp"
void FileWriter::write_buffer()
{
for (size_t i = 0; i < current_pos_; i++) {
stream_ << buffer_[i] << "\n";
}
current_pos_ = 0;
}
FileWriter::FileWriter(const std::string& filename, size_t buffer_size)
: buffer_(buffer_size)
, current_pos_(0)
, total_writes_(0)
{
std::filesystem::path file_path(filename);
std::filesystem::path dir_path = file_path.parent_path();
std::filesystem::create_directories(dir_path);
stream_.open(filename);
}
FileWriter::~FileWriter()
{
write_buffer();
}
void FileWriter::write(const Record& record)
{
if (current_pos_ >= buffer_.size()) {
write_buffer();
}
buffer_[current_pos_] = record;
current_pos_++;
total_writes_++;
}
void FileWriter::write_chunk(std::span<const Record>& chunk)
{
for (const auto& record : chunk) {
write(record);
}
}
size_t FileWriter::total_writes() const
{
return total_writes_;
}

View file

@ -1,19 +1,16 @@
#include "config.hpp"
#include "record.hpp"
#include "sort.cpp"
#include "writer.hpp"
#include <fstream>
#include "../include/config.hpp"
#include "../include/file_reader.hpp"
#include "../include/file_writer.hpp"
#include "../include/merge_sorter.hpp"
#include "../include/record.hpp"
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
void generate_file(int N, const std::string& filename)
{
std::filesystem::path dirPath = std::filesystem::path(filename).parent_path();
std::filesystem::create_directories(dirPath);
std::ofstream out_stream(filename);
Writer output(out_stream);
FileWriter output(filename);
for (int i = 0; i < N; i++) {
Record rec = Record::random();
@ -21,47 +18,33 @@ void generate_file(int N, const std::string& filename)
}
}
void read_and_evaluate(std::string filename, int n)
void read_and_evaluate(std::string filename)
{
Buffer main_buffer(n);
auto buff = main_buffer.divide(1)[0];
std::ifstream in_stream(filename);
Reader input_reader(in_stream);
FileReader input(filename);
while (true) {
size_t records_read = read_chunk(input_reader, buff);
if (records_read == 0) {
break;
auto rec = input.read();
if (!rec.has_value()) {
return;
}
for (size_t i = 0; i < records_read; ++i) {
const Record& rec = buff[i];
std::cout << "[Evaluate i = " << i << ": " << rec.evaluate() << "] " << rec << "\n";
}
std::cout << "[Evaluate: " << rec.value().evaluate() << "] " << rec.value() << "\n";
}
}
int main(int argc, char** argv)
{
try {
Configuration opts = Configuration::parse_args(argc, argv);
Configuration opts(argc, argv);
if (opts.generate_data) {
generate_file(opts.N, opts.output_file);
return 0;
}
if (opts.evaluate_file) {
read_and_evaluate(opts.input_file, opts.N);
return 0;
}
sort_file(opts);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
return 1;
if (opts.generate_data) {
generate_file(opts.N, opts.output_file);
return 0;
}
if (opts.evaluate_file) {
read_and_evaluate(opts.input_file);
return 0;
}
MergeSorter sorter(opts.b, opts.n, opts.tmp_dir);
sorter.sort_file(opts.input_file, opts.output_file);
}

46
src/merge_sorter.cpp Normal file
View file

@ -0,0 +1,46 @@
#include "../include/merge_sorter.hpp"
size_t MergeSorter::create_initial_runs(const std::string& input_file)
{
FileReader reader(input_file);
std::span<Record> chunk(buffer_);
size_t run_count = 0;
for (run_count = 0;; run_count++) {
size_t records_read = reader.read_chunk(chunk);
if (records_read == 0) {
break;
}
std::sort(chunk.begin(), chunk.begin() + records_read);
std::string run_file = tmp_dir_ + "pass0/run_" + std::to_string(run_count) + ".dat";
FileWriter writer(run_file);
auto output = std::span<const Record>(chunk.data(), records_read);
writer.write_chunk(output);
disk_reads_ += reader.total_reads() - disk_reads_;
disk_writes_ += writer.total_writes() - disk_writes_;
}
return run_count;
}
MergeSorter::MergeSorter(size_t buffer_rows, size_t buffer_cols, const std::string& tmp_dir)
: buffer_(buffer_rows * buffer_cols)
, tmp_dir_(tmp_dir)
, buffer_rows(buffer_rows)
, disk_reads_(0)
, disk_writes_(0)
, phases_(0)
{
if (buffer_rows < 3) {
throw std::invalid_argument("Buffer must have at least 3 rows for merging");
}
}
bool MergeSorter::sort_file(const std::string& input_file, const std::string& output_file)
{
create_initial_runs(input_file);
std::cout << output_file << '\n';
return true;
}

46
src/record.cpp Normal file
View file

@ -0,0 +1,46 @@
#include "../include/record.hpp"
#include <random>
int Record::evaluate() const
{
int out = 0;
int x_n = 1;
for (int i = 0; i < 5; i++) {
out += a[i] * x_n;
x_n *= x;
}
return out;
}
bool Record::operator<(const Record& other) const
{
return evaluate() < other.evaluate();
}
Record Record::random()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<int> dist;
Record r {};
for (int& val : r.a) {
val = dist(gen);
}
r.x = dist(gen);
return r;
}
std::ostream& operator<<(std::ostream& os, const Record& r)
{
os << r.a[0] << ' ' << r.a[1] << ' ' << r.a[2] << ' '
<< r.a[3] << ' ' << r.a[4] << ' ' << r.x;
return os;
}
std::istream& operator>>(std::istream& is, Record& r)
{
is >> r.a[0] >> r.a[1] >> r.a[2] >> r.a[3] >> r.a[4] >> r.x;
return is;
}