[Lldb-commits] [lldb] r281717 - [RenderScript] Support tracking and dumping reduction kernels
Zachary Turner via lldb-commits
lldb-commits at lists.llvm.org
Fri Sep 16 07:57:49 PDT 2016
On Fri, Sep 16, 2016 at 4:36 AM Luke Drummond via lldb-commits <
lldb-commits at lists.llvm.org> wrote:
> Author: ldrumm
> Date: Fri Sep 16 06:28:12 2016
> New Revision: 281717
>
> URL: http://llvm.org/viewvc/llvm-project?rev=281717&view=rev
> Log:
> [RenderScript] Support tracking and dumping reduction kernels
>
> Initial implementation of support for tracking
> [RenderScript Reductions](
> https://developer.android.com/guide/topics/renderscript/compute.html#reduction-in-depth
> )
>
> With this patch, `language renderscript module dump` properly lists
> reductions
> that are part of loaded RenderScript modules as well the the consituent
> functions and their roles, within the reduction.
>
> This support required new tracking mechanisms for the `#pragma(reduce)`
> mechanism, and extension of `RSModuleDescriptor::ParseRSInfo` to support
> the metadata output by `bcc`. This work was also an opportunity to
> refactor/improve parse code:
>
> - `RSModuleDescriptor::ParseExportReduceCount` now has a complete
> implementation and the debugger can correctly track reductions on
> receipt of a module hook.
> - `RSModuleDescriptor::Dump` now dumps Reductions as well as `ForEach`
> kernels. Also, fixed indentation of the output, and made indentation
> groupings in the source clearer.
> - `RSModuleDescriptor::ParseRSInfo` now returns true if the `".rs.info"`
> packet has nonzero linecount, rather than rejecting RenderScripts that
> don't contain kernels (an unlikely situation, but possibly valid). This
> was changed because scripts that only contained reductions were not
> being tracked in `RenderScriptRuntime::LoadModule`.
> - Refactor `RSModuleInfo::ParseRSInfo` and add reduction spec parser stub
> - Prepared ParseRSInfo to more easily be able to add new parser types
> - Use llvm::StringRef and llvm::StringMap helpers to make the parsing
> code cleaner
> - factor out forEachCount, globalVarCount, and pragmaCount parsing block
> to their own methods
> - Add ExportReduceCount Parser
> - Use `llvm::StringRef` in `RSKernelDescriptor` constructor
> - removed now superfluous `MAXLINE` macros as we've switched from `const
> char *` to `llvm::StringRef`
>
> Modified:
>
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
>
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
>
> Modified:
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp?rev=281717&r1=281716&r2=281717&view=diff
>
> ==============================================================================
> ---
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
> (original)
> +++
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp
> Fri Sep 16 06:28:12 2016
> @@ -10,6 +10,8 @@
> // C Includes
> // C++ Includes
> // Other libraries and framework includes
> +#include "llvm/ADT/StringMap.h"
> +
> // Project includes
> #include "RenderScriptRuntime.h"
>
> @@ -2587,17 +2589,104 @@ void RenderScriptRuntime::Update() {
> }
> }
>
> -// The maximum line length of an .rs.info packet
> -#define MAXLINE 500
> -#define STRINGIFY(x) #x
> -#define MAXLINESTR_(x) "%" STRINGIFY(x) "s"
> -#define MAXLINESTR MAXLINESTR_(MAXLINE)
> +bool RSModuleDescriptor::ParsePragmaCount(llvm::StringRef *lines,
> + size_t n_lines) {
> + // Skip the pragma prototype line
> + ++lines;
> + for (; n_lines--; ++lines) {
> + const auto kv_pair = lines->split(" - ");
> + m_pragmas[kv_pair.first.trim().str()] = kv_pair.second.trim().str();
> + }
> + return true;
> +}
> +
> +bool RSModuleDescriptor::ParseExportReduceCount(llvm::StringRef *lines,
> + size_t n_lines) {
>
This should take an ArrayRef<StringRef>. In general this is true any time
you're passing an array to a function via (T* items, size_t length).
> + // The list of reduction kernels in the `.rs.info` symbol is of the
> form
> + // "signature - accumulatordatasize - reduction_name - initializer_name
> -
> + // accumulator_name - combiner_name -
> + // outconverter_name - halter_name"
> + // Where a function is not explicitly named by the user, or is not
> generated
> + // by the compiler, it is named "." so the
> + // dash separated list should always be 8 items long
> + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
> + // Skip the exportReduceCount line
> + ++lines;
> + for (; n_lines--; ++lines) {
>
With ArrayRef this would be written as:
for (StringRef line : lines.drop_front()) {
}
> + llvm::SmallVector<llvm::StringRef, 8> spec;
> + lines->split(spec, " - ");
> + if (spec.size() != 8) {
> + if (spec.size() < 8) {
> + if (log)
> + log->Error("Error parsing RenderScript reduction spec. wrong
> number "
> + "of fields");
> + return false;
> + } else if (log)
> + log->Warning("Extraneous members in reduction spec: '%s'",
> + lines->str().c_str());
> + }
> +
> + const auto sig_s = spec[0];
> + uint32_t sig;
> + if (sig_s.getAsInteger(10, sig)) {
> + if (log)
> + log->Error("Error parsing Renderscript reduction spec: invalid
> kernel "
> + "signature: '%s'",
> + sig_s.str().c_str());
> + return false;
> + }
> +
> + const auto accum_data_size_s = spec[1];
> + uint32_t accum_data_size;
> + if (accum_data_size_s.getAsInteger(10, accum_data_size)) {
> + if (log)
> + log->Error("Error parsing Renderscript reduction spec: invalid "
> + "accumulator data size %s",
> + accum_data_size_s.str().c_str());
> + return false;
> + }
> +
> + if (log)
> + log->Printf("Found RenderScript reduction '%s'",
> spec[2].str().c_str());
> +
> + m_reductions.push_back(RSReductionDescriptor(this, sig,
> accum_data_size,
> + spec[2], spec[3],
> spec[4],
> + spec[5], spec[6],
> spec[7]));
> + }
> + return true;
> +}
> +
> +bool RSModuleDescriptor::ParseExportForeachCount(llvm::StringRef *lines,
> + size_t n_lines) {
>
Same as above.
> + // Skip the exportForeachCount line
> + ++lines;
> + for (; n_lines--; ++lines) {
> + uint32_t slot;
> + // `forEach` kernels are listed in the `.rs.info` packet as a "slot
> - name"
> + // pair per line
> + const auto kv_pair = lines->split(" - ");
> + if (kv_pair.first.getAsInteger(10, slot))
> + return false;
> + m_kernels.push_back(RSKernelDescriptor(this, kv_pair.second, slot));
> + }
> + return true;
> +}
> +
> +bool RSModuleDescriptor::ParseExportVarCount(llvm::StringRef *lines,
> + size_t n_lines) {
>
Same
> + // Skip the ExportVarCount line
> + ++lines;
> + for (; n_lines--; ++lines)
> + m_globals.push_back(RSGlobalDescriptor(this, *lines));
> + return true;
> +}
>
> // The .rs.info symbol in renderscript modules contains a string which
> needs to
> // be parsed.
> // The string is basic and is parsed on a line by line basis.
> bool RSModuleDescriptor::ParseRSInfo() {
> assert(m_module);
> + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
> const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(
> ConstString(".rs.info"), eSymbolTypeData);
> if (!info_sym)
> @@ -2615,61 +2704,85 @@ bool RSModuleDescriptor::ParseRSInfo() {
> return false;
>
> // split rs.info. contents into lines
> - std::vector<std::string> info_lines;
> + llvm::SmallVector<llvm::StringRef, 128> info_lines;
> {
> - const std::string info((const char *)buffer->GetBytes());
> - for (size_t tail = 0; tail < info.size();) {
> - // find next new line or end of string
> - size_t head = info.find('\n', tail);
> - head = (head == std::string::npos) ? info.size() : head;
> - std::string line = info.substr(tail, head - tail);
> - // add to line list
> - info_lines.push_back(line);
> - tail = head + 1;
> - }
> + const llvm::StringRef raw_rs_info((const char *)buffer->GetBytes());
> + raw_rs_info.split(info_lines, '\n');
> + if (log)
> + log->Printf("'.rs.info symbol for '%s':\n%s",
> + m_module->GetFileSpec().GetCString(),
> + raw_rs_info.str().c_str());
> }
>
> - std::array<char, MAXLINE> name{{'\0'}};
> - std::array<char, MAXLINE> value{{'\0'}};
> + enum {
> + eExportVar,
> + eExportForEach,
> + eExportReduce,
> + ePragma,
> + eBuildChecksum,
> + eObjectSlot
> + };
> +
> + static const llvm::StringMap<int> rs_info_handlers{
> + {// The number of visible global variables in the script
> + {"exportVarCount", eExportVar},
> + // The number of RenderScrip `forEach` kernels
> __attribute__((kernel))
> + {"exportForEachCount", eExportForEach},
> + // The number of generalreductions: This marked in the script by
> `#pragma
> + // reduce()`
> + {"exportReduceCount", eExportReduce},
> + // Total count of all RenderScript specific `#pragmas` used in the
> script
> + {"pragmaCount", ePragma},
> + {"objectSlotCount", eObjectSlot}}};
>
> // parse all text lines of .rs.info
> for (auto line = info_lines.begin(); line != info_lines.end(); ++line) {
>
How about (for auto line : info_lines) {
> - uint32_t numDefns = 0;
> - if (sscanf(line->c_str(), "exportVarCount: %" PRIu32 "", &numDefns)
> == 1) {
> - while (numDefns--)
> - m_globals.push_back(RSGlobalDescriptor(this, (++line)->c_str()));
> - } else if (sscanf(line->c_str(), "exportForEachCount: %" PRIu32 "",
> - &numDefns) == 1) {
> - while (numDefns--) {
> - uint32_t slot = 0;
> - name[0] = '\0';
> - static const char *fmt_s = "%" PRIu32 " - " MAXLINESTR;
> - if (sscanf((++line)->c_str(), fmt_s, &slot, name.data()) == 2) {
> - if (name[0] != '\0')
> - m_kernels.push_back(RSKernelDescriptor(this, name.data(),
> slot));
> - }
> - }
> - } else if (sscanf(line->c_str(), "pragmaCount: %" PRIu32 "",
> &numDefns) ==
> - 1) {
> - while (numDefns--) {
> - name[0] = value[0] = '\0';
> - static const char *fmt_s = MAXLINESTR " - " MAXLINESTR;
> - if (sscanf((++line)->c_str(), fmt_s, name.data(), value.data())
> != 0) {
> - if (name[0] != '\0')
> - m_pragmas[std::string(name.data())] = value.data();
> - }
> - }
> - } else {
> - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE));
> - if (log) {
> + const auto kv_pair = line->split(": ");
> + const auto key = kv_pair.first;
> + const auto val = kv_pair.second.trim();
> +
> + const auto handler = rs_info_handlers.find(key);
> + if (handler == rs_info_handlers.end())
> + continue;
>
Instead of constructing this map, you could use llvm::StringSwitch, like
this:
int handler = llvm::StringSwitch<int>(key)
.Case("exportVarCount", eExportVar)
.Case("exportForEachCount", eExportForEach)
.Case("exportReduceCount", eExportReduce)
.Case("pragmaCount", ePragma)
.Case("objectSlotCount", eObjectSlot)
.Default(-1);
> + // getAsInteger returns `true` on an error condition - we're only
> interested
> + // in
> + // numeric fields at the moment
> + uint64_t n_lines;
> + if (val.getAsInteger(10, n_lines)) {
> + if (log)
> + log->Debug("Failed to parse non-numeric '.rs.info' section %s",
> + line->str().c_str());
> + continue;
> + }
> + if (info_lines.end() - (line + 1) < (ptrdiff_t)n_lines)
> + return false;
> +
> + bool success = false;
> + switch (handler->getValue()) {
> + case eExportVar:
> + success = ParseExportVarCount(line, n_lines);
> + break;
> + case eExportForEach:
> + success = ParseExportForeachCount(line, n_lines);
> + break;
> + case eExportReduce:
> + success = ParseExportReduceCount(line, n_lines);
> + break;
> + case ePragma:
> + success = ParsePragmaCount(line, n_lines);
> + break;
> + default: {
> + if (log)
> log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__,
> - line->c_str());
> - }
> + line->str().c_str());
> + continue;
> + }
> }
> + if (!success)
> + return false;
> + line += n_lines;
> }
> -
> - // 'root' kernel should always be present
> - return m_kernels.size() > 0;
> + return info_lines.size() > 0;
> }
>
> void RenderScriptRuntime::Status(Stream &strm) const {
> @@ -3419,15 +3532,15 @@ RenderScriptRuntime::CreateAllocation(ad
> }
>
> void RSModuleDescriptor::Dump(Stream &strm) const {
> + int indent = strm.GetIndentLevel();
> +
> strm.Indent();
> m_module->GetFileSpec().Dump(&strm);
> - if (m_module->GetNumCompileUnits()) {
> - strm.Indent("Debug info loaded.");
> - } else {
> - strm.Indent("Debug info does not exist.");
> - }
> + strm.Indent(m_module->GetNumCompileUnits() ? "Debug info loaded."
> + : "Debug info does not
> exist.");
> strm.EOL();
> strm.IndentMore();
> +
> strm.Indent();
> strm.Printf("Globals: %" PRIu64,
> static_cast<uint64_t>(m_globals.size()));
> strm.EOL();
> @@ -3436,6 +3549,7 @@ void RSModuleDescriptor::Dump(Stream &st
> global.Dump(strm);
> }
> strm.IndentLess();
> +
> strm.Indent();
> strm.Printf("Kernels: %" PRIu64,
> static_cast<uint64_t>(m_kernels.size()));
> strm.EOL();
> @@ -3443,14 +3557,29 @@ void RSModuleDescriptor::Dump(Stream &st
> for (const auto &kernel : m_kernels) {
> kernel.Dump(strm);
> }
> + strm.IndentLess();
> +
> + strm.Indent();
> strm.Printf("Pragmas: %" PRIu64,
> static_cast<uint64_t>(m_pragmas.size()));
> strm.EOL();
> strm.IndentMore();
> for (const auto &key_val : m_pragmas) {
> + strm.Indent();
> strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str());
> strm.EOL();
> }
> - strm.IndentLess(4);
> + strm.IndentLess();
> +
> + strm.Indent();
> + strm.Printf("Reductions: %" PRIu64,
> + static_cast<uint64_t>(m_reductions.size()));
> + strm.EOL();
> + strm.IndentMore();
> + for (const auto &reduction : m_reductions) {
> + reduction.Dump(strm);
> + }
> +
> + strm.SetIndentLevel(indent);
> }
>
> void RSGlobalDescriptor::Dump(Stream &strm) const {
> @@ -3483,6 +3612,29 @@ void RSKernelDescriptor::Dump(Stream &st
> strm.EOL();
> }
>
> +void RSReductionDescriptor::Dump(lldb_private::Stream &stream) const {
> + stream.Indent(m_reduce_name.AsCString());
> + stream.IndentMore();
> + stream.EOL();
> + stream.Indent();
> + stream.Printf("accumulator: %s", m_accum_name.AsCString());
> + stream.EOL();
> + stream.Indent();
> + stream.Printf("initializer: %s", m_init_name.AsCString());
> + stream.EOL();
> + stream.Indent();
> + stream.Printf("combiner: %s", m_comb_name.AsCString());
> + stream.EOL();
> + stream.Indent();
> + stream.Printf("outconverter: %s", m_outc_name.AsCString());
> + stream.EOL();
> + // XXX This is currently unspecified by RenderScript, and unused
> + // stream.Indent();
> + // stream.Printf("halter: '%s'", m_init_name.AsCString());
> + // stream.EOL();
> + stream.IndentLess();
> +}
> +
> class CommandObjectRenderScriptRuntimeModuleDump : public
> CommandObjectParsed {
> public:
> CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter
> &interpreter)
>
> Modified:
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
> URL:
> http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h?rev=281717&r1=281716&r2=281717&view=diff
>
> ==============================================================================
> ---
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
> (original)
> +++
> lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h
> Fri Sep 16 06:28:12 2016
> @@ -19,6 +19,8 @@
> #include <vector>
>
> // Other libraries and framework includes
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringRef.h"
> // Project includes
> #include "lldb/Core/Module.h"
> #include "lldb/Expression/LLVMUserExpression.h"
> @@ -33,6 +35,7 @@ typedef uint32_t RSSlot;
> class RSModuleDescriptor;
> struct RSGlobalDescriptor;
> struct RSKernelDescriptor;
> +struct RSReductionDescriptor;
>
> typedef std::shared_ptr<RSModuleDescriptor> RSModuleDescriptorSP;
> typedef std::shared_ptr<RSGlobalDescriptor> RSGlobalDescriptorSP;
> @@ -75,7 +78,7 @@ protected:
>
> struct RSKernelDescriptor {
> public:
> - RSKernelDescriptor(const RSModuleDescriptor *module, const char *name,
> + RSKernelDescriptor(const RSModuleDescriptor *module, llvm::StringRef
> name,
> uint32_t slot)
> : m_module(module), m_name(name), m_slot(slot) {}
>
> @@ -88,7 +91,7 @@ public:
>
> struct RSGlobalDescriptor {
> public:
> - RSGlobalDescriptor(const RSModuleDescriptor *module, const char *name)
> + RSGlobalDescriptor(const RSModuleDescriptor *module, llvm::StringRef
> name)
> : m_module(module), m_name(name) {}
>
> void Dump(Stream &strm) const;
> @@ -97,7 +100,56 @@ public:
> ConstString m_name;
> };
>
> +struct RSReductionDescriptor {
> + RSReductionDescriptor(const RSModuleDescriptor *module, uint32_t sig,
> + uint32_t accum_data_size, llvm::StringRef name,
> + llvm::StringRef init_name, llvm::StringRef
> accum_name,
> + llvm::StringRef comb_name, llvm::StringRef
> outc_name,
> + llvm::StringRef halter_name = ".")
> + : m_module(module), m_reduce_name(name), m_init_name(init_name),
> + m_accum_name(accum_name), m_comb_name(comb_name),
> + m_outc_name(outc_name), m_halter_name(halter_name) {
> + // TODO Check whether the combiner is an autogenerated name, and track
> + // this
> + }
> +
> + void Dump(Stream &strm) const;
> +
> + const RSModuleDescriptor *m_module;
> + ConstString m_reduce_name; // This is the name given to the general
> reduction
> + // as a group as passed to pragma
> + // reduce(m_reduce_name). There is no kernel function with this name
> + ConstString m_init_name; // The name of the initializer name. "." if no
> + // initializer given
> + ConstString m_accum_name; // The accumulator function name. "." if not
> given
> + ConstString m_comb_name; // The name of the combiner function. If this
> was not
> + // given, a name is generated by the
> + // compiler. TODO
> + ConstString m_outc_name; // The name of the outconverter
> +
> + ConstString m_halter_name; // The name of the halter function. XXX This
> is not
> + // yet specified by the RenderScript
> + // compiler or runtime, and its semantics and existence is still under
> + // discussion by the
> + // RenderScript Contributors
> + RSSlot m_accum_sig; // metatdata signature for this reduction (bitwise
> mask of
> + // type information (see
> + // libbcc/include/bcinfo/MetadataExtractor.h
> + uint32_t m_accum_data_size; // Data size of the accumulator function
> input
> + bool m_comb_name_generated; // Was the combiner name generated by the
> compiler
> +};
> +
> class RSModuleDescriptor {
> + bool ParseExportForeachCount(llvm::StringRef *, size_t n_lines);
> +
> + bool ParseExportVarCount(llvm::StringRef *, size_t n_lines);
> +
> + bool ParseExportReduceCount(llvm::StringRef *, size_t n_lines);
> +
> + bool ParseBuildChecksum(llvm::StringRef *, size_t n_lines);
> +
> + bool ParsePragmaCount(llvm::StringRef *, size_t n_lines);
> +
> public:
> RSModuleDescriptor(const lldb::ModuleSP &module) : m_module(module) {}
>
> @@ -110,6 +162,7 @@ public:
> const lldb::ModuleSP m_module;
> std::vector<RSKernelDescriptor> m_kernels;
> std::vector<RSGlobalDescriptor> m_globals;
> + std::vector<RSReductionDescriptor> m_reductions;
> std::map<std::string, std::string> m_pragmas;
>
You should consider changing this to llvm::StringMap, which has better
performance characteristics than std::map
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20160916/e4950308/attachment-0001.html>
More information about the lldb-commits
mailing list