| //===--- XpcTracing.cpp ---------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "sourcekitd/XpcTracing.h" |
| |
| #include "swift/Frontend/Frontend.h" |
| |
| #include "llvm/Support/TimeValue.h" |
| #include "llvm/Support/YAMLTraits.h" |
| |
| #include <xpc/xpc.h> |
| |
| using namespace sourcekitd; |
| using namespace sourcekitd::trace; |
| using namespace llvm; |
| |
| |
| |
| //===----------------------------------------------------------------------===// |
| // General |
| //===----------------------------------------------------------------------===// |
| |
| static std::atomic<uint64_t> operation_id(0); |
| static uint64_t tracing_session = llvm::sys::TimeValue::now().msec(); |
| |
| uint64_t trace::getTracingSession() { |
| return tracing_session; |
| } |
| |
| static void append(xpc_object_t Contents, uint64_t Value) { |
| xpc_array_set_uint64(Contents, XPC_ARRAY_APPEND, Value); |
| } |
| |
| static void append(xpc_object_t Contents, ActionKind Value) { |
| append(Contents, static_cast<uint64_t>(Value)); |
| } |
| |
| static void append(xpc_object_t Contents, OperationKind Value) { |
| append(Contents, static_cast<uint64_t>(Value)); |
| } |
| |
| static void append(xpc_object_t Contents, llvm::StringRef Value) { |
| xpc_array_set_string(Contents, XPC_ARRAY_APPEND, Value.data()); |
| } |
| |
| static void append(xpc_object_t Contents, const StringPairs &Files) { |
| append(Contents, Files.size()); |
| std::for_each(Files.begin(), Files.end(), |
| [&] (const std::pair<std::string, std::string> &File) { |
| append(Contents, File.first); |
| append(Contents, File.second); |
| }); |
| } |
| |
| template <typename U> |
| struct llvm::yaml::SequenceTraits<std::vector<U>> { |
| static size_t size(IO &Io, std::vector<U> &Vector) { |
| return Vector.size(); |
| } |
| static U &element(IO &Io, std::vector<U> &Vector, size_t Index) { |
| return Vector[Index]; |
| } |
| }; |
| |
| template <> |
| struct llvm::yaml::MappingTraits<SwiftArguments> { |
| static void mapping(IO &Io, SwiftArguments &Args) { |
| |
| Io.mapOptional("PrimaryFile", Args.PrimaryFile, std::string()); |
| Io.mapRequired("CompilerArgs", Args.Args); |
| } |
| }; |
| |
| static std::string serializeCompilerArguments(const SwiftArguments &Args) { |
| // Serialize compiler instance |
| std::string OptionsAsYaml; |
| llvm::raw_string_ostream OptionsStream(OptionsAsYaml); |
| llvm::yaml::Output YamlOutput(OptionsStream); |
| YamlOutput << const_cast<SwiftArguments &>(Args); |
| OptionsStream.flush(); |
| return OptionsAsYaml; |
| } |
| |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Trace consumer |
| //===----------------------------------------------------------------------===// |
| |
| class XpcTraceConsumer : public SourceKit::trace::TraceConsumer { |
| public: |
| virtual ~XpcTraceConsumer() = default; |
| |
| // Operation previously started with startXXX has finished |
| virtual void operationFinished(uint64_t OpId) override; |
| |
| // Trace start of SourceKit operation |
| virtual void operationStarted(uint64_t OpId, OperationKind OpKind, |
| const SwiftInvocation &Inv, |
| const StringPairs &OpArgs) override; |
| }; |
| |
| // Trace start of SourceKit operation |
| void XpcTraceConsumer::operationStarted(uint64_t OpId, |
| OperationKind OpKind, |
| const SwiftInvocation &Inv, |
| const StringPairs &OpArgs) { |
| xpc_object_t Contents = xpc_array_create(nullptr, 0); |
| append(Contents, ActionKind::OperationStarted); |
| append(Contents, OpId); |
| append(Contents, OpKind); |
| append(Contents, serializeCompilerArguments(Inv.Args)); |
| append(Contents, Inv.Files); |
| append(Contents, OpArgs); |
| trace::sendTraceMessage(Contents); |
| } |
| |
| // Operation previously started with startXXX has finished |
| void XpcTraceConsumer::operationFinished(uint64_t OpId) { |
| xpc_object_t Contents = xpc_array_create(nullptr, 0); |
| append(Contents, trace::ActionKind::OperationFinished); |
| append(Contents, OpId); |
| trace::sendTraceMessage(Contents); |
| } |
| |
| static XpcTraceConsumer Instance; |
| |
| void trace::initialize() { |
| SourceKit::trace::registerConsumer(&Instance); |
| } |
| |