Skip to content

Commit

Permalink
Update to latest libprimesieve
Browse files Browse the repository at this point in the history
  • Loading branch information
kimwalisch committed Feb 15, 2024
1 parent 918921b commit 695f92e
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 72 deletions.
115 changes: 49 additions & 66 deletions lib/primesieve/src/app/CmdOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

#include "CmdOptions.hpp"

#include <primesieve/calculator.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/primesieve_error.hpp>

Expand All @@ -50,29 +49,6 @@ enum IsParam
OPTIONAL_PARAM
};

/// Command-line option
struct Option
{
// Example:
// str = "--threads=32"
// opt = "--threads"
// val = "32"
std::string str;
std::string opt;
std::string val;

template <typename T>
T getValue() const
{
try {
return calculator::eval<T>(val);
}
catch (std::exception&) {
throw primesieve_error("invalid option '" + opt + "=" + val + "'");
}
}
};

/// Options start with "-" or "--", then
/// follows a Latin ASCII character.
///
Expand Down Expand Up @@ -210,29 +186,42 @@ Option parseOption(int argc,
return opt;
}

void optionPrint(Option& opt,
CmdOptions& opts)
} // namespace

void CmdOptions::setMainOption(OptionID optionID,
const std::string& optStr)
{
opts.quiet = true;
// Multiple main options are not allowed
if (!optionStr.empty())
throw primesieve_error("incompatible options: " + optionStr + " " + optStr);
else
{
optionStr = optStr;
option = optionID;
}
}

void CmdOptions::optionPrint(Option& opt)
{
quiet = true;

// by default print primes
if (opt.val.empty())
opt.val = "1";

switch (opt.getValue<int>())
{
case 1: opts.flags |= PRINT_PRIMES; break;
case 2: opts.flags |= PRINT_TWINS; break;
case 3: opts.flags |= PRINT_TRIPLETS; break;
case 4: opts.flags |= PRINT_QUADRUPLETS; break;
case 5: opts.flags |= PRINT_QUINTUPLETS; break;
case 6: opts.flags |= PRINT_SEXTUPLETS; break;
case 1: flags |= PRINT_PRIMES; break;
case 2: flags |= PRINT_TWINS; break;
case 3: flags |= PRINT_TRIPLETS; break;
case 4: flags |= PRINT_QUADRUPLETS; break;
case 5: flags |= PRINT_QUINTUPLETS; break;
case 6: flags |= PRINT_SEXTUPLETS; break;
default: throw primesieve_error("invalid option '" + opt.str + "'");
}
}

