Skip to content

Real time output #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions src/limits/TimeLimitListener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,27 @@ executor::ExecuteAction TimeLimitListener::onSigalrmSignal() {
if (!isTimerCreated_) {
return executor::ExecuteAction::CONTINUE;
}
return verifyTimeUsage();
auto time = getTimeUsage();
return verifyTimeUsage(move(time));
}

void TimeLimitListener::onPostExecute() {
// TODO: run this just after child exit
verifyTimeUsage();
// TODO Save time usage to OutputBuilder.
auto time = getTimeUsage();
outputBuilder_->setRealTimeMicroseconds(time->realTimeUs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should double-check this, but IIRC the old "real-cpu" supervisor uses user time, not real time.

verifyTimeUsage(move(time));
}

executor::ExecuteAction TimeLimitListener::verifyTimeUsage() {
if (rTimelimitUs_ != 0 && getRealTimeUsage() > rTimelimitUs_) {
executor::ExecuteAction TimeLimitListener::verifyTimeUsage(std::unique_ptr<TimeLimitListener::TimeUsage> timeUsage) {
if (rTimelimitUs_ != 0 && timeUsage->realTimeUs > rTimelimitUs_) {
outputBuilder_->setKillReason(
printer::OutputBuilder::KillReason::TLE,
"real time limit exceeded");
return executor::ExecuteAction::KILL;
}
if (uTimelimitUs_ != 0 || sTimelimitUs_ != 0 || usTimelimitUs_ != 0) {
ProcessTimeUsage ptu = getProcessTimeUsage();
ProcessTimeUsage& ptu = timeUsage->processTimeUs;

if (uTimelimitUs_ != 0 && ptu.uTimeUs > uTimelimitUs_) {
outputBuilder_->setKillReason(
printer::OutputBuilder::KillReason::TLE,
Expand All @@ -128,7 +131,7 @@ executor::ExecuteAction TimeLimitListener::verifyTimeUsage() {
return executor::ExecuteAction::CONTINUE;
}

uint64_t TimeLimitListener::getRealTimeUsage() {
uint64_t TimeLimitListener::getRealTimeUsage() const {
std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now();
std::chrono::steady_clock::duration realTimeUsage = now - startRealTime_;
Expand All @@ -138,7 +141,7 @@ uint64_t TimeLimitListener::getRealTimeUsage() {
return realTimeUsageUs;
}

TimeLimitListener::ProcessTimeUsage TimeLimitListener::getProcessTimeUsage() {
TimeLimitListener::ProcessTimeUsage TimeLimitListener::getProcessTimeUsage() const {
std::ifstream stat("/proc/" + std::to_string(childPid_) + "/stat");
if (!stat.good()) {
throw SystemException("Error reading /proc/childPid_/stat");
Expand All @@ -164,6 +167,14 @@ TimeLimitListener::ProcessTimeUsage TimeLimitListener::getProcessTimeUsage() {
return result;
}

std::unique_ptr<TimeLimitListener::TimeUsage> TimeLimitListener::getTimeUsage() const {
return std::make_unique<TimeUsage>(
TimeUsage{
.realTimeUs = getRealTimeUsage(),
.processTimeUs = getProcessTimeUsage()
}
);
}

} // namespace limits
} // namespace s2j
12 changes: 9 additions & 3 deletions src/limits/TimeLimitListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ class TimeLimitListener
uint64_t sTimeUs; // system time in [us]
};

struct TimeUsage {
uint64_t realTimeUs;
ProcessTimeUsage processTimeUs;
};

static const uint64_t TIMER_TICKING_INTERVAL_US;
static const long CLOCK_TICKS_PER_SECOND;

executor::ExecuteAction verifyTimeUsage();
uint64_t getRealTimeUsage();
ProcessTimeUsage getProcessTimeUsage();
executor::ExecuteAction verifyTimeUsage(std::unique_ptr<TimeUsage>);
uint64_t getRealTimeUsage() const;
ProcessTimeUsage getProcessTimeUsage() const;
std::unique_ptr<TimeUsage> getTimeUsage() const;

uint64_t rTimelimitUs_; // real time limit in [us]
uint64_t uTimelimitUs_; // user time limit in [us]
Expand Down
6 changes: 6 additions & 0 deletions src/printer/OIModelOutputBuilder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace printer {

OIModelOutputBuilder::OIModelOutputBuilder()
: milliSecondsElapsed_(0)
, realMilliSecondsElapsed_(0)
, memoryPeakKb_(0)
, syscallsCounter_(0)
, exitStatus_(0)
Expand All @@ -15,6 +16,11 @@ OutputBuilder& OIModelOutputBuilder::setCyclesUsed(uint64_t cyclesUsed) {
return *this;
}

OutputBuilder& OIModelOutputBuilder::setRealTimeMicroseconds(uint64_t time) {
realMilliSecondsElapsed_ = time / 1000;
return *this;
}

OutputBuilder& OIModelOutputBuilder::setMemoryPeak(uint64_t memoryPeakKb) {
memoryPeakKb_ = memoryPeakKb;
return *this;
Expand Down
2 changes: 2 additions & 0 deletions src/printer/OIModelOutputBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class OIModelOutputBuilder : public OutputBuilder {
OIModelOutputBuilder();

OutputBuilder& setCyclesUsed(uint64_t cyclesUsed) override;
OutputBuilder& setRealTimeMicroseconds(uint64_t time) override;
OutputBuilder& setMemoryPeak(uint64_t memoryPeakKb) override;
OutputBuilder& setExitStatus(uint32_t exitStatus) override;
OutputBuilder& setKillSignal(uint32_t killSignal) override;
Expand All @@ -20,6 +21,7 @@ class OIModelOutputBuilder : public OutputBuilder {
static const uint64_t CYCLES_PER_SECOND = 2'000'000'000;

uint64_t milliSecondsElapsed_;
uint64_t realMilliSecondsElapsed_;
uint64_t memoryPeakKb_;
uint64_t syscallsCounter_;
uint32_t exitStatus_;
Expand Down
3 changes: 3 additions & 0 deletions src/printer/OutputBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class OutputBuilder {
virtual OutputBuilder& setCyclesUsed(uint64_t cyclesUsed) {
return *this;
}
virtual OutputBuilder& setRealTimeMicroseconds(uint64_t time) {
return *this;
}
virtual OutputBuilder& setMemoryPeak(uint64_t memoryPeakKb) {
return *this;
}
Expand Down
44 changes: 44 additions & 0 deletions src/printer/RealTimeOIOutputBuilder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "RealTimeOIOutputBuilder.h"

#include <sstream>

namespace s2j {
namespace printer {

const std::string RealTimeOIOutputBuilder::FORMAT_NAME = "oireal";

std::string RealTimeOIOutputBuilder::dump() const {
KillReason reason = killReason_;
if (reason == KillReason::NONE) {
if (killSignal_ > 0 || exitStatus_ > 0) {
reason = KillReason::RE;
}
}

std::stringstream ss;
ss << killReasonName(reason) << " " << exitStatus_ << " "
<< realMilliSecondsElapsed_ << " "
<< 0ULL << " " << memoryPeakKb_ << " "
<< syscallsCounter_ << std::endl;
dumpStatus(ss);
ss << std::endl;
return ss.str();
}

void RealTimeOIOutputBuilder::dumpStatus(std::ostream& ss) const {
if (killReason_ != KillReason::NONE) {
ss << killReasonComment_;
}
else if (killSignal_ > 0) {
ss << "process exited due to signal " << killSignal_;
}
else if (exitStatus_ > 0) {
ss << "runtime error " << exitStatus_;
}
else {
ss << "ok";
}
}

} // namespace printer
} // namespace s2j
20 changes: 20 additions & 0 deletions src/printer/RealTimeOIOutputBuilder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "OIModelOutputBuilder.h"

namespace s2j {
namespace printer {

class RealTimeOIOutputBuilder : public OIModelOutputBuilder {
public:
std::string dump() const override;

const static std::string FORMAT_NAME;

private:
void dumpStatus(std::ostream& ss) const;
int encodeStatusCode() const;
};

} // namespace printer
} // namespace s2j
8 changes: 6 additions & 2 deletions src/s2japp/ApplicationSettings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "common/Utils.h"
#include "printer/AugmentedOIOutputBuilder.h"
#include "printer/OITimeToolOutputBuilder.h"
#include "printer/RealTimeOIOutputBuilder.h"
#include "seccomp/policy/DefaultPolicy.h"
#include "seccomp/policy/PermissivePolicy.h"

Expand Down Expand Up @@ -80,7 +81,7 @@ class StringOutputGenerator : public TCLAP::StdOutput {
namespace s2j {
namespace app {

const std::string ApplicationSettings::VERSION = "1.4.1-beta";
const std::string ApplicationSettings::VERSION = "1.4.2";

const std::string ApplicationSettings::DESCRIPTION =
"SIO2jail, a sandbox for programming contests.";
Expand All @@ -90,7 +91,10 @@ const FactoryMap<s2j::printer::OutputBuilder>
{{"oitt",
std::make_shared<s2j::printer::OITimeToolOutputBuilder>},
{"oiaug",
std::make_shared<s2j::printer::AugmentedOIOutputBuilder>}});
std::make_shared<s2j::printer::AugmentedOIOutputBuilder>},
{"oireal",
std::make_shared<s2j::printer::RealTimeOIOutputBuilder>}
});
const std::string ApplicationSettings::DEFAULT_OUTPUT_FORMAT = "oitt";

const FactoryMap<s2j::seccomp::policy::BaseSyscallPolicy>
Expand Down
6 changes: 4 additions & 2 deletions src/seccomp/policy/DefaultPolicy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ void DefaultPolicy::addExecutionControlRules(bool allowFork) {
"clock_nanosleep",
"open",
"epoll_create1",
"openat"});
"openat"
});

rules_.emplace_back(SeccompRule(
"set_thread_area", action::ActionTrace([](auto& /* tracee */) {
Expand Down Expand Up @@ -128,7 +129,7 @@ void DefaultPolicy::addInputOutputRules() {
"dup2", action::ActionAllow(), filter::SyscallArg(1) >= 3));

// Allow reading from any file descriptor
allowSyscalls({"read", "readv", "dup", "fcntl", "fcntl64"});
allowSyscalls({"read", "readv", "dup", "fcntl", "fcntl64", "pread64"});

rules_.emplace_back(SeccompRule("ioctl", action::ActionErrno(ENOTTY)));

Expand All @@ -150,6 +151,7 @@ void DefaultPolicy::addFileSystemAccessRules(bool readOnly) {
"stat64",
"fstat",
"fstat64",
"newfstatat",
"lstat",
"lstat64",
"listxattr",
Expand Down