Skip to content

Commit bb894b9

Browse files
committed
[lldb] Extract reproducer providers & co into their own header.
Extract all the provider related logic from Reproducer.h and move it into its own header ReproducerProvider.h. These classes are seeing most of the development these days and this reorganization reduces incremental compilation from ~520 to ~110 files when making changes to the new header.
1 parent 8e06bf6 commit bb894b9

File tree

18 files changed

+506
-452
lines changed

18 files changed

+506
-452
lines changed

lldb/include/lldb/Core/IOHandler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "lldb/Utility/ConstString.h"
1616
#include "lldb/Utility/Flags.h"
1717
#include "lldb/Utility/Predicate.h"
18-
#include "lldb/Utility/Reproducer.h"
1918
#include "lldb/Utility/Stream.h"
2019
#include "lldb/Utility/StringList.h"
2120
#include "lldb/lldb-defines.h"
@@ -32,6 +31,9 @@
3231

3332
namespace lldb_private {
3433
class Debugger;
34+
namespace repro {
35+
class DataRecorder;
36+
}
3537
}
3638

3739
namespace curses {

lldb/include/lldb/Utility/GDBRemote.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#define LLDB_UTILITY_GDBREMOTE_H
1111

1212
#include "lldb/Utility/FileSpec.h"
13-
#include "lldb/Utility/Reproducer.h"
13+
#include "lldb/Utility/ReproducerProvider.h"
1414
#include "lldb/Utility/StreamString.h"
1515
#include "lldb/lldb-enumerations.h"
1616
#include "lldb/lldb-public.h"

lldb/include/lldb/Utility/ProcessInfo.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "lldb/Utility/Environment.h"
1515
#include "lldb/Utility/FileSpec.h"
1616
#include "lldb/Utility/NameMatches.h"
17-
#include "lldb/Utility/Reproducer.h"
1817
#include "llvm/Support/YAMLTraits.h"
1918
#include <vector>
2019

@@ -217,40 +216,7 @@ class ProcessInstanceInfoMatch {
217216
};
218217

219218
namespace repro {
220-
class ProcessInfoRecorder : public AbstractRecorder {
221-
public:
222-
ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec)
223-
: AbstractRecorder(filename, ec) {}
224-
225-
static llvm::Expected<std::unique_ptr<ProcessInfoRecorder>>
226-
Create(const FileSpec &filename);
227-
228-
void Record(const ProcessInstanceInfoList &process_infos);
229-
};
230-
231-
class ProcessInfoProvider : public repro::Provider<ProcessInfoProvider> {
232-
public:
233-
struct Info {
234-
static const char *name;
235-
static const char *file;
236-
};
237-
238-
ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {}
239-
240-
ProcessInfoRecorder *GetNewProcessInfoRecorder();
241-
242-
void Keep() override;
243-
void Discard() override;
244-
245-
static char ID;
246-
247-
private:
248-
std::unique_ptr<llvm::raw_fd_ostream> m_stream_up;
249-
std::vector<std::unique_ptr<ProcessInfoRecorder>> m_process_info_recorders;
250-
};
251-
252219
llvm::Optional<ProcessInstanceInfoList> GetReplayProcessInstanceInfoList();
253-
254220
} // namespace repro
255221
} // namespace lldb_private
256222

lldb/include/lldb/Utility/Reproducer.h

Lines changed: 1 addition & 299 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "llvm/ADT/DenseMap.h"
1414
#include "llvm/ADT/StringRef.h"
1515
#include "llvm/Support/Error.h"
16-
#include "llvm/Support/FileCollector.h"
16+
#include "llvm/Support/VirtualFileSystem.h"
1717
#include "llvm/Support/YAMLTraits.h"
1818

1919
#include <mutex>
@@ -84,250 +84,6 @@ template <typename ThisProviderT> class Provider : public ProviderBase {
8484
using ProviderBase::ProviderBase; // Inherit constructor.
8585
};
8686