void optionCount(Option& opt,
CmdOptions& opts)
void CmdOptions::optionCount(Option& opt)
{
// by default count primes
if (opt.val.empty())
Expand All @@ -244,52 +233,48 @@ void optionCount(Option& opt,
{
switch (n % 10)
{
case 1: opts.flags |= COUNT_PRIMES; break;
case 2: opts.flags |= COUNT_TWINS; break;
case 3: opts.flags |= COUNT_TRIPLETS; break;
case 4: opts.flags |= COUNT_QUADRUPLETS; break;
case 5: opts.flags |= COUNT_QUINTUPLETS; break;
case 6: opts.flags |= COUNT_SEXTUPLETS; break;
case 1: flags |= COUNT_PRIMES; break;
case 2: flags |= COUNT_TWINS; break;
case 3: flags |= COUNT_TRIPLETS; break;
case 4: flags |= COUNT_QUADRUPLETS; break;
case 5: flags |= COUNT_QUINTUPLETS; break;
case 6: flags |= COUNT_SEXTUPLETS; break;
default: throw primesieve_error("invalid option '" + opt.str + "'");
}
}
}

void optionDistance(Option& opt,
CmdOptions& opts)
void CmdOptions::optionDistance(Option& opt)
{
uint64_t start = 0;
uint64_t val = opt.getValue<uint64_t>();
auto& numbers = opts.numbers;

if (!numbers.empty())
start = numbers[0];

numbers.push_back(start + val);
}

void optionStressTest(Option& opt,
CmdOptions& opts)
void CmdOptions::optionStressTest(Option& opt)
{
opts.option = OPTION_STRESS_TEST;
setMainOption(OPTION_STRESS_TEST, opt.str);
std::transform(opt.val.begin(), opt.val.end(), opt.val.begin(),
[](unsigned char c){ return std::toupper(c); });

// If the stress test mode is not specified
// we use "CPU" by default.
if (opt.val.empty())
opts.stressTestMode = "CPU";
stressTestMode = "CPU";
else if (opt.val == "CPU")
opts.stressTestMode = "CPU";
stressTestMode = "CPU";
else if (opt.val == "RAM")
opts.stressTestMode = "RAM";
stressTestMode = "RAM";
else
throw primesieve_error("invalid option '" + opt.str + "=" + opt.val + "'");
}

/// Stress test timeout
void optionTimeout(Option& opt,
CmdOptions& opts)
void CmdOptions::optionTimeout(Option& opt)
{
std::transform(opt.val.begin(), opt.val.end(), opt.val.begin(),
[](unsigned char c){ return std::tolower(c); });
Expand All @@ -298,19 +283,17 @@ void optionTimeout(Option& opt,
// https://manpages.debian.org/unstable/stress-ng/stress-ng.1.en.html
switch (opt.val.back())
{
case 's': opt.val.pop_back(); opts.timeout = opt.getValue<int64_t>(); break;
case 'm': opt.val.pop_back(); opts.timeout = opt.getValue<int64_t>() * 60; break;
case 'h': opt.val.pop_back(); opts.timeout = opt.getValue<int64_t>() * 3600; break;
case 'd': opt.val.pop_back(); opts.timeout = opt.getValue<int64_t>() * 24 * 3600; break;
case 'y': opt.val.pop_back(); opts.timeout = opt.getValue<int64_t>() * 365 * 24 * 3600; break;
case 's': opt.val.pop_back(); timeout = opt.getValue<int64_t>(); break;
case 'm': opt.val.pop_back(); timeout = opt.getValue<int64_t>() * 60; break;
case 'h': opt.val.pop_back(); timeout = opt.getValue<int64_t>() * 3600; break;
case 'd': opt.val.pop_back(); timeout = opt.getValue<int64_t>() * 24 * 3600; break;
case 'y': opt.val.pop_back(); timeout = opt.getValue<int64_t>() * 365 * 24 * 3600; break;

// By default assume seconds like stress-ng
default: opts.timeout = opt.getValue<int64_t>();
default: timeout = opt.getValue<int64_t>();
}
}

} // namespace

CmdOptions parseOptions(int argc, char* argv[])
{
// No command-line options provided
Expand Down Expand Up @@ -361,18 +344,18 @@ CmdOptions parseOptions(int argc, char* argv[])

switch (optionID)
{
case OPTION_COUNT: optionCount(opt, opts); break;
case OPTION_DISTANCE: optionDistance(opt, opts); break;
case OPTION_PRINT: optionPrint(opt, opts); break;
case OPTION_STRESS_TEST: optionStressTest(opt, opts); break;
case OPTION_TIMEOUT: optionTimeout(opt, opts); break;
case OPTION_COUNT: opts.optionCount(opt); break;
case OPTION_DISTANCE: opts.optionDistance(opt); break;
case OPTION_PRINT: opts.optionPrint(opt); break;
case OPTION_STRESS_TEST: opts.optionStressTest(opt); break;
case OPTION_TIMEOUT: opts.optionTimeout(opt); break;
case OPTION_SIZE: opts.sieveSize = opt.getValue<int>(); break;
case OPTION_THREADS: opts.threads = opt.getValue<int>(); break;
case OPTION_QUIET: opts.quiet = true; break;
case OPTION_NO_STATUS: opts.status = false; break;
case OPTION_TIME: opts.time = true; break;
case OPTION_NUMBER: opts.numbers.push_back(opt.getValue<uint64_t>()); break;
default: opts.option = optionID;
default: opts.setMainOption(optionID, opt.str);
}
}

Expand Down
35 changes: 35 additions & 0 deletions lib/primesieve/src/app/CmdOptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
#ifndef CMDOPTIONS_HPP
#define CMDOPTIONS_HPP

#include <primesieve/calculator.hpp>
#include <primesieve/primesieve_error.hpp>
#include <primesieve/Vector.hpp>

#include <exception>
#include <stdint.h>
#include <string>

Expand All @@ -36,10 +40,34 @@ enum OptionID
OPTION_VERSION
};

