Skip to content

Commit 6d2cf10

Browse files
committed
[llvm-advisor] add compilatoin management and viewer integration
- implement compilation manager - add viewer launcher for web server - improve compilation pipeline
1 parent 3691bdb commit 6d2cf10

File tree

5 files changed

+255
-27
lines changed

5 files changed

+255
-27
lines changed

llvm/tools/llvm-advisor/src/Core/CompilationManager.cpp

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "CompilationManager.h"
1616
#include "../Detection/UnitDetector.h"
1717
#include "../Utils/FileManager.h"
18+
#include "../Utils/UnitMetadata.h"
1819
#include "CommandAnalyzer.h"
1920
#include "DataExtractor.h"
2021
#include "llvm/ADT/DenseSet.h"
@@ -23,6 +24,7 @@
2324
#include "llvm/Support/Path.h"
2425
#include <chrono>
2526
#include <cstdlib>
27+
#include <ctime>
2628
#include <unordered_set>
2729

2830
namespace llvm {
@@ -59,6 +61,23 @@ CompilationManager::CompilationManager(const AdvisorConfig &config)
5961
if (config_.getVerbose()) {
6062
llvm::outs() << "Using temporary directory: " << tempDir_ << "\n";
6163
}
64+
65+
// Initialize unit metadata tracking
66+
llvm::SmallString<256> outputDirPath;
67+
if (llvm::sys::path::is_absolute(config_.getOutputDir())) {
68+
outputDirPath = config_.getOutputDir();
69+
} else {
70+
outputDirPath = initialWorkingDir_;
71+
llvm::sys::path::append(outputDirPath, config_.getOutputDir());
72+
}
73+
74+
unitMetadata_ = std::make_unique<utils::UnitMetadata>(outputDirPath.str());
75+
if (auto Err = unitMetadata_->loadMetadata()) {
76+
if (config_.getVerbose()) {
77+
llvm::errs() << "Failed to load metadata: "
78+
<< llvm::toString(std::move(Err)) << "\n";
79+
}
80+
}
6281
}
6382

6483
CompilationManager::~CompilationManager() {
@@ -95,6 +114,9 @@ llvm::Expected<int> CompilationManager::executeWithDataCollection(
95114
llvm::SmallVector<std::unique_ptr<CompilationUnit>, 4> units;
96115
for (auto &unitInfo : *detectedUnits) {
97116
units.push_back(std::make_unique<CompilationUnit>(unitInfo, tempDir_));
117+
118+
// Register unit in metadata tracker
119+
unitMetadata_->registerUnit(unitInfo.name);
98120
}
99121

100122
// Scan existing files before compilation
@@ -119,6 +141,17 @@ llvm::Expected<int> CompilationManager::executeWithDataCollection(
119141
llvm::errs() << "Data extraction failed: "
120142
<< llvm::toString(std::move(Err)) << "\n";
121143
}
144+
// Mark unit as failed if data extraction fails
145+
unitMetadata_->updateUnitStatus(unit->getName(), "failed");
146+
} else {
147+
// Update unit metadata with file counts and artifact types
148+
const auto &generatedFiles = unit->getAllGeneratedFiles();
149+
size_t totalFiles = 0;
150+
for (const auto &category : generatedFiles) {
151+
totalFiles += category.second.size();
152+
unitMetadata_->addArtifactType(unit->getName(), category.first);
153+
}
154+
unitMetadata_->updateUnitFileCount(unit->getName(), totalFiles);
122155
}
123156
}
124157

@@ -128,6 +161,23 @@ llvm::Expected<int> CompilationManager::executeWithDataCollection(
128161
llvm::errs() << "Output organization failed: "
129162
<< llvm::toString(std::move(Err)) << "\n";
130163
}
164+
// Mark units as failed if output organization fails
165+
for (auto &unit : units) {
166+
unitMetadata_->updateUnitStatus(unit->getName(), "failed");
167+
}
168+
} else {
169+
// Mark units as completed on successful organization
170+
for (auto &unit : units) {
171+
unitMetadata_->updateUnitStatus(unit->getName(), "completed");
172+
}
173+
}
174+
175+
// Save metadata to disk
176+
if (auto Err = unitMetadata_->saveMetadata()) {
177+
if (config_.getVerbose()) {
178+
llvm::errs() << "Failed to save metadata: "
179+
<< llvm::toString(std::move(Err)) << "\n";
180+
}
131181
}
132182

