aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-04-05 00:48:46 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-04-05 00:48:46 +0900
commit28602c83ac43224b555157739842bd9167fb67b8 (patch)
tree0f3eb4ce787a66cab3dfd8d860bafd2296f68641
parent492cb5aec30cbb253932f54d549f07610a2ed037 (diff)
downloadpoe-28602c83ac43224b555157739842bd9167fb67b8.tar.gz
実行時間の計測に対応
-rw-r--r--backend/src/run_result.rs9
-rw-r--r--config.json28
-rw-r--r--frontend/app/snippet-detail.component.ts2
-rw-r--r--frontend/app/snippet.service.ts1
-rw-r--r--sandbox/child.c3
-rw-r--r--sandbox/main.c29
6 files changed, 61 insertions, 11 deletions
diff --git a/backend/src/run_result.rs b/backend/src/run_result.rs
index 697b8fa..2deb2e0 100644
--- a/backend/src/run_result.rs
+++ b/backend/src/run_result.rs
@@ -13,6 +13,7 @@ use std::process::Output;
struct RunResultMetadata {
pub exit: i32,
pub result: i32,
+ pub elapsed: u64,
pub message: String,
pub truncated: bool,
}
@@ -28,6 +29,7 @@ pub fn open_render(snip: &Snippet, comp: &Compiler) -> Json {
let meta: RunResultMetadata = json::decode(&encoded).unwrap();
map.insert("exit".to_string(), meta.exit.to_json());
map.insert("result".to_string(), meta.result.to_json());
+ map.insert("elapsed".to_string(), meta.elapsed.to_json());
map.insert("message".to_string(), meta.message.to_json());
map.insert("truncated".to_string(), meta.truncated.to_json());
map.insert("output".to_string(), read_output_str(&snip, &comp).to_json());
@@ -80,17 +82,18 @@ pub fn parse_and_save(snip: &Snippet, comp: &Compiler, output: Output) -> Result
let output_limit = 65536;
if output.status.success() {
- if output.stderr.len() < 8 {
+ if output.stderr.len() < 16 {
return Err(PoeError::from("failed sandbox (result)"));
}
- let (metavec, msgvec) = output.stderr.split_at(8);
+ let (metavec, msgvec) = output.stderr.split_at(16);
let mut rdr = Cursor::new(metavec);
let reason = rdr.read_i32::<LittleEndian>().unwrap();
let exit = rdr.read_i32::<LittleEndian>().unwrap();
+ let elapsed = rdr.read_u64::<LittleEndian>().unwrap();
let msg_str = String::from_utf8_lossy(&msgvec);
let trunc = output.stdout.len() > output_limit;
- let meta = RunResultMetadata { exit: exit, result: reason, message: msg_str.into_owned(), truncated: trunc };
+ let meta = RunResultMetadata { exit: exit, result: reason, message: msg_str.into_owned(), truncated: trunc, elapsed: elapsed };
let mut meta_file = fs::File::create(format!("{}/results/{}.json", &snip.basedir(), &comp.id))?;
meta_file.write(json::encode(&meta).unwrap().as_bytes())?;
diff --git a/config.json b/config.json
index 7dc40b1..fb75a7e 100644
--- a/config.json
+++ b/config.json
@@ -24,6 +24,34 @@
"{}"
]
},
+ "ruby-2.2.3": {
+ "version": "ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]",
+ "commandline": [
+ "/opt/bin/ruby",
+ "{}"
+ ]
+ },
+ "ruby-2.2.2": {
+ "version": "ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]",
+ "commandline": [
+ "/opt/bin/ruby",
+ "{}"
+ ]
+ },
+ "ruby-2.2.1": {
+ "version": "ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]",
+ "commandline": [
+ "/opt/bin/ruby",
+ "{}"
+ ]
+ },
+ "ruby-2.2.0": {
+ "version": "ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]",
+ "commandline": [
+ "/opt/bin/ruby",
+ "{}"
+ ]
+ },
"ruby-2.1.10": {
"version": "ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]",
"commandline": [
diff --git a/frontend/app/snippet-detail.component.ts b/frontend/app/snippet-detail.component.ts
index f9ddae6..a80107a 100644
--- a/frontend/app/snippet-detail.component.ts
+++ b/frontend/app/snippet-detail.component.ts
@@ -9,7 +9,7 @@ import {EditingData, EditingDataService} from "./editing-data.service";
<div class="result-item panel"
*ngFor="#r of snippet.results.slice().reverse(); #i = index"
[ngClass]="{'panel-success': isSuccess(r), 'panel-failure': isFailure(r), 'panel-running': isRunning(r), 'result-item-collapsed': isHiddenIdx(i)}">
- <div class="panel-heading" (click)="toggleHiddenIdx(i)">{{r.compiler.id}} ({{r.compiler.version}})</div>
+ <div class="panel-heading" (click)="toggleHiddenIdx(i)">{{r.compiler.id}} ({{r.compiler.version}}) {{r.elapsed / 1000}}ms</div>
<div class="panel-body container">
<pre><code [innerHTML]="formatted_output(r)"></code></pre>
</div>
diff --git a/frontend/app/snippet.service.ts b/frontend/app/snippet.service.ts
index dd1278e..ad687f9 100644
--- a/frontend/app/snippet.service.ts
+++ b/frontend/app/snippet.service.ts
@@ -13,6 +13,7 @@ export class Result {
public compiler: Compiler,
public result: number,
public exit: number,
+ public elapsed: number,
public message: string,
public output: any[],
public _: any,
diff --git a/sandbox/child.c b/sandbox/child.c
index a521a4a..caa6fc5 100644
--- a/sandbox/child.c
+++ b/sandbox/child.c
@@ -49,8 +49,7 @@ noreturn void poe_child_do(struct playground *pg,
if (poe_seccomp_init())
bug("seccomp init failed");
- if (close(child_fd[0]) || close(child_fd[1]))
- bug("close child_fds failed");
+ // child_fd は exec によって close される
if (dup2(stdout_fd[1], STDOUT_FILENO) < 0 || close(stdout_fd[0]) || close(stdout_fd[1]))
bug("dup2/close stdout failed");
if (dup2(stderr_fd[1], STDERR_FILENO) < 0 || close(stderr_fd[0]) || close(stderr_fd[1]))
diff --git a/sandbox/main.c b/sandbox/main.c
index d539a63..8043929 100644
--- a/sandbox/main.c
+++ b/sandbox/main.c
@@ -1,9 +1,21 @@
#include "sandbox.h"
+static struct timespec start_timespec = { 0 };
+
static noreturn void finish(enum poe_exit_reason reason, int status, const char *fmt, ...)
{
+ if (!start_timespec.tv_sec && !start_timespec.tv_nsec)
+ bug("start_timespec not set?");
+ struct timespec end_timespec;
+ if (clock_gettime(CLOCK_MONOTONIC, &end_timespec))
+ bug("clock_gettime failed");
+ uint64_t elapsed =
+ (uint64_t)(end_timespec.tv_sec - start_timespec.tv_sec) * 1000 * 1000 +
+ (end_timespec.tv_nsec - start_timespec.tv_nsec) / 1000;
+
int xx[] = { reason, status };
fwrite(xx, sizeof(int), 2, stderr);
+ fwrite(&elapsed, sizeof(uint64_t), 1, stderr);
if (fmt) {
va_list args;
va_start(args, fmt);
@@ -103,6 +115,9 @@ int main(int argc, char *argv[])
bug("unreachable");
}
+ if (close(stdout_fd[1]) || close(stderr_fd[1]) || close(child_fd[1]))
+ bug("close child write pipe failed");
+
int epoll_fd = epoll_create1(0);
if (epoll_fd < 0)
bug("epoll_create1 failed");
@@ -124,7 +139,7 @@ int main(int argc, char *argv[])
if (timerfd_settime(timer_fd, 0, &(struct itimerspec) { .it_value.tv_sec = POE_TIME_LIMIT }, NULL))
bug("timerfd_settime failed");
-#define ADD(_fd__) do if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, _fd__, &(struct epoll_event) { .data.fd = _fd__, .events = EPOLLIN })) \
+#define ADD(_fd__) do if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, _fd__, &(struct epoll_event) { .data.fd = _fd__, .events = EPOLLRDHUP|EPOLLIN })) \
bug("EPOLL_CTL_ADD failed"); while (0)
ADD(signal_fd);
ADD(timer_fd);
@@ -150,10 +165,6 @@ int main(int argc, char *argv[])
for (int i = 0; i < n; i++) {
struct epoll_event *ev = &events[i];
- if (ev->events & EPOLLERR) {
- // fd closed
- close(ev->data.fd);
- }
if (ev->events & EPOLLIN) {
if (ev->data.fd == stdout_fd[0]) {
handle_stdout(ev->data.fd, STDOUT_FILENO);
@@ -173,6 +184,14 @@ int main(int argc, char *argv[])
die("child err: %s", strndupa(buf, nx));
}
}
+ if (ev->events & EPOLLERR || ev->events & EPOLLHUP || ev->events & EPOLLRDHUP) {
+ // fd closed
+ close(ev->data.fd);
+ if (ev->data.fd == child_fd[0])
+ // exec succeeded
+ if (clock_gettime(CLOCK_MONOTONIC, &start_timespec))
+ bug("clock_gettime failed");
+ }
}
}