[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