133183
// Clean up leaked files from source directory
@@ -208,22 +258,34 @@ llvm::Error CompilationManager::organizeOutput(
208258
llvm::outs() << "Output directory: " << outputDir << "\n";
209259
}
210260

261+
// Generate timestamp for this compilation run
262+
auto now = std::chrono::system_clock::now();
263+
auto time_t = std::chrono::system_clock::to_time_t(now);
264+
auto tm = *std::localtime(&time_t);
265+
266+
char timestampStr[20];
267+
std::strftime(timestampStr, sizeof(timestampStr), "%Y%m%d_%H%M%S", &tm);
268+
211269
// Move collected files to organized structure
212270
for (const auto &unit : units) {
213-
std::string unitDir = outputDir + "/" + unit->getName();
214-
215-
// Remove existing unit directory if it exists
216-
if (llvm::sys::fs::exists(unitDir)) {
217-
if (auto EC = llvm::sys::fs::remove_directories(unitDir)) {
218-
if (config_.getVerbose()) {
219-
llvm::errs() << "Warning: Could not remove existing unit directory: "
220-
<< unitDir << "\n";
221-
}
222-
}
271+
// Create base unit directory if it doesn't exist
272+
std::string baseUnitDir = outputDir + "/" + unit->getName();
273+
llvm::sys::fs::create_directories(baseUnitDir);
274+
275+
// Create timestamped run directory
276+
std::string runDirName = unit->getName() + "_" + std::string(timestampStr);
277+
std::string unitDir = baseUnitDir + "/" + runDirName;
278+
279+
if (config_.getVerbose()) {
280+
llvm::outs() << "Creating run directory: " << unitDir << "\n";
223281
}
224282

225-
// Create fresh unit directory
283+
// Create timestamped run directory
226284
if (auto EC = llvm::sys::fs::create_directories(unitDir)) {
285+
if (config_.getVerbose()) {
286+
llvm::errs() << "Warning: Could not create run directory: " << unitDir
287+
<< "\n";
288+
}
227289
continue; // Skip if we can't create the directory
228290
}
229291

llvm/tools/llvm-advisor/src/Core/CompilationManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "../Config/AdvisorConfig.h"
1818
#include "../Utils/FileClassifier.h"
19+
#include "../Utils/UnitMetadata.h"
1920
#include "BuildExecutor.h"
2021
#include "CompilationUnit.h"
2122
#include "llvm/ADT/DenseSet.h"
@@ -54,6 +55,7 @@ class CompilationManager {
5455
BuildExecutor buildExecutor_;
5556
std::string tempDir_;
5657
std::string initialWorkingDir_;
58+
std::unique_ptr<utils::UnitMetadata> unitMetadata_;
5759
};
5860

5961
} // namespace advisor
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===---------------- ViewerLauncher.cpp - LLVM Advisor ------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "ViewerLauncher.h"
10+
#include "llvm/Support/FileSystem.h"
11+
#include "llvm/Support/Path.h"
12+
#include "llvm/Support/Program.h"
13+
#include "llvm/Support/raw_ostream.h"
14+
15+
using namespace llvm;
16+
using namespace llvm::advisor;
17+
18+
Expected<std::string> ViewerLauncher::findPythonExecutable() {
19+
std::vector<std::string> candidates = {"python3", "python"};
20+
21+
for (const auto &candidate : candidates) {
22+
if (auto path = sys::findProgramByName(candidate)) {
23+
return *path;
24+
}
25+
}
26+
27+
return createStringError(
28+
std::make_error_code(std::errc::no_such_file_or_directory),
29+
"Python executable not found. Please install Python 3.");
30+
}
31+
32+
Expected<std::string> ViewerLauncher::getViewerScript() {
33+
SmallString<256> scriptPath;
34+
35+
// Try to find the server script relative to the executable
36+
auto mainExecutable = sys::fs::getMainExecutable(nullptr, nullptr);
37+
if (mainExecutable.empty()) {
38+
return createStringError(
39+
std::make_error_code(std::errc::no_such_file_or_directory),
40+
"Cannot determine executable path");
41+
}
42+
43+
// Try: relative to binary (development/build tree)
44+
sys::path::append(scriptPath, sys::path::parent_path(mainExecutable));
45+
sys::path::append(scriptPath, "..");
46+
sys::path::append(scriptPath, "tools");
47+
sys::path::append(scriptPath, "webserver");
48+
sys::path::append(scriptPath, "server.py");
49+
50+
if (sys::fs::exists(scriptPath)) {
51+
return scriptPath.str().str();
52+
}
53+
54+
// Try: relative to binary (same directory as executable)
55+
scriptPath.clear();
56+
sys::path::append(scriptPath, sys::path::parent_path(mainExecutable));
57+
sys::path::append(scriptPath, "tools");
58+
sys::path::append(scriptPath, "webserver");
59+
sys::path::append(scriptPath, "server.py");
60+
61+
if (sys::fs::exists(scriptPath)) {
62+
return scriptPath.str().str();
63+
}
64+
65+
// Try: installed location
66+
scriptPath.clear();
67+
sys::path::append(scriptPath, sys::path::parent_path(mainExecutable));
68+
sys::path::append(scriptPath, "..");
69+
sys::path::append(scriptPath, "share");
70+
sys::path::append(scriptPath, "llvm-advisor");
71+
sys::path::append(scriptPath, "tools");
72+
sys::path::append(scriptPath, "webserver");
73+
sys::path::append(scriptPath, "server.py");
74+
75+
if (sys::fs::exists(scriptPath)) {
76+
return scriptPath.str().str();
77+
}
78+
79+
return createStringError(
80+
std::make_error_code(std::errc::no_such_file_or_directory),
81+
"Web server script not found. Please ensure tools/webserver/server.py "
82+
"exists.");
83+
}
84+
85+
Expected<int> ViewerLauncher::launch(const std::string &outputDir, int port) {
86+
auto pythonOrErr = findPythonExecutable();
87+
if (!pythonOrErr) {
88+
return pythonOrErr.takeError();
89+
}
90+
91+
auto scriptOrErr = getViewerScript();
92+
if (!scriptOrErr) {
93+
return scriptOrErr.takeError();
94+
}
95+
96+
// Verify output directory exists and has data
97+
if (!sys::fs::exists(outputDir)) {
98+
return createStringError(
99+
std::make_error_code(std::errc::no_such_file_or_directory),
100+
"Output directory does not exist: " + outputDir);
101+
}
102+
103+
std::vector<StringRef> args = {*pythonOrErr, *scriptOrErr,
104+
"--data-dir", outputDir,
105+
"--port", std::to_string(port)};
106+
107+
// Execute the Python web server
108+
int result = sys::ExecuteAndWait(*pythonOrErr, args);
109+
110+
if (result != 0) {
111+
return createStringError(std::make_error_code(std::errc::io_error),
112+
"Web server failed with exit code: " +
113+
std::to_string(result));
114+
}
115+
116+
return result;
117+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===---------------- ViewerLauncher.h - LLVM Advisor --------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// ViewerLauncher handles launching the Python web server to visualize
10+
// the collected compilation data.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_ADVISOR_CORE_VIEWERLAUNCHER_H
15+
#define LLVM_ADVISOR_CORE_VIEWERLAUNCHER_H
16+
17+
#include "llvm/Support/Error.h"
18+
#include <string>
19+
20+
namespace llvm {
21+
namespace advisor {
22+
23+
class ViewerLauncher {
24+
public:
25+
static llvm::Expected<int> launch(const std::string &outputDir,
26+
int port = 8000);
27+
28+
private:
29+
static llvm::Expected<std::string> findPythonExecutable();
30+
static llvm::Expected<std::string> getViewerScript();
31+
};
32+
33+
} // namespace advisor
34+
} // namespace llvm
35+
36+
#endif // LLVM_ADVISOR_CORE_VIEWERLAUNCHER_H

0 commit comments

Comments
 (0)