aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/tools
diff options
context:
space:
mode:
authorGravatar ruperts <ruperts@google.com>2017-11-28 21:17:48 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2017-11-28 21:19:26 -0800
commitb394da457e9e1f717581b00926e811f6c9e018f3 (patch)
treede17a49a8222a84ca26a477a0a1f42300004471f /src/main/tools
parent85d69f2397d7b54fa8b8c69b7bc9ec6d36cb1d49 (diff)
Make process-wrapper output execution statistics for executed commands.
For example, it now outputs resource usage statistics like the amount of user time and system time used. RELNOTES: None PiperOrigin-RevId: 177263221
Diffstat (limited to 'src/main/tools')
-rw-r--r--src/main/tools/BUILD5
-rw-r--r--src/main/tools/process-tools.cc68
-rw-r--r--src/main/tools/process-tools.h9
-rw-r--r--src/main/tools/process-wrapper-legacy.cc11
-rw-r--r--src/main/tools/process-wrapper-options.cc14
-rw-r--r--src/main/tools/process-wrapper-options.h2
6 files changed, 103 insertions, 6 deletions
diff --git a/src/main/tools/BUILD b/src/main/tools/BUILD
index dc788a4c54..9319b0a0d3 100644
--- a/src/main/tools/BUILD
+++ b/src/main/tools/BUILD
@@ -10,7 +10,10 @@ cc_library(
name = "process-tools",
srcs = ["process-tools.cc"],
hdrs = ["process-tools.h"],
- deps = [":logging"],
+ deps = [
+ ":logging",
+ "//src/main/protobuf:execution_statistics_cc_proto",
+ ],
)
cc_binary(
diff --git a/src/main/tools/process-tools.cc b/src/main/tools/process-tools.cc
index 7dd623fa76..45aa6b7346 100644
--- a/src/main/tools/process-tools.cc
+++ b/src/main/tools/process-tools.cc
@@ -21,12 +21,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <memory>
+
+#include "src/main/protobuf/execution_statistics.pb.h"
#include "src/main/tools/logging.h"
int SwitchToEuid() {
@@ -178,8 +182,70 @@ int WaitChild(pid_t pid) {
} while (err == -1 && errno == EINTR);
if (err == -1) {
- DIE("wait");
+ DIE("waitpid");
}
return status;
}
+
+int WaitChildWithRusage(pid_t pid, struct rusage *rusage) {
+ int err, status;
+
+ do {
+ err = wait4(pid, &status, 0, rusage);
+ } while (err == -1 && errno == EINTR);
+
+ if (err == -1) {
+ DIE("wait4");
+ }
+
+ return status;
+}
+
+static std::unique_ptr<tools::protos::ExecutionStatistics>
+CreateExecutionStatisticsProto(struct rusage *rusage) {
+ std::unique_ptr<tools::protos::ExecutionStatistics> execution_statistics(
+ new tools::protos::ExecutionStatistics);
+
+ tools::protos::ResourceUsage *resource_usage =
+ execution_statistics->mutable_resource_usage();
+
+ resource_usage->set_utime_sec(rusage->ru_utime.tv_sec);
+ resource_usage->set_utime_usec(rusage->ru_utime.tv_usec);
+ resource_usage->set_stime_sec(rusage->ru_stime.tv_sec);
+ resource_usage->set_stime_usec(rusage->ru_stime.tv_usec);
+ resource_usage->set_maxrss(rusage->ru_maxrss);
+ resource_usage->set_ixrss(rusage->ru_ixrss);
+ resource_usage->set_idrss(rusage->ru_idrss);
+ resource_usage->set_isrss(rusage->ru_isrss);
+ resource_usage->set_minflt(rusage->ru_minflt);
+ resource_usage->set_majflt(rusage->ru_majflt);
+ resource_usage->set_nswap(rusage->ru_nswap);
+ resource_usage->set_inblock(rusage->ru_inblock);
+ resource_usage->set_oublock(rusage->ru_oublock);
+ resource_usage->set_msgsnd(rusage->ru_msgsnd);
+ resource_usage->set_msgrcv(rusage->ru_msgrcv);
+ resource_usage->set_nsignals(rusage->ru_nsignals);
+ resource_usage->set_nvcsw(rusage->ru_nvcsw);
+ resource_usage->set_nivcsw(rusage->ru_nivcsw);
+
+ return execution_statistics;
+}
+
+// Write execution statistics (e.g. resource usage) to a file.
+void WriteStatsToFile(struct rusage *rusage, const std::string &stats_path) {
+ const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND;
+ int fd_out = open(stats_path.c_str(), flags, 0666);
+ if (fd_out < 0) {
+ DIE("open(%s)", stats_path.c_str());
+ }
+
+ std::unique_ptr<tools::protos::ExecutionStatistics> execution_statistics =
+ CreateExecutionStatisticsProto(rusage);
+
+ if (!execution_statistics->SerializeToFileDescriptor(fd_out)) {
+ DIE("could not write resource usage to file: %s", stats_path.c_str());
+ }
+
+ close(fd_out);
+}
diff --git a/src/main/tools/process-tools.h b/src/main/tools/process-tools.h
index 8f122f6b35..6f6f4946f9 100644
--- a/src/main/tools/process-tools.h
+++ b/src/main/tools/process-tools.h
@@ -55,7 +55,14 @@ void ClearSignalMask();
void SetTimeout(double timeout_secs);
// Wait for "pid" to exit and return its exit code.
-// "name" is used for the error message only.
int WaitChild(pid_t pid);
+// Wait for "pid" to exit and return its exit code.
+// Resource usage is returned in "rusage" regardless of the exit status of the
+// child process.
+int WaitChildWithRusage(pid_t pid, struct rusage *rusage);
+
+// Write execution statistics to a file.
+void WriteStatsToFile(struct rusage *rusage, const std::string &stats_path);
+
#endif // PROCESS_TOOLS_H__
diff --git a/src/main/tools/process-wrapper-legacy.cc b/src/main/tools/process-wrapper-legacy.cc
index ac7b3ec5be..03fdec5448 100644
--- a/src/main/tools/process-wrapper-legacy.cc
+++ b/src/main/tools/process-wrapper-legacy.cc
@@ -17,7 +17,9 @@
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -68,7 +70,14 @@ void LegacyProcessWrapper::WaitForChild() {
SetTimeout(opt.timeout_secs);
}
- int status = WaitChild(child_pid);
+ int status;
+ if (!opt.stats_path.empty()) {
+ struct rusage child_rusage;
+ status = WaitChildWithRusage(child_pid, &child_rusage);
+ WriteStatsToFile(&child_rusage, opt.stats_path);
+ } else {
+ status = WaitChild(child_pid);
+ }
// The child is done for, but may have grandchildren that we still have to
// kill.
diff --git a/src/main/tools/process-wrapper-options.cc b/src/main/tools/process-wrapper-options.cc
index 94b66d1536..82384113c9 100644
--- a/src/main/tools/process-wrapper-options.cc
+++ b/src/main/tools/process-wrapper-options.cc
@@ -45,6 +45,7 @@ static void Usage(char *program_name, const char *fmt, ...) {
"before killing the child with SIGKILL\n"
" -o/--stdout <file> redirect stdout to a file\n"
" -e/--stderr <file> redirect stderr to a file\n"
+ " -s/--stats <file> if set, write stats in protobuf format to a file\n"
" -d/--debug if set, debug info will be printed\n"
" -- command to run inside sandbox, followed by arguments\n");
exit(EXIT_FAILURE);
@@ -58,14 +59,15 @@ static void ParseCommandLine(const std::vector<char *> &args) {
{"kill_delay", required_argument, 0, 'k'},
{"stdout", required_argument, 0, 'o'},
{"stderr", required_argument, 0, 'e'},
+ {"stats", required_argument, 0, 's'},
{"debug", no_argument, 0, 'd'},
{0, 0, 0, 0}};
extern char *optarg;
extern int optind, optopt;
int c;
- while ((c = getopt_long(args.size(), args.data(), "+:t:k:o:e:d", long_options,
- nullptr)) != -1) {
+ while ((c = getopt_long(args.size(), args.data(), "+:t:k:o:e:s:d",
+ long_options, nullptr)) != -1) {
switch (c) {
case 't':
if (sscanf(optarg, "%lf", &opt.timeout_secs) != 1) {
@@ -93,6 +95,14 @@ static void ParseCommandLine(const std::vector<char *> &args) {
"Cannot redirect stderr (-e) to more than one destination.");
}
break;
+ case 's':
+ if (opt.stats_path.empty()) {
+ opt.stats_path.assign(optarg);
+ } else {
+ Usage(args.front(),
+ "Cannot write stats (-s) to more than one destination.");
+ }
+ break;
case 'd':
opt.debug = true;
break;
diff --git a/src/main/tools/process-wrapper-options.h b/src/main/tools/process-wrapper-options.h
index cb173027e2..e8156a801e 100644
--- a/src/main/tools/process-wrapper-options.h
+++ b/src/main/tools/process-wrapper-options.h
@@ -30,6 +30,8 @@ struct Options {
std::string stderr_path;
// Whether to print debugging messages (-d)
bool debug;
+ // Where to write stats, in protobuf format (-s)
+ std::string stats_path;
// Command to run (--)
std::vector<char *> args;
};