Files
swift-mirror/tools/SourceKit/lib/Support/Tracing.cpp
Ben Langmuir 79d641d89b [sourcekit] Add optional compile notifications
When enabled, send a notification before/after every "compilation",
which for now means `performSema`. This piggy-backs and modifies some
existing code that we had for "tracing" operations in sourcekitd that
unfortunately was untested.  At least now some of the basic parts are
tested via the new notifications.

Part of rdar://38438512
2018-03-29 14:59:30 -07:00

89 lines
3.0 KiB
C++

//===--- Tracing.cpp ------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "SourceKit/Support/Tracing.h"
#include "swift/Frontend/Frontend.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/YAMLTraits.h"
using namespace SourceKit;
using namespace llvm;
using swift::OptionSet;
static llvm::sys::Mutex consumersLock;
// Must hold consumersLock to access.
static std::vector<trace::TraceConsumer *> consumers;
// Must hold consumersLock to modify, but can be read any time.
static std::atomic<uint64_t> tracedOperations;
//===----------------------------------------------------------------------===//
// Trace commands
//===----------------------------------------------------------------------===//
// Is tracing enabled
bool trace::anyEnabled() { return static_cast<bool>(tracedOperations); }
bool trace::enabled(OperationKind op) {
return OptionSet<OperationKind>(tracedOperations).contains(op);
}
// Trace start of perform sema call, returns OpId
uint64_t trace::startOperation(trace::OperationKind OpKind,
const trace::SwiftInvocation &Inv,
const trace::StringPairs &OpArgs) {
static std::atomic<uint64_t> operationId(0);
auto OpId = ++operationId;
if (trace::anyEnabled()) {
llvm::sys::ScopedLock L(consumersLock);
for (auto *consumer : consumers) {
consumer->operationStarted(OpId, OpKind, Inv, OpArgs);
}
}
return OpId;
}
// Operation previously started with startXXX has finished
void trace::operationFinished(uint64_t OpId, trace::OperationKind OpKind) {
if (trace::anyEnabled()) {
llvm::sys::ScopedLock L(consumersLock);
for (auto *consumer : consumers) {
consumer->operationFinished(OpId, OpKind);
}
}
}
// Must be called with consumersLock held.
static void updateTracedOperations() {
OptionSet<trace::OperationKind> operations;
for (auto *consumer : consumers) {
operations |= consumer->desiredOperations();
}
// It is safe to store without a compare, because writers hold consumersLock.
tracedOperations.store(uint64_t(operations), std::memory_order_relaxed);
}
// Register trace consumer
void trace::registerConsumer(trace::TraceConsumer *Consumer) {
llvm::sys::ScopedLock L(consumersLock);
consumers.push_back(Consumer);
updateTracedOperations();
}
void trace::unregisterConsumer(trace::TraceConsumer *Consumer) {
llvm::sys::ScopedLock L(consumersLock);
consumers.erase(std::remove(consumers.begin(), consumers.end(), Consumer),
consumers.end());
updateTracedOperations();
}