/// Command-line option
struct Option
{
// Example:
// str = "--threads=32"
// opt = "--threads"
// val = "32"
std::string str;
std::string opt;
std::string val;

template <typename T>
T getValue() const
{
try {
return calculator::eval<T>(val);
}
catch (std::exception&) {
throw primesieve::primesieve_error("invalid option '" + opt + "=" + val + "'");
}
}
};

struct CmdOptions
{
primesieve::Vector<uint64_t> numbers;
std::string stressTestMode;
std::string optionStr;
int option = -1;
int flags = 0;
int sieveSize = 0;
Expand All @@ -50,6 +78,13 @@ struct CmdOptions
bool quiet = false;
bool status = true;
bool time = false;

void setMainOption(OptionID optionID, const std::string& optStr);
void optionPrint(Option& opt);
void optionCount(Option& opt);
void optionDistance(Option& opt);
void optionStressTest(Option& opt);
void optionTimeout(Option& opt);
};

CmdOptions parseOptions(int, char**);
Expand Down
48 changes: 42 additions & 6 deletions lib/primesieve/src/app/stressTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <iostream>
#include <iomanip>
Expand Down Expand Up @@ -125,9 +126,9 @@ std::string getTimeElapsed(int64_t secs)

for (std::size_t i = 0; i < time.size(); i++)
{
if (secs >= time[i])
if (secs > time[i])
{
timeStr += (timeStr.empty()) ? "" : " ";
timeStr += timeStr.empty() ? "" : " ";
timeStr += std::to_string(secs / time[i]) + suffix[i];
secs %= time[i];
}
Expand Down Expand Up @@ -179,6 +180,39 @@ std::string getStartString(uint64_t start)
}
}

/// Date time format: "[Jan 13 22:07] "
std::string getDateTime()
{
#if 0
// Thread safe.
// Requires C23, but does not work yet with the
// MSVC 2022 and MinGW-w64 compilers.
std::tm result;
std::time_t currentTime = std::time(nullptr);
if (!localtime_r(&currentTime, &result))
return "";

std::ostringstream oss;
oss << std::put_time(&result, "[%b %d %H:%M] ");
return oss.str();
#else
// Not thread safe.
// But we lock a mutex before calling getDateTime()
// hence this is not an issue for us.
#if defined(_MSC_VER)
#pragma warning(disable : 4996)
#endif
std::time_t currentTime = std::time(nullptr);
std::tm* currentDateTime = std::localtime(&currentTime);
if (!currentDateTime)
return "";

std::ostringstream oss;
oss << std::put_time(currentDateTime, "[%b %d %H:%M] ");
return oss.str();
#endif
}

void printResult(int threadId,
int threads,
uint64_t i,
Expand All @@ -194,15 +228,17 @@ void printResult(int threadId,

if (count == primeCounts[i])
{
std::cout << "Thread: " << std::setw(threadIdPadding) << std::right << threadId
<< ", secs: " << std::fixed << std::setprecision(3) << secsThread.count()
std::cout << getDateTime()
<< "Thread " << std::setw(threadIdPadding) << std::right << threadId
<< ", " << std::fixed << std::setprecision(2) << secsThread.count() << " secs"
<< ", PrimePi(" << startStr << std::setw(iPadding) << std::right << i-1 << "e11, "
<< startStr << std::setw(iPadding) << std::right << i << "e11) = " << count << " OK" << std::endl;
}
else
{
std::cerr << "Thread: " << std::setw(threadIdPadding) << std::right << threadId
<< ", secs: " << std::fixed << std::setprecision(3) << secsThread.count()
std::cerr << getDateTime()
<< "Thread " << std::setw(threadIdPadding) << std::right << threadId
<< ", " << std::fixed << std::setprecision(2) << secsThread.count() << " secs"
<< ", PrimePi(" << startStr << std::setw(iPadding) << std::right << i-1 << "e11, "
<< startStr << std::setw(iPadding) << std::right << i << "e11) = " << count << " ERROR" << std::endl;

Expand Down

0 comments on commit 695f92e

Please sign in to comment.