blob: 672bad97ac3e63c44afb629b2620872aef146fc8 [file] [log] [blame]
//===-- BuildEngineTrace.cpp ----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 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 "BuildEngineTrace.h"
#include "llbuild/Core/BuildEngine.h"
#include <cassert>
#include <cstdio>
#include <cstring>
#include <errno.h>
using namespace llbuild;
using namespace llbuild::core;
BuildEngineTrace::BuildEngineTrace() {}
BuildEngineTrace::~BuildEngineTrace() {}
bool BuildEngineTrace::open(const std::string& filename,
std::string* error_out) {
assert(!isOpen());
FILE *fp = fopen(filename.c_str(), "wb");
if (!fp) {
*error_out = "unable to open '" + filename + "' (" +
::strerror(errno) + ")";
return false;
}
outputPtr = fp;
assert(isOpen());
// Write the opening header.
fprintf(fp, "[\n");
return true;
}
bool BuildEngineTrace::close(std::string* error_out) {
assert(isOpen());
FILE *fp = static_cast<FILE*>(outputPtr);
// Write the footer.
fprintf(fp, "]\n");
bool success = fclose(fp) == 0;
outputPtr = nullptr;
assert(!isOpen());
if (!success) {
*error_out = "unable to close file";
return false;
}
return true;
}
#pragma mark - Tracing APIs
const char* BuildEngineTrace::getTaskName(const Task* task) {
FILE *fp = static_cast<FILE*>(outputPtr);
// See if we have already assigned a name.
auto it = taskNames.find(task);
if (it != taskNames.end())
return it->second.c_str();
// Otherwise, create a name.
char name[64];
sprintf(name, "T%d", ++numNamedTasks);
auto result = taskNames.emplace(task, name);
// Report the newly seen rule.
fprintf(fp, "{ \"new-task\", \"%s\" },\n", name);
return result.first->second.c_str();
}
const char* BuildEngineTrace::getRuleName(const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
// See if we have already assigned a name.
auto it = ruleNames.find(rule);
if (it != ruleNames.end())
return it->second.c_str();
// Otherwise, create a name.
char name[64];
sprintf(name, "R%d", ++numNamedRules);
auto result = ruleNames.emplace(rule, name);
// Report the newly seen rule.
fprintf(fp, "{ \"new-rule\", \"%s\", \"%s\" },\n", name, rule->key.c_str());
return result.first->second.c_str();
}
void BuildEngineTrace::buildStarted() {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"build-started\" },\n");
}
void BuildEngineTrace::handlingBuildInputRequest(const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"handling-build-input-request\", \"%s\" },\n",
getRuleName(rule));
}
void BuildEngineTrace::createdTaskForRule(const Task* task,
const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"created-task-for-rule\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule));
}
void BuildEngineTrace::handlingTaskInputRequest(const Task* task,
const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"handling-task-input-request\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule));
}
void BuildEngineTrace::pausedInputRequestForRuleScan(const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"paused-input-request-for-rule-scan\", \"%s\" },\n",
getRuleName(rule));
}
void BuildEngineTrace::readyingTaskInputRequest(const Task* task,
const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"readying-task-input-request\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule));
}
void BuildEngineTrace::addedRulePendingTask(const Rule* rule,
const Task* task) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"added-rule-pending-task\", \"%s\", \"%s\" },\n",
getRuleName(rule), getTaskName(task));
}
void BuildEngineTrace::completedTaskInputRequest(const Task* task,
const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"completed-task-input-request\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule));
}
void BuildEngineTrace::updatedTaskWaitCount(const Task* task,
unsigned waitCount) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"updated-task-wait-count\", \"%s\", %d },\n",
getTaskName(task), waitCount);
}
void BuildEngineTrace::unblockedTask(const Task* task) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"unblocked-task\", \"%s\" },\n", getTaskName(task));
}
void BuildEngineTrace::readiedTask(const Task* task, const Rule* rule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"readied-task\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule));
}
void BuildEngineTrace::finishedTask(const Task* task, const Rule* rule,
bool wasChanged) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"finished-task\", \"%s\", \"%s\", \"%s\" },\n",
getTaskName(task), getRuleName(rule),
wasChanged ? "changed" : "unchanged");
// Delete the task entry, as it could be reused.
taskNames.erase(taskNames.find(task));
}
void BuildEngineTrace::buildEnded() {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"build-ended\" },\n");
}
#pragma mark - Dependency Scanning Tracing APIs
void BuildEngineTrace::checkingRuleNeedsToRun(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"checking-rule-needs-to-run\", \"%s\" },\n",
getRuleName(forRule));
}
void BuildEngineTrace::ruleScheduledForScanning(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, ("{ \"rule-scheduled-for-scanning\", \"%s\"},\n"),
getRuleName(forRule));
}
void BuildEngineTrace::ruleScanningNextInput(const Rule* forRule,
const Rule* inputRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, ("{ \"rule-scanning-next-input\", \"%s\", \"%s\" },\n"),
getRuleName(forRule), getRuleName(inputRule));
}
void
BuildEngineTrace::ruleScanningDeferredOnInput(const Rule* forRule,
const Rule* inputRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, ("{ \"rule-scanning-deferred-on-input\", \"%s\", \"%s\" },\n"),
getRuleName(forRule), getRuleName(inputRule));
}
void
BuildEngineTrace::ruleScanningDeferredOnTask(const Rule* forRule,
const Task* inputTask) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, ("{ \"rule-scanning-deferred-on-task\", \"%s\", \"%s\" },\n"),
getRuleName(forRule), getTaskName(inputTask));
}
void BuildEngineTrace::ruleNeedsToRunBecauseNeverBuilt(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"rule-needs-to-run\", \"%s\", \"never-built\" },\n",
getRuleName(forRule));
}
void BuildEngineTrace::ruleNeedsToRunBecauseInvalidValue(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"rule-needs-to-run\", \"%s\", \"invalid-value\" },\n",
getRuleName(forRule));
}
void
BuildEngineTrace::ruleNeedsToRunBecauseInputMissing(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"rule-needs-to-run\", \"%s\", \"input-missing\" },\n",
getRuleName(forRule));
}
void
BuildEngineTrace::ruleNeedsToRunBecauseInputRebuilt(const Rule* forRule,
const Rule* inputRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, ("{ \"rule-needs-to-run\", \"%s\", "
"\"input-rebuilt\", \"%s\" },\n"),
getRuleName(forRule), getRuleName(inputRule));
}
void BuildEngineTrace::ruleDoesNotNeedToRun(const Rule* forRule) {
FILE *fp = static_cast<FILE*>(outputPtr);
fprintf(fp, "{ \"rule-does-not-need-to-run\", \"%s\" },\n",
getRuleName(forRule));
}