87-
class FileProvider : public Provider<FileProvider> {
88-
public:
89-
struct Info {
90-
static const char *name;
91-
static const char *file;
92-
};
93-
94-
FileProvider(const FileSpec &directory)
95-
: Provider(directory),
96-
m_collector(std::make_shared<llvm::FileCollector>(
97-
directory.CopyByAppendingPathComponent("root").GetPath(),
98-
directory.GetPath())) {}
99-
100-
std::shared_ptr<llvm::FileCollector> GetFileCollector() {
101-
return m_collector;
102-
}
103-
104-
void RecordInterestingDirectory(const llvm::Twine &dir);
105-
void RecordInterestingDirectoryRecursive(const llvm::Twine &dir);
106-
107-
void Keep() override {
108-
auto mapping = GetRoot().CopyByAppendingPathComponent(Info::file);
109-
// Temporary files that are removed during execution can cause copy errors.
110-
if (auto ec = m_collector->copyFiles(/*stop_on_error=*/false))
111-
return;
112-
m_collector->writeMapping(mapping.GetPath());
113-
}
114-
115-
static char ID;
116-
117-
private:
118-
std::shared_ptr<llvm::FileCollector> m_collector;
119-
};
120-
121-
/// Provider for the LLDB version number.
122-
///
123-
/// When the reproducer is kept, it writes the lldb version to a file named
124-
/// version.txt in the reproducer root.
125-
class VersionProvider : public Provider<VersionProvider> {
126-
public:
127-
VersionProvider(const FileSpec &directory) : Provider(directory) {}
128-
struct Info {
129-
static const char *name;
130-
static const char *file;
131-
};
132-
void SetVersion(std::string version) {
133-
assert(m_version.empty());
134-
m_version = std::move(version);
135-
}
136-
void Keep() override;
137-
std::string m_version;
138-
static char ID;
139-
};
140-
141-
/// Abstract provider to storing directory paths.
142-
template <typename T> class DirectoryProvider : public repro::Provider<T> {
143-
public:
144-
DirectoryProvider(const FileSpec &root) : Provider<T>(root) {}
145-
void SetDirectory(std::string directory) {
146-
m_directory = std::move(directory);
147-
}
148-
llvm::StringRef GetDirectory() { return m_directory; }
149-
150-
void Keep() override {
151-
FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file);
152-
std::error_code ec;
153-
llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
154-
if (ec)
155-
return;
156-
os << m_directory << "\n";
157-
}
158-
159-
protected:
160-
std::string m_directory;
161-
};
162-
163-
/// Provider for the current working directory.
164-
///
165-
/// When the reproducer is kept, it writes lldb's current working directory to
166-
/// a file named cwd.txt in the reproducer root.
167-
class WorkingDirectoryProvider
168-
: public DirectoryProvider<WorkingDirectoryProvider> {
169-
public:
170-
WorkingDirectoryProvider(const FileSpec &directory)
171-
: DirectoryProvider(directory) {
172-
llvm::SmallString<128> cwd;
173-
if (std::error_code EC = llvm::sys::fs::current_path(cwd))
174-
return;
175-
SetDirectory(std::string(cwd));
176-
}
177-
struct Info {
178-
static const char *name;
179-
static const char *file;
180-
};
181-
static char ID;
182-
};
183-
184-
/// Provider for the home directory.
185-
///
186-
/// When the reproducer is kept, it writes the user's home directory to a file
187-
/// a file named home.txt in the reproducer root.
188-
class HomeDirectoryProvider : public DirectoryProvider<HomeDirectoryProvider> {
189-
public:
190-
HomeDirectoryProvider(const FileSpec &directory)
191-
: DirectoryProvider(directory) {
192-
llvm::SmallString<128> home_dir;
193-
llvm::sys::path::home_directory(home_dir);
194-
SetDirectory(std::string(home_dir));
195-
}
196-
struct Info {
197-
static const char *name;
198-
static const char *file;
199-
};
200-
static char ID;
201-
};
202-
203-
/// The recorder is a small object handed out by a provider to record data. It
204-
/// is commonly used in combination with a MultiProvider which is meant to
205-
/// record information for multiple instances of the same source of data.
206-
class AbstractRecorder {
207-
protected:
208-
AbstractRecorder(const FileSpec &filename, std::error_code &ec)
209-
: m_filename(filename.GetFilename().GetStringRef()),
210-
m_os(filename.GetPath(), ec, llvm::sys::fs::OF_Text), m_record(true) {}
211-
212-
public:
213-
const FileSpec &GetFilename() { return m_filename; }
214-
215-
void Stop() {
216-
assert(m_record);
217-
m_record = false;
218-
}
219-
220-
private:
221-
FileSpec m_filename;
222-
223-
protected:
224-
llvm::raw_fd_ostream m_os;
225-
bool m_record;
226-
};
227-
228-
/// Recorder that records its data as text to a file.
229-
class DataRecorder : public AbstractRecorder {
230-
public:
231-
DataRecorder(const FileSpec &filename, std::error_code &ec)
232-
: AbstractRecorder(filename, ec) {}
233-
234-
static llvm::Expected<std::unique_ptr<DataRecorder>>
235-
Create(const FileSpec &filename);
236-
237-
template <typename T> void Record(const T &t, bool newline = false) {
238-
if (!m_record)
239-
return;
240-
m_os << t;
241-
if (newline)
242-
m_os << '\n';
243-
m_os.flush();
244-
}
245-
};
246-
247-
/// Recorder that records its data as YAML to a file.
248-
class YamlRecorder : public AbstractRecorder {
249-
public:
250-
YamlRecorder(const FileSpec &filename, std::error_code &ec)
251-
: AbstractRecorder(filename, ec) {}
252-
253-
static llvm::Expected<std::unique_ptr<YamlRecorder>>
254-
Create(const FileSpec &filename);
255-
256-
template <typename T> void Record(const T &t) {
257-
if (!m_record)
258-
return;
259-
llvm::yaml::Output yout(m_os);
260-
// The YAML traits are defined as non-const because they are used for
261-
// serialization and deserialization. The cast is safe because
262-
// serialization doesn't modify the object.
263-
yout << const_cast<T &>(t);
264-
m_os.flush();
265-
}
266-
};
267-
268-
/// The MultiProvider is a provider that hands out recorder which can be used
269-
/// to capture data for different instances of the same object. The recorders
270-
/// can be passed around or stored as an instance member.
271-
///
272-
/// The Info::file for the MultiProvider contains an index of files for every
273-
/// recorder. Use the MultiLoader to read the index and get the individual
274-
/// files.
275-
template <typename T, typename V>
276-
class MultiProvider : public repro::Provider<V> {
277-
public:
278-
MultiProvider(const FileSpec &directory) : Provider<V>(directory) {}
279-
280-
T *GetNewRecorder() {
281-
std::size_t i = m_recorders.size() + 1;
282-
std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") +
283-
llvm::Twine(i) + llvm::Twine(".yaml"))
284-
.str();
285-
auto recorder_or_error =
286-
T::Create(this->GetRoot().CopyByAppendingPathComponent(filename));
287-
if (!recorder_or_error) {
288-
llvm::consumeError(recorder_or_error.takeError());
289-
return nullptr;
290-
}
291-
292-
m_recorders.push_back(std::move(*recorder_or_error));
293-
return m_recorders.back().get();
294-
}
295-
296-
void Keep() override {
297-
std::vector<std::string> files;
298-
for (auto &recorder : m_recorders) {
299-
recorder->Stop();
300-
files.push_back(recorder->GetFilename().GetPath());
301-
}
302-
303-
FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file);
304-
std::error_code ec;
305-
llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text);
306-
if (ec)
307-
return;
308-
llvm::yaml::Output yout(os);
309-
yout << files;
310-
}
311-
312-
void Discard() override { m_recorders.clear(); }
313-
314-
private:
315-
std::vector<std::unique_ptr<T>> m_recorders;
316-
};
317-
318-
class CommandProvider : public MultiProvider<DataRecorder, CommandProvider> {
319-
public:
320-
struct Info {
321-
static const char *name;
322-
static const char *file;
323-
};
324-
325-
CommandProvider(const FileSpec &directory)
326-
: MultiProvider<DataRecorder, CommandProvider>(directory) {}
327-
328-
static char ID;
329-
};
330-
33187
/// The generator is responsible for the logic needed to generate a
33288
/// reproducer. For doing so it relies on providers, who serialize data that
33389
/// is necessary for reproducing a failure.
@@ -469,60 +225,6 @@ class Reproducer {
469225
mutable std::mutex m_mutex;
470226
};
471227

472-
/// Loader for data captured with the MultiProvider. It will read the index and
473-
/// return the path to the files in the index.
474-
template <typename T> class MultiLoader {
475-
public:
476-
MultiLoader(std::vector<std::string> files) : m_files(std::move(files)) {}
477-
478-
static std::unique_ptr<MultiLoader> Create(Loader *loader) {
479-
if (!loader)
480-
return {};
481-
482-
FileSpec file = loader->GetFile<typename T::Info>();
483-
if (!file)
484-
return {};
485-
486-
auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath());
487-
if (auto err = error_or_file.getError())
488-
return {};
489-
490-
std::vector<std::string> files;
491-
llvm::yaml::Input yin((*error_or_file)->getBuffer());
492-
yin >> files;
493-
494-
if (auto err = yin.error())
495-
return {};
496-
497-
for (auto &file : files) {
498-
FileSpec absolute_path =
499-
loader->GetRoot().CopyByAppendingPathComponent(file);
500-
file = absolute_path.GetPath();
501-
}
502-
503-
return std::make_unique<MultiLoader<T>>(std::move(files));
504-
}
505-
506-
llvm::Optional<std::string> GetNextFile() {
507-
if (m_index >= m_files.size())
508-
return {};
509-
return m_files[m_index++];
510-
}
511-
512-
private:
513-
std::vector<std::string> m_files;
514-
unsigned m_index = 0;
515-
};
516-
517-
/// Helper to read directories written by the DirectoryProvider.
518-
template <typename T>
519-
llvm::Expected<std::string> GetDirectoryFrom(repro::Loader *loader) {
520-
llvm::Expected<std::string> dir = loader->LoadBuffer<T>();
521-
if (!dir)
522-
return dir.takeError();
523-
return std::string(llvm::StringRef(*dir).rtrim());
524-
}
525-
526228
} // namespace repro
527229
} // namespace lldb_private
528230

0 commit comments

Comments
 (0)