mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When providing the -parseable-output flag to the swift compiler, it will provide json formatted messages about tasks that run. I added some optional usage information in form of user time, system time and maxrss to the output. This can be used by other tools using the compiler to get some insights about time and memory usage. Since the output does not longer match processes run (in batch mode), I also added a real_pid field so the client could reason about jobs that belong together if needed. rdar://39798231
141 lines
4.7 KiB
C++
141 lines
4.7 KiB
C++
//===--- TaskQueue.inc - Default serial TaskQueue ---------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief This file contains a platform-agnostic implementation of TaskQueue
|
|
/// using the functions from llvm/Support/Program.h.
|
|
///
|
|
/// \note The default implementation of TaskQueue does not support parallel
|
|
/// execution, nor does it support output buffering. As a result,
|
|
/// platform-specific implementations should be preferred.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/TaskQueue.h"
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
|
|
using namespace llvm::sys;
|
|
|
|
namespace swift {
|
|
namespace sys {
|
|
|
|
class Task {
|
|
public:
|
|
/// The path to the executable which this Task will execute.
|
|
const char *ExecPath;
|
|
|
|
/// Any arguments which should be passed during execution.
|
|
ArrayRef<const char *> Args;
|
|
|
|
/// The environment which should be used during execution. If empty,
|
|
/// the current process's environment will be used instead.
|
|
ArrayRef<const char *> Env;
|
|
|
|
/// Context associated with this Task.
|
|
void *Context;
|
|
|
|
Task(const char *ExecPath, ArrayRef<const char *> Args,
|
|
ArrayRef<const char *> Env = llvm::None, void *Context = nullptr)
|
|
: ExecPath(ExecPath), Args(Args), Env(Env), Context(Context) {}
|
|
};
|
|
|
|
} // end namespace sys
|
|
} // end namespace swift
|
|
|
|
bool TaskQueue::supportsBufferingOutput() {
|
|
// The default implementation does not support buffering output.
|
|
return false;
|
|
}
|
|
|
|
bool TaskQueue::supportsParallelExecution() {
|
|
// The default implementation does not support parallel execution.
|
|
return false;
|
|
}
|
|
|
|
unsigned TaskQueue::getNumberOfParallelTasks() const {
|
|
// The default implementation does not support parallel execution.
|
|
return 1;
|
|
}
|
|
|
|
void TaskQueue::addTask(const char *ExecPath, ArrayRef<const char *> Args,
|
|
ArrayRef<const char *> Env, void *Context,
|
|
bool SeparateErrors) {
|
|
// This implementation of TaskQueue ignores SeparateErrors.
|
|
// We need to reference SeparateErrors to avoid warnings, though.
|
|
(void)SeparateErrors;
|
|
std::unique_ptr<Task> T(new Task(ExecPath, Args, Env, Context));
|
|
QueuedTasks.push(std::move(T));
|
|
}
|
|
|
|
bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
|
|
TaskSignalledCallback Signalled) {
|
|
bool ContinueExecution = true;
|
|
|
|
// This implementation of TaskQueue doesn't support parallel execution.
|
|
// We need to reference NumberOfParallelTasks to avoid warnings, though.
|
|
(void)NumberOfParallelTasks;
|
|
|
|
while (!QueuedTasks.empty() && ContinueExecution) {
|
|
std::unique_ptr<Task> T(QueuedTasks.front().release());
|
|
QueuedTasks.pop();
|
|
|
|
SmallVector<const char *, 128> Argv;
|
|
Argv.push_back(T->ExecPath);
|
|
Argv.append(T->Args.begin(), T->Args.end());
|
|
Argv.push_back(0);
|
|
|
|
const char *const *envp = T->Env.empty() ? nullptr : T->Env.data();
|
|
|
|
bool ExecutionFailed = false;
|
|
ProcessInfo PI = ExecuteNoWait(T->ExecPath, Argv.data(),
|
|
(const char **)envp,
|
|
/*redirects*/None, /*memoryLimit*/0,
|
|
/*ErrMsg*/nullptr, &ExecutionFailed);
|
|
if (ExecutionFailed) {
|
|
return true;
|
|
}
|
|
|
|
if (Began) {
|
|
Began(PI.Pid, T->Context);
|
|
}
|
|
|
|
std::string ErrMsg;
|
|
PI = Wait(PI, 0, true, &ErrMsg);
|
|
int ReturnCode = PI.ReturnCode;
|
|
if (ReturnCode == -2) {
|
|
// Wait() returning a return code of -2 indicates the process received
|
|
// a signal during execution.
|
|
if (Signalled) {
|
|
TaskFinishedResponse Response =
|
|
Signalled(PI.Pid, ErrMsg, StringRef(), StringRef(), T->Context, None, TaskProcessInformation(PI.Pid));
|
|
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
|
|
} else {
|
|
// If we don't have a Signalled callback, unconditionally stop.
|
|
ContinueExecution = false;
|
|
}
|
|
} else {
|
|
// Wait() returned a normal return code, so just indicate that the task
|
|
// finished.
|
|
if (Finished) {
|
|
TaskFinishedResponse Response = Finished(PI.Pid, PI.ReturnCode,
|
|
StringRef(), StringRef(), TaskProcessInformation(PI.Pid), T->Context);
|
|
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
|
|
} else if (PI.ReturnCode != 0) {
|
|
ContinueExecution = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return !ContinueExecution;
|
|
}
|