diff options
author | ruperts <ruperts@google.com> | 2017-11-28 21:17:48 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2017-11-28 21:19:26 -0800 |
commit | b394da457e9e1f717581b00926e811f6c9e018f3 (patch) | |
tree | de17a49a8222a84ca26a477a0a1f42300004471f /src/main/tools | |
parent | 85d69f2397d7b54fa8b8c69b7bc9ec6d36cb1d49 (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/BUILD | 5 | ||||
-rw-r--r-- | src/main/tools/process-tools.cc | 68 | ||||
-rw-r--r-- | src/main/tools/process-tools.h | 9 | ||||
-rw-r--r-- | src/main/tools/process-wrapper-legacy.cc | 11 | ||||
-rw-r--r-- | src/main/tools/process-wrapper-options.cc | 14 | ||||
-rw-r--r-- | src/main/tools/process-wrapper-options.h | 2 |
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; }; |