On Fri, Sep 16, 2016 at 4:36 AM Luke Drummond via lldb-commits < lldb-commits@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
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits