<commit_before>/*
 * SessionEnvironment.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionEnvironment.hpp"
#include "EnvironmentMonitor.hpp"

#include <algorithm>

#include <core/Exec.hpp>

#define INTERNAL_R_FUNCTIONS
#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/session/RSession.hpp>
#include <r/RInterface.hpp>
#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>
#include <boost/foreach.hpp>

#include "EnvironmentUtils.hpp"

#define TOP_FUNCTION 1

using namespace core ;

namespace session {
namespace modules {
namespace environment {

EnvironmentMonitor s_environmentMonitor;

namespace {

bool handleRBrowseEnv(const core::FilePath& filePath)
{
   if (filePath.filename() == "wsbrowser.html")
   {
      module_context::showContent("R objects", filePath);
      return true;
   }
   else
   {
      return false;
   }
}

SEXP getOriginalFunctionCallObject(const RCNTXT* pContext)
{
   SEXP callObject = pContext->callfun;
   // enabling tracing on a function turns it into an S4 object with an
   // 'original' slot that includes the function's original contents. use
   // this instead if it's set up. (consider: is it safe to assume that S4
   // objects here are always traced functions, or do we need to compare classes
   // to be safe?)
   if (Rf_isS4(callObject))
   {
      callObject = r::sexp::getAttrib(callObject, "original");
   }
   return callObject;
}

Error getFileNameFromContext(const RCNTXT* pContext,
                             std::string* pFileName)
{
   SEXP srcref = pContext->srcref;
   return r::exec::RFunction(".rs.sourceFileFromRef", srcref)
                 .call(pFileName);
}

SEXP getFunctionSourceRefFromContext(const RCNTXT* pContext)
{
   return r::sexp::getAttrib(getOriginalFunctionCallObject(pContext), "srcref");
}

bool isDebugHiddenContext(RCNTXT* pContext)
{
   SEXP hideFlag = r::sexp::getAttrib(pContext->callfun, "hideFromDebugger");
   return TYPEOF(hideFlag) != NILSXP && r::sexp::asLogical(hideFlag);
}

// given a context from the context stack, indicate whether it should be emitted
// to the callstack.
bool isPrintableContext(RCNTXT* pContext)
{
   if (pContext->callflag & CTXT_FUNCTION)
   {
      if (isDebugHiddenContext(pContext))
      {
         // hidden function
         return false;
      }
      // printable function
      return true;
   }
   // not a function at all
   return false;
}

// return the function context at the given depth
RCNTXT* getFunctionContext(const int depth,
                           bool findUserCode = false,
                           int* pFoundDepth = NULL,
                           SEXP* pEnvironment = NULL)
{
   RCNTXT* pRContext = r::getGlobalContext();
   int currentDepth = 0;
   while (pRContext->callflag)
   {
      if (isPrintableContext(pRContext))
      {
         SEXP srcref = getFunctionSourceRefFromContext(pRContext);
         // if the caller asked us to find user code, don't stop unless the
         // context we're examining has a source file attached
         if (++currentDepth >= depth &&
             !(findUserCode && (TYPEOF(srcref) == NILSXP)))
         {
             break;
         }
      }
      pRContext = pRContext->nextcontext;
   }

   // indicate the depth at which we stopped and the environment we found at
   // that depth, if requested
   if (pFoundDepth)
   {
      *pFoundDepth = currentDepth;
   }
   if (pEnvironment)
   {
      *pEnvironment = currentDepth == 0 ? R_GlobalEnv : pRContext->cloenv;
   }
   return pRContext;
}

SEXP getEnvironment(const int depth)
{
   return depth == 0 ? R_GlobalEnv : getFunctionContext(depth)->cloenv;
}

// return whether the context stack contains a pure (interactive) browser
bool inBrowseContext()
{
   RCNTXT* pRContext = r::getGlobalContext();
   while (pRContext->callflag)
   {
      if ((pRContext->callflag & CTXT_BROWSER) &&
          !(pRContext->callflag & CTXT_FUNCTION))
      {
         return true;
      }
      pRContext = pRContext->nextcontext;
   }
   return false;
}

// return whether the current context is being evaluated inside a hidden
// (debugger internal) function.
bool insideDebugHiddenFunction()
{
   RCNTXT* pRContext = r::getGlobalContext();
   while (pRContext->callflag)
   {
      if (pRContext->callflag & CTXT_FUNCTION)
      {
         if (isDebugHiddenContext(pRContext))
            return true;
      }
      pRContext = pRContext->nextcontext;
   }
   return false;
}

Error functionNameFromContext(const RCNTXT* pContext,
                              std::string* pFunctionName)
{
   return r::exec::RFunction(".rs.functionNameFromCall", pContext->call)
                            .call(pFunctionName);
}

json::Array callFramesAsJson()
{
   RCNTXT* pRContext = r::getGlobalContext();
   RCNTXT* pSrcContext = pRContext;
   json::Array listFrames;
   int contextDepth = 0;
   Error error;
   bool skipDebugFrame = false;

   while (pRContext->callflag)
   {
      // if this context is hidden from the debugger, we want to avoid
      // delivering source refs for the context that invoked it. set a flag
      // to prevent the following context from picking them up.
      if (isDebugHiddenContext(pRContext))
      {
          skipDebugFrame = true;
      }
      else if (isPrintableContext(pRContext))
      {
         json::Object varFrame;
         std::string functionName;
         error = functionNameFromContext(pRContext, &functionName);
         if (error)
         {
            LOG_ERROR(error);
         }
         varFrame["context_depth"] = ++contextDepth;
         varFrame["function_name"] = functionName;

         // in the linked list of R contexts, the srcref associated with each
         // context points to the place from which the context was invoked.
         // however, for traditional debugging, we want the call frame to show
         // where control *left* the frame to go to the next frame. pSrcContext
         // keeps track of the previous invocation.
         if (!skipDebugFrame)
         {
            std::string filename;
            error = getFileNameFromContext(pSrcContext, &filename);
            if (error)
               LOG_ERROR(error);
            varFrame["file_name"] = filename;
            sourceRefToJson(pSrcContext->srcref, &varFrame);
         }
         else
         {
            varFrame["file_name"] = "";
            sourceRefToJson(NULL, &varFrame);
            skipDebugFrame = false;
         }
         pSrcContext = pRContext;

         // extract the first line of the function. the client can optionally
         // use this to compute the source location as an offset into the
         // function rather than as an absolute file position (useful when
         // we need to debug a copy of the function rather than the real deal).
         SEXP srcRef = getFunctionSourceRefFromContext(pSrcContext);
         if (srcRef && TYPEOF(srcRef) != NILSXP)
         {
            varFrame["function_line_number"] = INTEGER(srcRef)[0];
         }

         std::string argList;
         SEXP args = CDR(pRContext->call);
         switch (TYPEOF(args))
         {
            case LISTSXP:
               error = r::exec::RFunction(".rs.argumentListSummary", args)
                 .call(&argList);
              break;
            case LANGSXP:
               error = r::exec::RFunction(".rs.promiseDescription", args)
                 .call(&argList);
               break;
         }
         if (error)
         {
            LOG_ERROR(error);
         }
         varFrame["argument_list"] = error ? "" : argList;

         listFrames.push_back(varFrame);
      }
      pRContext = pRContext->nextcontext;
   }
   return listFrames;
}

json::Array environmentListAsJson(int depth)
{
    using namespace r::sexp;
    Protect rProtect;
    std::vector<Variable> vars;
    SEXP env = getEnvironment(depth);
    listEnvironment(env, false, &rProtect, &vars);

    // get object details and transform to json
    json::Array listJson;
    std::transform(vars.begin(),
                   vars.end(),
                   std::back_inserter(listJson),
                   boost::bind(varToJson, env, _1));
    return listJson;
}

Error listEnvironment(boost::shared_ptr<int> pContextDepth,
                      const json::JsonRpcRequest&,
                      json::JsonRpcResponse* pResponse)
{
   // return list
   pResponse->setResult(environmentListAsJson(*pContextDepth));
   return Success();
}

// given a function context, indicate whether the copy of the source code
// for the function is different than the source code on disk.
bool functionIsOutOfSync(const RCNTXT *pContext,
                         std::string *pFunctionCode)
{
   Error error;

   // start by extracting the source code from the call site
   error = r::exec::RFunction(".rs.sourceCodeFromFunction",
                              getOriginalFunctionCallObject(pContext))
         .call(pFunctionCode);
   if (error)
   {
      LOG_ERROR(error);
      return true;
   }

   // next, look up the name of the source file that contains the file in
   // question
   std::string fileName;
   SEXP srcRef = getFunctionSourceRefFromContext(pContext);
   if (srcRef == NULL || TYPEOF(srcRef) == NILSXP)
   {
      return true;
   }

   return functionDiffersFromSource(srcRef, *pFunctionCode);
}

// create a JSON object that contains information about the current environment;
// used both to initialize the environment state on first load and to send
// information about the new environment on a context change
json::Value commonEnvironmentStateData(int depth)
{
   json::Object varJson;
   bool useProvidedSource = false;
   std::string functionCode;

   varJson["context_depth"] = depth;
   varJson["environment_list"] = environmentListAsJson(depth);
   varJson["call_frames"] = callFramesAsJson();

   // if we're in a debug context, add information about the function currently
   // being debugged
   if (depth > 0)
   {
      RCNTXT* pContext = getFunctionContext(depth);
      std::string functionName;
      Error error = functionNameFromContext(pContext, &functionName);
      if (error)
      {
         LOG_ERROR(error);
      }
      varJson["function_name"] = functionName;

      // see if the function to be debugged is out of sync with its saved
      // sources (if available).
      if ((pContext))
      {
         useProvidedSource =
               functionIsOutOfSync(pContext, &functionCode) &&
               functionCode != "NULL";
      }
   }
   else
   {
      varJson["function_name"] = "";
   }

   // always emit the code for the function, even if we don't think that the
   // client's going to need it. we only checked the saved copy of the function
   // above; the client may be aware of local/unsaved changes to the function,
   // in which case it will need to fall back on a server-provided copy.
   varJson["use_provided_source"] = useProvidedSource;
   varJson["function_code"] = functionCode;

   return varJson;
}

void enqueContextDepthChangedEvent(int depth)
{
   // emit an event to the client indicating the new call frame and the
   // current state of the environment
   ClientEvent event (client_events::kContextDepthChanged,
                      commonEnvironmentStateData(depth));
   module_context::enqueClientEvent(event);
}

void enqueBrowserLineChangedEvent(const SEXP srcref)
{
   json::Object varJson;
   sourceRefToJson(srcref, &varJson);
   ClientEvent event (client_events::kBrowserLineChanged, varJson);
   module_context::enqueClientEvent(event);
}

Error setContextDepth(boost::shared_ptr<int> pContextDepth,
                      const json::JsonRpcRequest& request,
                      json::JsonRpcResponse* pResponse)
{
   // get the requested depth
   int requestedDepth;
   Error error = json::readParam(request.params, 0, &requestedDepth);
   if (error)
      return error;

   // set state for the new depth
   *pContextDepth = requestedDepth;

   // populate the new state on the client
   enqueContextDepthChangedEvent(*pContextDepth);

   return Success();
}

void onDetectChanges(module_context::ChangeSource source)
{
   s_environmentMonitor.checkForChanges();
}

void onConsolePrompt(boost::shared_ptr<int> pContextDepth,
                     boost::shared_ptr<RCNTXT*> pCurrentContext)
{
   int depth = 0;
   SEXP environmentTop = NULL;
   RCNTXT* pRContext =
         getFunctionContext(TOP_FUNCTION, true, &depth, &environmentTop);

   if (environmentTop != s_environmentMonitor.getMonitoredEnvironment() ||
       depth != *pContextDepth ||
       pRContext != *pCurrentContext)
   {
      json::Object varJson;

      // if we appear to be switching into debug mode, make sure there's a
      // browser call somewhere on the stack. if there isn't, then we're
      // probably just waiting for user input inside a function (e.g. scan());
      // assume the user isn't interested in seeing the function's internals.
      if (*pContextDepth == 0 &&
          !inBrowseContext())
      {
         return;
      }

      // start monitoring the enviroment at the new depth
      s_environmentMonitor.setMonitoredEnvironment(environmentTop);
      *pContextDepth = depth;
      *pCurrentContext = pRContext;
      enqueContextDepthChangedEvent(depth);
   }
   // if we're debugging and stayed in the same frame, update the line number
   else if (depth > 0)
   {
      // we don't want to send linenumber updates if the current depth is inside
      // a debug-hidden function
      if (!insideDebugHiddenFunction())
      {
         enqueBrowserLineChangedEvent(r::getGlobalContext()->srcref);
      }
   }
}

} // anonymous namespace

json::Value environmentStateAsJson()
{
   int contextDepth = 0;
   getFunctionContext(TOP_FUNCTION, true, &contextDepth);
   return commonEnvironmentStateData(contextDepth);
}

Error initialize()
{
   boost::shared_ptr<int> pContextDepth =
         boost::make_shared<int>(0);
   boost::shared_ptr<RCNTXT*> pCurrentContext =
         boost::make_shared<RCNTXT*>(r::getGlobalContext());

   // begin monitoring the environment
   SEXP environmentTop = NULL;
   getFunctionContext(TOP_FUNCTION, true, pContextDepth.get(), &environmentTop);
   s_environmentMonitor.setMonitoredEnvironment(environmentTop);

   // subscribe to events
   using boost::bind;
   using namespace session::module_context;
   events().onDetectChanges.connect(bind(onDetectChanges, _1));
   events().onConsolePrompt.connect(bind(onConsolePrompt,
                                         pContextDepth,
                                         pCurrentContext));

   json::JsonRpcFunction listEnv =
         boost::bind(listEnvironment, pContextDepth, _1, _2);
   json::JsonRpcFunction setCtxDepth =
         boost::bind(setContextDepth, pContextDepth, _1, _2);

   // source R functions
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRBrowseFileHandler, handleRBrowseEnv))
      (bind(registerRpcMethod, "list_environment", listEnv))
      (bind(registerRpcMethod, "set_context_depth", setCtxDepth))
      (bind(sourceModuleRFile, "SessionEnvironment.R"));

   return initBlock.execute();
}

} // namespace environment
} // namespace modules
} // namesapce session

<commit_msg>show correct source refs in callstack when error is not raised intentionally<commit_after>/*
 * SessionEnvironment.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionEnvironment.hpp"
#include "EnvironmentMonitor.hpp"

#include <algorithm>

#include <core/Exec.hpp>

#define INTERNAL_R_FUNCTIONS
#include <r/RSexp.hpp>
#include <r/RExec.hpp>
#include <r/session/RSession.hpp>
#include <r/RInterface.hpp>
#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>
#include <boost/foreach.hpp>

#include "EnvironmentUtils.hpp"

#define TOP_FUNCTION 1

using namespace core ;

namespace session {
namespace modules {
namespace environment {

EnvironmentMonitor s_environmentMonitor;

namespace {

bool handleRBrowseEnv(const core::FilePath& filePath)
{
   if (filePath.filename() == "wsbrowser.html")
   {
      module_context::showContent("R objects", filePath);
      return true;
   }
   else
   {
      return false;
   }
}

SEXP getOriginalFunctionCallObject(const RCNTXT* pContext)
{
   SEXP callObject = pContext->callfun;
   // enabling tracing on a function turns it into an S4 object with an
   // 'original' slot that includes the function's original contents. use
   // this instead if it's set up. (consider: is it safe to assume that S4
   // objects here are always traced functions, or do we need to compare classes
   // to be safe?)
   if (Rf_isS4(callObject))
   {
      callObject = r::sexp::getAttrib(callObject, "original");
   }
   return callObject;
}

Error getFileNameFromContext(const RCNTXT* pContext,
                             std::string* pFileName)
{
   SEXP srcref = pContext->srcref;
   return r::exec::RFunction(".rs.sourceFileFromRef", srcref)
                 .call(pFileName);
}

SEXP sourceRefsOfContext(const RCNTXT* pContext)
{
   return r::sexp::getAttrib(getOriginalFunctionCallObject(pContext), "srcref");
}

bool hasSourceRefs(const RCNTXT* pContext)
{
   SEXP srcref = sourceRefsOfContext(pContext);
   return srcref != NULL && TYPEOF(srcref) != NILSXP;
}

bool isDebugHiddenContext(RCNTXT* pContext)
{
   SEXP hideFlag = r::sexp::getAttrib(pContext->callfun, "hideFromDebugger");
   return TYPEOF(hideFlag) != NILSXP && r::sexp::asLogical(hideFlag);
}

// given a context from the context stack, indicate whether it should be emitted
// to the callstack.
bool isPrintableContext(RCNTXT* pContext)
{
   if (pContext->callflag & CTXT_FUNCTION)
   {
      if (isDebugHiddenContext(pContext))
      {
         // hidden function
         return false;
      }
      // printable function
      return true;
   }
   // not a function at all
   return false;
}

// return the function context at the given depth
RCNTXT* getFunctionContext(const int depth,
                           bool findUserCode = false,
                           int* pFoundDepth = NULL,
                           SEXP* pEnvironment = NULL)
{
   RCNTXT* pRContext = r::getGlobalContext();
   int currentDepth = 0;
   while (pRContext->callflag)
   {
      if (isPrintableContext(pRContext))
      {
         // if the caller asked us to find user code, don't stop unless the
         // context we're examining has a source file attached
         if (++currentDepth >= depth &&
             !(findUserCode && !hasSourceRefs(pRContext)))
         {
             break;
         }
      }
      pRContext = pRContext->nextcontext;
   }

   // indicate the depth at which we stopped and the environment we found at
   // that depth, if requested
   if (pFoundDepth)
   {
      *pFoundDepth = currentDepth;
   }
   if (pEnvironment)
   {
      *pEnvironment = currentDepth == 0 ? R_GlobalEnv : pRContext->cloenv;
   }
   return pRContext;
}

SEXP getEnvironment(const int depth)
{
   return depth == 0 ? R_GlobalEnv : getFunctionContext(depth)->cloenv;
}

// return whether the context stack contains a pure (interactive) browser
bool inBrowseContext()
{
   RCNTXT* pRContext = r::getGlobalContext();
   while (pRContext->callflag)
   {
      if ((pRContext->callflag & CTXT_BROWSER) &&
          !(pRContext->callflag & CTXT_FUNCTION))
      {
         return true;
      }
      pRContext = pRContext->nextcontext;
   }
   return false;
}

// return whether the current context is being evaluated inside a hidden
// (debugger internal) function.
bool insideDebugHiddenFunction()
{
   RCNTXT* pRContext = r::getGlobalContext();
   while (pRContext->callflag)
   {
      if (pRContext->callflag & CTXT_FUNCTION)
      {
         if (isDebugHiddenContext(pRContext))
            return true;
      }
      pRContext = pRContext->nextcontext;
   }
   return false;
}

Error functionNameFromContext(const RCNTXT* pContext,
                              std::string* pFunctionName)
{
   return r::exec::RFunction(".rs.functionNameFromCall", pContext->call)
                            .call(pFunctionName);
}

json::Array callFramesAsJson()
{
   RCNTXT* pRContext = r::getGlobalContext();
   RCNTXT* pSrcContext = pRContext;
   json::Array listFrames;
   int contextDepth = 0;
   Error error;

   while (pRContext->callflag)
   {
      // If this context is hidden from the debugger, we want to avoid
      // delivering source refs for the context that invoked it. Pick up
      // source refs from the next context in this case.
      if (isDebugHiddenContext(pRContext))
      {
          pSrcContext = pRContext->nextcontext;
      }
      else if (isPrintableContext(pRContext))
      {
         json::Object varFrame;
         std::string functionName;
         error = functionNameFromContext(pRContext, &functionName);
         if (error)
         {
            LOG_ERROR(error);
         }
         varFrame["context_depth"] = ++contextDepth;
         varFrame["function_name"] = functionName;

         // in the linked list of R contexts, the srcref associated with each
         // context points to the place from which the context was invoked.
         // however, for traditional debugging, we want the call frame to show
         // where control *left* the frame to go to the next frame. pSrcContext
         // keeps track of the previous invocation.
         std::string filename;
         error = getFileNameFromContext(pSrcContext, &filename);
         if (error)
            LOG_ERROR(error);
         varFrame["file_name"] = filename;
         sourceRefToJson(pSrcContext->srcref, &varFrame);
         pSrcContext = pRContext;

         // extract the first line of the function. the client can optionally
         // use this to compute the source location as an offset into the
         // function rather than as an absolute file position (useful when
         // we need to debug a copy of the function rather than the real deal).
         SEXP srcRef = sourceRefsOfContext(pSrcContext);
         if (srcRef && TYPEOF(srcRef) != NILSXP)
         {
            varFrame["function_line_number"] = INTEGER(srcRef)[0];
         }

         std::string argList;
         SEXP args = CDR(pRContext->call);
         switch (TYPEOF(args))
         {
            case LISTSXP:
               error = r::exec::RFunction(".rs.argumentListSummary", args)
                 .call(&argList);
              break;
            case LANGSXP:
               error = r::exec::RFunction(".rs.promiseDescription", args)
                 .call(&argList);
               break;
         }
         if (error)
         {
            LOG_ERROR(error);
         }
         varFrame["argument_list"] = error ? "" : argList;

         listFrames.push_back(varFrame);
      }
      pRContext = pRContext->nextcontext;
   }
   return listFrames;
}

json::Array environmentListAsJson(int depth)
{
    using namespace r::sexp;
    Protect rProtect;
    std::vector<Variable> vars;
    SEXP env = getEnvironment(depth);
    listEnvironment(env, false, &rProtect, &vars);

    // get object details and transform to json
    json::Array listJson;
    std::transform(vars.begin(),
                   vars.end(),
                   std::back_inserter(listJson),
                   boost::bind(varToJson, env, _1));
    return listJson;
}

Error listEnvironment(boost::shared_ptr<int> pContextDepth,
                      const json::JsonRpcRequest&,
                      json::JsonRpcResponse* pResponse)
{
   // return list
   pResponse->setResult(environmentListAsJson(*pContextDepth));
   return Success();
}

// given a function context, indicate whether the copy of the source code
// for the function is different than the source code on disk.
bool functionIsOutOfSync(const RCNTXT *pContext,
                         std::string *pFunctionCode)
{
   Error error;

   // start by extracting the source code from the call site
   error = r::exec::RFunction(".rs.sourceCodeFromFunction",
                              getOriginalFunctionCallObject(pContext))
         .call(pFunctionCode);
   if (error)
   {
      LOG_ERROR(error);
      return true;
   }

   // make sure the function has source references
   if (!hasSourceRefs(pContext))
   {
      return true;
   }

   return functionDiffersFromSource(
            sourceRefsOfContext(pContext), *pFunctionCode);
}

// create a JSON object that contains information about the current environment;
// used both to initialize the environment state on first load and to send
// information about the new environment on a context change
json::Value commonEnvironmentStateData(int depth)
{
   json::Object varJson;
   bool useProvidedSource = false;
   std::string functionCode;

   varJson["context_depth"] = depth;
   varJson["environment_list"] = environmentListAsJson(depth);
   varJson["call_frames"] = callFramesAsJson();

   // if we're in a debug context, add information about the function currently
   // being debugged
   if (depth > 0)
   {
      RCNTXT* pContext = getFunctionContext(depth);
      std::string functionName;
      Error error = functionNameFromContext(pContext, &functionName);
      if (error)
      {
         LOG_ERROR(error);
      }
      varJson["function_name"] = functionName;

      // see if the function to be debugged is out of sync with its saved
      // sources (if available).
      if ((pContext))
      {
         useProvidedSource =
               functionIsOutOfSync(pContext, &functionCode) &&
               functionCode != "NULL";
      }
   }
   else
   {
      varJson["function_name"] = "";
   }

   // always emit the code for the function, even if we don't think that the
   // client's going to need it. we only checked the saved copy of the function
   // above; the client may be aware of local/unsaved changes to the function,
   // in which case it will need to fall back on a server-provided copy.
   varJson["use_provided_source"] = useProvidedSource;
   varJson["function_code"] = functionCode;

   return varJson;
}

void enqueContextDepthChangedEvent(int depth)
{
   // emit an event to the client indicating the new call frame and the
   // current state of the environment
   ClientEvent event (client_events::kContextDepthChanged,
                      commonEnvironmentStateData(depth));
   module_context::enqueClientEvent(event);
}

void enqueBrowserLineChangedEvent(const SEXP srcref)
{
   json::Object varJson;
   sourceRefToJson(srcref, &varJson);
   ClientEvent event (client_events::kBrowserLineChanged, varJson);
   module_context::enqueClientEvent(event);
}

Error setContextDepth(boost::shared_ptr<int> pContextDepth,
                      const json::JsonRpcRequest& request,
                      json::JsonRpcResponse* pResponse)
{
   // get the requested depth
   int requestedDepth;
   Error error = json::readParam(request.params, 0, &requestedDepth);
   if (error)
      return error;

   // set state for the new depth
   *pContextDepth = requestedDepth;

   // populate the new state on the client
   enqueContextDepthChangedEvent(*pContextDepth);

   return Success();
}

void onDetectChanges(module_context::ChangeSource source)
{
   s_environmentMonitor.checkForChanges();
}

void onConsolePrompt(boost::shared_ptr<int> pContextDepth,
                     boost::shared_ptr<RCNTXT*> pCurrentContext)
{
   int depth = 0;
   SEXP environmentTop = NULL;
   RCNTXT* pRContext =
         getFunctionContext(TOP_FUNCTION, true, &depth, &environmentTop);

   if (environmentTop != s_environmentMonitor.getMonitoredEnvironment() ||
       depth != *pContextDepth ||
       pRContext != *pCurrentContext)
   {
      json::Object varJson;

      // if we appear to be switching into debug mode, make sure there's a
      // browser call somewhere on the stack. if there isn't, then we're
      // probably just waiting for user input inside a function (e.g. scan());
      // assume the user isn't interested in seeing the function's internals.
      if (*pContextDepth == 0 &&
          !inBrowseContext())
      {
         return;
      }

      // start monitoring the enviroment at the new depth
      s_environmentMonitor.setMonitoredEnvironment(environmentTop);
      *pContextDepth = depth;
      *pCurrentContext = pRContext;
      enqueContextDepthChangedEvent(depth);
   }
   // if we're debugging and stayed in the same frame, update the line number
   else if (depth > 0)
   {
      // we don't want to send linenumber updates if the current depth is inside
      // a debug-hidden function
      if (!insideDebugHiddenFunction())
      {
         enqueBrowserLineChangedEvent(r::getGlobalContext()->srcref);
      }
   }
}

} // anonymous namespace

json::Value environmentStateAsJson()
{
   int contextDepth = 0;
   getFunctionContext(TOP_FUNCTION, true, &contextDepth);
   return commonEnvironmentStateData(contextDepth);
}

Error initialize()
{
   boost::shared_ptr<int> pContextDepth =
         boost::make_shared<int>(0);
   boost::shared_ptr<RCNTXT*> pCurrentContext =
         boost::make_shared<RCNTXT*>(r::getGlobalContext());

   // begin monitoring the environment
   SEXP environmentTop = NULL;
   getFunctionContext(TOP_FUNCTION, true, pContextDepth.get(), &environmentTop);
   s_environmentMonitor.setMonitoredEnvironment(environmentTop);

   // subscribe to events
   using boost::bind;
   using namespace session::module_context;
   events().onDetectChanges.connect(bind(onDetectChanges, _1));
   events().onConsolePrompt.connect(bind(onConsolePrompt,
                                         pContextDepth,
                                         pCurrentContext));

   json::JsonRpcFunction listEnv =
         boost::bind(listEnvironment, pContextDepth, _1, _2);
   json::JsonRpcFunction setCtxDepth =
         boost::bind(setContextDepth, pContextDepth, _1, _2);

   // source R functions
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerRBrowseFileHandler, handleRBrowseEnv))
      (bind(registerRpcMethod, "list_environment", listEnv))
      (bind(registerRpcMethod, "set_context_depth", setCtxDepth))
      (bind(sourceModuleRFile, "SessionEnvironment.R"));

   return initBlock.execute();
}

} // namespace environment
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#ifndef PCL_FEATURES_IMPL_SHOT_LRF_OMP_H_
#define PCL_FEATURES_IMPL_SHOT_LRF_OMP_H_

#include <utility>
#include <pcl/features/shot_lrf_omp.h>
#include <pcl/features/shot_lrf.h>

template<typename PointInT, typename PointOutT>
void
pcl::SHOTLocalReferenceFrameEstimationOMP<PointInT, PointOutT>::computeFeature (PointCloudOut &output)
{
  if (threads_ < 0)
    threads_ = 1;

  //check whether used with search radius or search k-neighbors
  if (this->getKSearch () != 0)
  {
    PCL_ERROR(
        "[pcl::%s::computeFeature] Error! Search method set to k-neighborhood. Call setKSearch(0) and setRadiusSearch( radius ) to use this class.\n",
        getClassName().c_str ());
    return;
  }
  tree_->setSortedResults (true);

#pragma omp parallel for num_threads(threads_)
  for (size_t i = 0; i < indices_->size (); ++i)
  {
    // point result
    Eigen::Matrix3f rf;
    PointOutT& output_rf = output[i];

    //output_rf.confidence = getLocalRF ((*indices_)[i], rf);
    //if (output_rf.confidence == std::numeric_limits<float>::max ())

    std::vector<int> n_indices;
    std::vector<float> n_sqr_distances;
    searchForNeighbors ((*indices_)[i], search_parameter_, n_indices, n_sqr_distances);
    if (getLocalRF ((*indices_)[i], rf) == std::numeric_limits<float>::max ())
    {
      output.is_dense = false;
    }

    output_rf.x_axis.getNormalVector3fMap () = rf.row (0);
    output_rf.y_axis.getNormalVector3fMap () = rf.row (1);
    output_rf.z_axis.getNormalVector3fMap () = rf.row (2);
  }

}

template<typename PointInT, typename PointOutT>
void
pcl::SHOTLocalReferenceFrameEstimationOMP<PointInT, PointOutT>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output)
{
  if (threads_ < 0)
     threads_ = 1;

  //check whether used with search radius or search k-neighbors
  if (this->getKSearch () != 0)
  {
    PCL_ERROR(
        "[pcl::%s::computeFeatureEigen] Error! Search method set to k-neighborhood. Call setKSearch(0) and setRadiusSearch( radius ) to use this class.\n",
        getClassName().c_str ());
    return;
  }
  tree_->setSortedResults (true);

  // Set up the output channels
  output.channels["shot_lrf"].name = "shot_lrf";
  output.channels["shot_lrf"].offset = 0;
  output.channels["shot_lrf"].size = 4;
  output.channels["shot_lrf"].count = 9;
  output.channels["shot_lrf"].datatype = sensor_msgs::PointField::FLOAT32;

  //output.points.resize (indices_->size (), 10);
  output.points.resize (indices_->size (), 9);

#pragma omp parallel for num_threads(threads_)
  for (size_t i = 0; i < indices_->size (); ++i)
  {
    // point result
    Eigen::Matrix3f rf;

    //output.points (i, 9) = getLocalRF ((*indices_)[i], rf);
    //if (output.points (i, 9) == std::numeric_limits<float>::max ())
    if (getLocalRF ((*indices_)[i], rf) == std::numeric_limits<float>::max ())
    {
      output.is_dense = false;
    }

    output.points.block<1, 3> (i, 0) = rf.row (0);
    output.points.block<1, 3> (i, 3) = rf.row (1);
    output.points.block<1, 3> (i, 6) = rf.row (2);
  }

}

#define PCL_INSTANTIATE_SHOTLocalReferenceFrameEstimationOMP(T,OutT) template class PCL_EXPORTS pcl::SHOTLocalReferenceFrameEstimationOMP<T,OutT>;

#endif    // PCL_FEATURES_IMPL_SHOT_LRF_H_
<commit_msg>Fixes compilation problem on Windows due to size_t variable in omp loop.<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */

#ifndef PCL_FEATURES_IMPL_SHOT_LRF_OMP_H_
#define PCL_FEATURES_IMPL_SHOT_LRF_OMP_H_

#include <utility>
#include <pcl/features/shot_lrf_omp.h>
#include <pcl/features/shot_lrf.h>

template<typename PointInT, typename PointOutT>
void
pcl::SHOTLocalReferenceFrameEstimationOMP<PointInT, PointOutT>::computeFeature (PointCloudOut &output)
{
  if (threads_ < 0)
    threads_ = 1;

  //check whether used with search radius or search k-neighbors
  if (this->getKSearch () != 0)
  {
    PCL_ERROR(
        "[pcl::%s::computeFeature] Error! Search method set to k-neighborhood. Call setKSearch(0) and setRadiusSearch( radius ) to use this class.\n",
        getClassName().c_str ());
    return;
  }
  tree_->setSortedResults (true);

  int data_size = static_cast<int> (indices_->size ());
#pragma omp parallel for num_threads(threads_)
  for (int i = 0; i < data_size; ++i)
  {
    // point result
    Eigen::Matrix3f rf;
    PointOutT& output_rf = output[i];

    //output_rf.confidence = getLocalRF ((*indices_)[i], rf);
    //if (output_rf.confidence == std::numeric_limits<float>::max ())

    std::vector<int> n_indices;
    std::vector<float> n_sqr_distances;
    searchForNeighbors ((*indices_)[i], search_parameter_, n_indices, n_sqr_distances);
    if (getLocalRF ((*indices_)[i], rf) == std::numeric_limits<float>::max ())
    {
      output.is_dense = false;
    }

    output_rf.x_axis.getNormalVector3fMap () = rf.row (0);
    output_rf.y_axis.getNormalVector3fMap () = rf.row (1);
    output_rf.z_axis.getNormalVector3fMap () = rf.row (2);
  }

}

template<typename PointInT, typename PointOutT>
void
pcl::SHOTLocalReferenceFrameEstimationOMP<PointInT, PointOutT>::computeFeatureEigen (pcl::PointCloud<Eigen::MatrixXf> &output)
{
  if (threads_ < 0)
     threads_ = 1;

  //check whether used with search radius or search k-neighbors
  if (this->getKSearch () != 0)
  {
    PCL_ERROR(
        "[pcl::%s::computeFeatureEigen] Error! Search method set to k-neighborhood. Call setKSearch(0) and setRadiusSearch( radius ) to use this class.\n",
        getClassName().c_str ());
    return;
  }
  tree_->setSortedResults (true);

  int data_size = static_cast<int> (indices_->size ());

  // Set up the output channels
  output.channels["shot_lrf"].name = "shot_lrf";
  output.channels["shot_lrf"].offset = 0;
  output.channels["shot_lrf"].size = 4;
  output.channels["shot_lrf"].count = 9;
  output.channels["shot_lrf"].datatype = sensor_msgs::PointField::FLOAT32;

  //output.points.resize (indices_->size (), 10);
  output.points.resize (data_size, 9);

#pragma omp parallel for num_threads(threads_)
  for (int i = 0; i < data_size; ++i)
  {
    // point result
    Eigen::Matrix3f rf;

    //output.points (i, 9) = getLocalRF ((*indices_)[i], rf);
    //if (output.points (i, 9) == std::numeric_limits<float>::max ())
    if (getLocalRF ((*indices_)[i], rf) == std::numeric_limits<float>::max ())
    {
      output.is_dense = false;
    }

    output.points.block<1, 3> (i, 0) = rf.row (0);
    output.points.block<1, 3> (i, 3) = rf.row (1);
    output.points.block<1, 3> (i, 6) = rf.row (2);
  }

}

#define PCL_INSTANTIATE_SHOTLocalReferenceFrameEstimationOMP(T,OutT) template class PCL_EXPORTS pcl::SHOTLocalReferenceFrameEstimationOMP<T,OutT>;

#endif    // PCL_FEATURES_IMPL_SHOT_LRF_H_
<|endoftext|>


<commit_before>#define NOD_ATHENA 1
#include "DNAMP2.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
#include "CMDL.hpp"
#include "ANCS.hpp"
#include "CINF.hpp"
#include "MREA.hpp"
#include "MAPA.hpp"
#include "MAPU.hpp"
#include "PATH.hpp"
#include "AFSM.hpp"
#include "SAVW.hpp"
#include "AGSC.hpp"
#include "../DNAMP1/HINT.hpp"
#include "../DNAMP1/CSNG.hpp"
#include "DataSpec/DNACommon/FSM2.hpp"
#include "DataSpec/DNACommon/TXTR.hpp"
#include "DataSpec/DNACommon/FONT.hpp"
#include "DataSpec/DNACommon/DGRP.hpp"
#include "DataSpec/DNACommon/ATBL.hpp"
#include "Runtime/GCNTypes.hpp"

namespace DataSpec::DNAMP2 {
logvisor::Module Log("urde::DNAMP2");

static bool GetNoShare(std::string_view name) {
  if (name == "FrontEnd.pak"sv)
    return false;
  std::string lowerName(name);
  std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
  if (lowerName.compare(0, 7, "metroid") == 0)
    return false;
  if (lowerName.compare(0, 8, "frontend") == 0)
    return false;
  return true;
}

PAKBridge::PAKBridge(const nod::Node& node, bool doExtract)
: m_node(node), m_pak(true, GetNoShare(node.getName())), m_doExtract(doExtract) {
  nod::AthenaPartReadStream rs(node.beginReadStream());
  m_pak.read(rs);

  /* Append Level String */
  for (const auto& entry : m_pak.m_entries) {
    const DNAMP2::PAK::Entry& e = entry.second;
    if (e.type == FOURCC('MLVL')) {
      PAKEntryReadStream rs = e.beginReadStream(m_node);
      MLVL mlvl;
      mlvl.read(rs);
      const DNAMP2::PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
      if (nameEnt) {
        PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
        STRG mlvlName;
        mlvlName.read(rs);
        if (m_levelString.size())
          m_levelString += _SYS_STR(", ");
        m_levelString += mlvlName.getSystemString(FOURCC('ENGL'), 0);
      }
    }
  }
}

static hecl::SystemString LayerName(std::string_view name) {
  hecl::SystemString ret(hecl::SystemStringConv(name).sys_str());
  for (auto& ch : ret)
    if (ch == _SYS_STR('/') || ch == _SYS_STR('\\'))
      ch = _SYS_STR('-');
  return ret;
}

void PAKBridge::build() {
  /* First pass: build per-area/per-layer dependency map */
  for (const auto& entry : m_pak.m_entries) {
    const DNAMP2::PAK::Entry& e = entry.second;
    if (e.type == FOURCC('MLVL')) {
      Level& level = m_levelDeps[e.id];

      MLVL mlvl;
      {
        PAKEntryReadStream rs = e.beginReadStream(m_node);
        mlvl.read(rs);
      }
      std::string catalogueName;
      std::string bestName = m_pak.bestEntryName(m_node, e, catalogueName);
      level.name = hecl::SystemStringConv(bestName).sys_str();
      level.areas.reserve(mlvl.areaCount);
      unsigned layerIdx = 0;

      /* Make MAPW available to lookup MAPAs */
      const DNAMP2::PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap);
      std::vector<UniqueID32> mapw;
      if (worldMapEnt) {
        PAKEntryReadStream rs = worldMapEnt->beginReadStream(m_node);
        rs.seek(8, athena::SeekOrigin::Current);
        atUint32 areaCount = rs.readUint32Big();
        mapw.reserve(areaCount);
        for (atUint32 i = 0; i < areaCount; ++i)
          mapw.emplace_back(rs);
      }

      /* Index areas */
      unsigned ai = 0;
      for (const MLVL::Area& area : mlvl.areas) {
        Level::Area& areaDeps = level.areas[area.areaMREAId];
        MLVL::LayerFlags& layerFlags = mlvl.layerFlags[ai];
        const DNAMP2::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
        if (areaNameEnt) {
          STRG areaName;
          {
            PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
            areaName.read(rs);
          }
          areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0);
          areaDeps.name = hecl::StringUtils::TrimWhitespace(areaDeps.name);
        }
        if (areaDeps.name.empty()) {
          areaDeps.name = hecl::SystemStringConv(area.internalAreaName).sys_str();
          if (areaDeps.name.empty()) {
            std::string idStr = area.areaMREAId.toString();
            areaDeps.name = hecl::SystemString(_SYS_STR("MREA_")) + hecl::SystemStringConv(idStr).c_str();
          }
        }
        hecl::SystemString num = fmt::format(fmt(_SYS_STR("{:02d} ")), ai);
        areaDeps.name = num + areaDeps.name;

        areaDeps.layers.reserve(area.depLayerCount - 1);
        unsigned r = 0;
        for (unsigned l = 1; l < area.depLayerCount; ++l) {
          areaDeps.layers.emplace_back();
          Level::Area::Layer& layer = areaDeps.layers.back();
          layer.name = LayerName(mlvl.layerNames[layerIdx++]);
          layer.active = layerFlags.flags >> (l - 1) & 0x1;
          layer.name = hecl::StringUtils::TrimWhitespace(layer.name);
          num = fmt::format(fmt(_SYS_STR("{:02d} ")), l - 1);
          layer.name = num + layer.name;

          layer.resources.reserve(area.depLayers[l] - r);
          for (; r < area.depLayers[l]; ++r)
            layer.resources.emplace(area.deps[r].id);
        }
        areaDeps.resources.reserve(area.depCount - r + 2);
        for (; r < area.depCount; ++r)
          areaDeps.resources.emplace(area.deps[r].id);
        areaDeps.resources.emplace(area.areaMREAId);
        if (mapw.size() > ai)
          areaDeps.resources.emplace(mapw[ai]);
        ++ai;
      }
    }
  }

  /* Second pass: cross-compare uniqueness */
  for (auto& entry : m_pak.m_entries) {
    entry.second.unique.checkEntry(*this, entry.second);
  }
}

void PAKBridge::addCMDLRigPairs(PAKRouter<PAKBridge>& pakRouter, CharacterAssociations<UniqueID32>& charAssoc) const {
  for (const auto& entry : m_pak.m_entries) {
    if (entry.second.type == FOURCC('ANCS')) {
      PAKEntryReadStream rs = entry.second.beginReadStream(m_node);
      ANCS ancs;
      ancs.read(rs);
      for (const ANCS::CharacterSet::CharacterInfo& ci : ancs.characterSet.characters) {
        charAssoc.m_cmdlRigs[ci.cmdl] = {ci.cskr, ci.cinf};
        charAssoc.m_cskrToCharacter[ci.cskr] =
            std::make_pair(entry.second.id, fmt::format(fmt("{}_{}.CSKR"), ci.name, ci.cskr));
        if (ci.cmdlIce.isValid()) {
          charAssoc.m_cmdlRigs[ci.cmdlIce] = {ci.cskrIce, ci.cinf};
          charAssoc.m_cskrToCharacter[ci.cskrIce] =
              std::make_pair(entry.second.id, fmt::format(fmt("{}.ICE_{}.CSKR"), ci.name, ci.cskrIce));
        }
      }
    }
  }
}

void PAKBridge::addPATHToMREA(PAKRouter<PAKBridge>& pakRouter,
                              std::unordered_map<UniqueID32, UniqueID32>& pathToMrea) const {
  for (const auto& [id, entry] : m_pak.m_entries) {
    if (entry.type == FOURCC('MREA')) {
      PAKEntryReadStream rs = entry.beginReadStream(m_node);
      UniqueID32 pathID = MREA::GetPATHId(rs);
      if (pathID.isValid())
        pathToMrea[pathID] = id;
    }
  }
}

static const atVec4f BottomRow = {{0.f, 0.f, 0.f, 1.f}};

void PAKBridge::addMAPATransforms(PAKRouter<PAKBridge>& pakRouter,
                                  std::unordered_map<UniqueID32, zeus::CMatrix4f>& addTo,
                                  std::unordered_map<UniqueID32, hecl::ProjectPath>& pathOverrides) const {
  for (const auto& entry : m_pak.m_entries) {
    if (entry.second.type == FOURCC('MLVL')) {
      MLVL mlvl;
      {
        PAKEntryReadStream rs = entry.second.beginReadStream(m_node);
        mlvl.read(rs);
      }
      hecl::ProjectPath mlvlDirPath = pakRouter.getWorking(&entry.second).getParentPath();

      if (mlvl.worldNameId.isValid())
        pathOverrides[mlvl.worldNameId] = hecl::ProjectPath(mlvlDirPath,
            fmt::format(fmt(_SYS_STR("!name_{}.yaml")), mlvl.worldNameId));

      for (const MLVL::Area& area : mlvl.areas) {
        {
          /* Get PATH transform */
          const nod::Node* areaNode;
          const PAK::Entry* areaEntry = pakRouter.lookupEntry(area.areaMREAId, &areaNode);
          PAKEntryReadStream rs = areaEntry->beginReadStream(*areaNode);
          UniqueID32 pathId = MREA::GetPATHId(rs);
          if (pathId.isValid())
            addTo[pathId] = zeus::CMatrix4f(area.transformMtx[0], area.transformMtx[1], area.transformMtx[2], BottomRow)
                .transposed();
        }
        hecl::ProjectPath areaDirPath = pakRouter.getWorking(area.areaMREAId).getParentPath();
        if (area.areaNameId.isValid())
          pathOverrides[area.areaNameId] = hecl::ProjectPath(areaDirPath,
              fmt::format(fmt(_SYS_STR("!name_{}.yaml")), area.areaNameId));
      }

      if (mlvl.worldMap.isValid()) {
        const nod::Node* mapNode;
        const DNAMP2::PAK::Entry* mapEntry = pakRouter.lookupEntry(mlvl.worldMap, &mapNode);
        if (mapEntry) {
          PAKEntryReadStream rs = mapEntry->beginReadStream(*mapNode);
          u32 magic = rs.readUint32Big();
          if (magic == 0xDEADF00D) {
            rs.readUint32Big();
            u32 count = rs.readUint32Big();
            for (u32 i = 0; i < count && i < mlvl.areas.size(); ++i) {
              MLVL::Area& areaData = mlvl.areas[i];
              UniqueID32 mapaId;
              mapaId.read(rs);
              addTo[mapaId] = zeus::CMatrix4f(areaData.transformMtx[0], areaData.transformMtx[1],
                                              areaData.transformMtx[2], BottomRow)
                                  .transposed();
            }
          }
        }
      }
    }
  }
}

ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const nod::Node& pakNode, const DNAMP2::PAK& pak,
                                                   const DNAMP2::PAK::Entry& entry) {
  switch (entry.type.toUint32()) {
  case SBIG('HINT'):
    return {DNAMP1::HINT::Extract, {_SYS_STR(".yaml")}};
  case SBIG('STRG'):
    return {STRG::Extract, {_SYS_STR(".yaml")}};
  case SBIG('TXTR'):
    return {TXTR::Extract, {_SYS_STR(".png")}};
  case SBIG('AFSM'):
    return {AFSM::Extract, {_SYS_STR(".yaml")}};
  case SBIG('SAVW'):
    return {SAVWCommon::ExtractSAVW<SAVW>, {_SYS_STR(".yaml")}};
  case SBIG('CMDL'):
    return {CMDL::Extract, {_SYS_STR(".blend")}, 1};
  case SBIG('CINF'):
    return {CINF::Extract<PAKBridge>, {_SYS_STR(".blend")}, 1};
  case SBIG('ANCS'):
    return {ANCS::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2};
  case SBIG('MLVL'):
    return {MLVL::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 3};
  case SBIG('MREA'):
    return {MREA::Extract, {_SYS_STR(".blend")}, 4};
  case SBIG('MAPA'):
    return {MAPA::Extract, {_SYS_STR(".blend")}, 4};
  case SBIG('MAPU'):
    return {MAPU::Extract, {_SYS_STR(".blend")}, 5};
  case SBIG('PATH'):
    return {PATH::Extract, {_SYS_STR(".blend")}, 5};
  case SBIG('FSM2'):
    return {DNAFSM2::ExtractFSM2<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('FONT'):
    return {DNAFont::ExtractFONT<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('DGRP'):
    return {DNADGRP::ExtractDGRP<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('AGSC'):
    return {AGSC::Extract, {}};
  case SBIG('CSNG'):
    return {DNAMP1::CSNG::Extract, {_SYS_STR(".mid"), _SYS_STR(".yaml")}};
  case SBIG('ATBL'):
    return {DNAAudio::ATBL::Extract, {_SYS_STR(".yaml")}};
  }
  return {};
}

} // namespace DataSpec::DNAMP2
<commit_msg>Remove redundant condition from MP2's GetNoShare<commit_after>#define NOD_ATHENA 1
#include "DNAMP2.hpp"
#include "STRG.hpp"
#include "MLVL.hpp"
#include "CMDL.hpp"
#include "ANCS.hpp"
#include "CINF.hpp"
#include "MREA.hpp"
#include "MAPA.hpp"
#include "MAPU.hpp"
#include "PATH.hpp"
#include "AFSM.hpp"
#include "SAVW.hpp"
#include "AGSC.hpp"
#include "../DNAMP1/HINT.hpp"
#include "../DNAMP1/CSNG.hpp"
#include "DataSpec/DNACommon/FSM2.hpp"
#include "DataSpec/DNACommon/TXTR.hpp"
#include "DataSpec/DNACommon/FONT.hpp"
#include "DataSpec/DNACommon/DGRP.hpp"
#include "DataSpec/DNACommon/ATBL.hpp"
#include "Runtime/GCNTypes.hpp"

namespace DataSpec::DNAMP2 {
logvisor::Module Log("urde::DNAMP2");

static bool GetNoShare(std::string_view name) {
  std::string lowerName(name);
  std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
  if (lowerName.compare(0, 7, "metroid") == 0)
    return false;
  if (lowerName.compare(0, 8, "frontend") == 0)
    return false;
  return true;
}

PAKBridge::PAKBridge(const nod::Node& node, bool doExtract)
: m_node(node), m_pak(true, GetNoShare(node.getName())), m_doExtract(doExtract) {
  nod::AthenaPartReadStream rs(node.beginReadStream());
  m_pak.read(rs);

  /* Append Level String */
  for (const auto& entry : m_pak.m_entries) {
    const DNAMP2::PAK::Entry& e = entry.second;
    if (e.type == FOURCC('MLVL')) {
      PAKEntryReadStream rs = e.beginReadStream(m_node);
      MLVL mlvl;
      mlvl.read(rs);
      const DNAMP2::PAK::Entry* nameEnt = m_pak.lookupEntry(mlvl.worldNameId);
      if (nameEnt) {
        PAKEntryReadStream rs = nameEnt->beginReadStream(m_node);
        STRG mlvlName;
        mlvlName.read(rs);
        if (m_levelString.size())
          m_levelString += _SYS_STR(", ");
        m_levelString += mlvlName.getSystemString(FOURCC('ENGL'), 0);
      }
    }
  }
}

static hecl::SystemString LayerName(std::string_view name) {
  hecl::SystemString ret(hecl::SystemStringConv(name).sys_str());
  for (auto& ch : ret)
    if (ch == _SYS_STR('/') || ch == _SYS_STR('\\'))
      ch = _SYS_STR('-');
  return ret;
}

void PAKBridge::build() {
  /* First pass: build per-area/per-layer dependency map */
  for (const auto& entry : m_pak.m_entries) {
    const DNAMP2::PAK::Entry& e = entry.second;
    if (e.type == FOURCC('MLVL')) {
      Level& level = m_levelDeps[e.id];

      MLVL mlvl;
      {
        PAKEntryReadStream rs = e.beginReadStream(m_node);
        mlvl.read(rs);
      }
      std::string catalogueName;
      std::string bestName = m_pak.bestEntryName(m_node, e, catalogueName);
      level.name = hecl::SystemStringConv(bestName).sys_str();
      level.areas.reserve(mlvl.areaCount);
      unsigned layerIdx = 0;

      /* Make MAPW available to lookup MAPAs */
      const DNAMP2::PAK::Entry* worldMapEnt = m_pak.lookupEntry(mlvl.worldMap);
      std::vector<UniqueID32> mapw;
      if (worldMapEnt) {
        PAKEntryReadStream rs = worldMapEnt->beginReadStream(m_node);
        rs.seek(8, athena::SeekOrigin::Current);
        atUint32 areaCount = rs.readUint32Big();
        mapw.reserve(areaCount);
        for (atUint32 i = 0; i < areaCount; ++i)
          mapw.emplace_back(rs);
      }

      /* Index areas */
      unsigned ai = 0;
      for (const MLVL::Area& area : mlvl.areas) {
        Level::Area& areaDeps = level.areas[area.areaMREAId];
        MLVL::LayerFlags& layerFlags = mlvl.layerFlags[ai];
        const DNAMP2::PAK::Entry* areaNameEnt = m_pak.lookupEntry(area.areaNameId);
        if (areaNameEnt) {
          STRG areaName;
          {
            PAKEntryReadStream rs = areaNameEnt->beginReadStream(m_node);
            areaName.read(rs);
          }
          areaDeps.name = areaName.getSystemString(FOURCC('ENGL'), 0);
          areaDeps.name = hecl::StringUtils::TrimWhitespace(areaDeps.name);
        }
        if (areaDeps.name.empty()) {
          areaDeps.name = hecl::SystemStringConv(area.internalAreaName).sys_str();
          if (areaDeps.name.empty()) {
            std::string idStr = area.areaMREAId.toString();
            areaDeps.name = hecl::SystemString(_SYS_STR("MREA_")) + hecl::SystemStringConv(idStr).c_str();
          }
        }
        hecl::SystemString num = fmt::format(fmt(_SYS_STR("{:02d} ")), ai);
        areaDeps.name = num + areaDeps.name;

        areaDeps.layers.reserve(area.depLayerCount - 1);
        unsigned r = 0;
        for (unsigned l = 1; l < area.depLayerCount; ++l) {
          areaDeps.layers.emplace_back();
          Level::Area::Layer& layer = areaDeps.layers.back();
          layer.name = LayerName(mlvl.layerNames[layerIdx++]);
          layer.active = layerFlags.flags >> (l - 1) & 0x1;
          layer.name = hecl::StringUtils::TrimWhitespace(layer.name);
          num = fmt::format(fmt(_SYS_STR("{:02d} ")), l - 1);
          layer.name = num + layer.name;

          layer.resources.reserve(area.depLayers[l] - r);
          for (; r < area.depLayers[l]; ++r)
            layer.resources.emplace(area.deps[r].id);
        }
        areaDeps.resources.reserve(area.depCount - r + 2);
        for (; r < area.depCount; ++r)
          areaDeps.resources.emplace(area.deps[r].id);
        areaDeps.resources.emplace(area.areaMREAId);
        if (mapw.size() > ai)
          areaDeps.resources.emplace(mapw[ai]);
        ++ai;
      }
    }
  }

  /* Second pass: cross-compare uniqueness */
  for (auto& entry : m_pak.m_entries) {
    entry.second.unique.checkEntry(*this, entry.second);
  }
}

void PAKBridge::addCMDLRigPairs(PAKRouter<PAKBridge>& pakRouter, CharacterAssociations<UniqueID32>& charAssoc) const {
  for (const auto& entry : m_pak.m_entries) {
    if (entry.second.type == FOURCC('ANCS')) {
      PAKEntryReadStream rs = entry.second.beginReadStream(m_node);
      ANCS ancs;
      ancs.read(rs);
      for (const ANCS::CharacterSet::CharacterInfo& ci : ancs.characterSet.characters) {
        charAssoc.m_cmdlRigs[ci.cmdl] = {ci.cskr, ci.cinf};
        charAssoc.m_cskrToCharacter[ci.cskr] =
            std::make_pair(entry.second.id, fmt::format(fmt("{}_{}.CSKR"), ci.name, ci.cskr));
        if (ci.cmdlIce.isValid()) {
          charAssoc.m_cmdlRigs[ci.cmdlIce] = {ci.cskrIce, ci.cinf};
          charAssoc.m_cskrToCharacter[ci.cskrIce] =
              std::make_pair(entry.second.id, fmt::format(fmt("{}.ICE_{}.CSKR"), ci.name, ci.cskrIce));
        }
      }
    }
  }
}

void PAKBridge::addPATHToMREA(PAKRouter<PAKBridge>& pakRouter,
                              std::unordered_map<UniqueID32, UniqueID32>& pathToMrea) const {
  for (const auto& [id, entry] : m_pak.m_entries) {
    if (entry.type == FOURCC('MREA')) {
      PAKEntryReadStream rs = entry.beginReadStream(m_node);
      UniqueID32 pathID = MREA::GetPATHId(rs);
      if (pathID.isValid())
        pathToMrea[pathID] = id;
    }
  }
}

static const atVec4f BottomRow = {{0.f, 0.f, 0.f, 1.f}};

void PAKBridge::addMAPATransforms(PAKRouter<PAKBridge>& pakRouter,
                                  std::unordered_map<UniqueID32, zeus::CMatrix4f>& addTo,
                                  std::unordered_map<UniqueID32, hecl::ProjectPath>& pathOverrides) const {
  for (const auto& entry : m_pak.m_entries) {
    if (entry.second.type == FOURCC('MLVL')) {
      MLVL mlvl;
      {
        PAKEntryReadStream rs = entry.second.beginReadStream(m_node);
        mlvl.read(rs);
      }
      hecl::ProjectPath mlvlDirPath = pakRouter.getWorking(&entry.second).getParentPath();

      if (mlvl.worldNameId.isValid())
        pathOverrides[mlvl.worldNameId] = hecl::ProjectPath(mlvlDirPath,
            fmt::format(fmt(_SYS_STR("!name_{}.yaml")), mlvl.worldNameId));

      for (const MLVL::Area& area : mlvl.areas) {
        {
          /* Get PATH transform */
          const nod::Node* areaNode;
          const PAK::Entry* areaEntry = pakRouter.lookupEntry(area.areaMREAId, &areaNode);
          PAKEntryReadStream rs = areaEntry->beginReadStream(*areaNode);
          UniqueID32 pathId = MREA::GetPATHId(rs);
          if (pathId.isValid())
            addTo[pathId] = zeus::CMatrix4f(area.transformMtx[0], area.transformMtx[1], area.transformMtx[2], BottomRow)
                .transposed();
        }
        hecl::ProjectPath areaDirPath = pakRouter.getWorking(area.areaMREAId).getParentPath();
        if (area.areaNameId.isValid())
          pathOverrides[area.areaNameId] = hecl::ProjectPath(areaDirPath,
              fmt::format(fmt(_SYS_STR("!name_{}.yaml")), area.areaNameId));
      }

      if (mlvl.worldMap.isValid()) {
        const nod::Node* mapNode;
        const DNAMP2::PAK::Entry* mapEntry = pakRouter.lookupEntry(mlvl.worldMap, &mapNode);
        if (mapEntry) {
          PAKEntryReadStream rs = mapEntry->beginReadStream(*mapNode);
          u32 magic = rs.readUint32Big();
          if (magic == 0xDEADF00D) {
            rs.readUint32Big();
            u32 count = rs.readUint32Big();
            for (u32 i = 0; i < count && i < mlvl.areas.size(); ++i) {
              MLVL::Area& areaData = mlvl.areas[i];
              UniqueID32 mapaId;
              mapaId.read(rs);
              addTo[mapaId] = zeus::CMatrix4f(areaData.transformMtx[0], areaData.transformMtx[1],
                                              areaData.transformMtx[2], BottomRow)
                                  .transposed();
            }
          }
        }
      }
    }
  }
}

ResExtractor<PAKBridge> PAKBridge::LookupExtractor(const nod::Node& pakNode, const DNAMP2::PAK& pak,
                                                   const DNAMP2::PAK::Entry& entry) {
  switch (entry.type.toUint32()) {
  case SBIG('HINT'):
    return {DNAMP1::HINT::Extract, {_SYS_STR(".yaml")}};
  case SBIG('STRG'):
    return {STRG::Extract, {_SYS_STR(".yaml")}};
  case SBIG('TXTR'):
    return {TXTR::Extract, {_SYS_STR(".png")}};
  case SBIG('AFSM'):
    return {AFSM::Extract, {_SYS_STR(".yaml")}};
  case SBIG('SAVW'):
    return {SAVWCommon::ExtractSAVW<SAVW>, {_SYS_STR(".yaml")}};
  case SBIG('CMDL'):
    return {CMDL::Extract, {_SYS_STR(".blend")}, 1};
  case SBIG('CINF'):
    return {CINF::Extract<PAKBridge>, {_SYS_STR(".blend")}, 1};
  case SBIG('ANCS'):
    return {ANCS::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2};
  case SBIG('MLVL'):
    return {MLVL::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 3};
  case SBIG('MREA'):
    return {MREA::Extract, {_SYS_STR(".blend")}, 4};
  case SBIG('MAPA'):
    return {MAPA::Extract, {_SYS_STR(".blend")}, 4};
  case SBIG('MAPU'):
    return {MAPU::Extract, {_SYS_STR(".blend")}, 5};
  case SBIG('PATH'):
    return {PATH::Extract, {_SYS_STR(".blend")}, 5};
  case SBIG('FSM2'):
    return {DNAFSM2::ExtractFSM2<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('FONT'):
    return {DNAFont::ExtractFONT<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('DGRP'):
    return {DNADGRP::ExtractDGRP<UniqueID32>, {_SYS_STR(".yaml")}};
  case SBIG('AGSC'):
    return {AGSC::Extract, {}};
  case SBIG('CSNG'):
    return {DNAMP1::CSNG::Extract, {_SYS_STR(".mid"), _SYS_STR(".yaml")}};
  case SBIG('ATBL'):
    return {DNAAudio::ATBL::Extract, {_SYS_STR(".yaml")}};
  }
  return {};
}

} // namespace DataSpec::DNAMP2
<|endoftext|>


<commit_before>#ifndef __CINT__
#include "TMath.h"
#include "AliCDBManager.h"
#include "AliTriggerScalers.h"
#include "AliTriggerRunScalers.h"
#include "AliTimeStamp.h"
#include "AliTriggerScalersRecord.h"
#include "AliTriggerConfiguration.h"
#include "AliLHCData.h"
#include "AliTriggerClass.h"
#include "AliTriggerBCMask.h"
#include "AliCDBPath.h"
#include "AliCDBEntry.h"
#endif

UInt_t dif(UInt_t stop, UInt_t start){
  UInt_t d;
  if(stop >= start) d=stop-start;
  else d = stop+(0xffffffff-start)+1;
  return d;
};

TObjArray GetClasses(Int_t run, TString ocdbStorage, TString &partition, TString &activeDetectors, Double_t& run_duration,
    ULong64_t* LMB, ULong64_t* LMA, ULong64_t* L0B, ULong64_t* L0A, ULong64_t* L1B, ULong64_t* L1A, ULong64_t* L2B, ULong64_t* L2A,ULong64_t* class_duration){
  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage(ocdbStorage.Data());
  man->SetRun(run);
  // Get scalers
  AliTriggerConfiguration* cfg = (AliTriggerConfiguration*) man->Get("GRP/CTP/Config")->GetObject();
  if (!cfg) { printf("No GRP/CTP/Config object for run %i\n",run); return TObjArray(); }

  partition = cfg->GetName();
  activeDetectors = cfg->GetActiveDetectors();

  TObjArray classes = cfg->GetClasses();

  AliTriggerRunScalers* scalers = (AliTriggerRunScalers*) man->Get("GRP/CTP/Scalers")->GetObject();
  if (!scalers) { printf("No GRP/CTP/Scalers object for run %i\n",run); return TObjArray(); }
  Int_t nEntries = scalers->GetScalersRecords()->GetEntriesFast();

  ULong64_t previousL2A[100];
  for (Int_t r=0;r<nEntries-1;r++){
    // Get SOR and EOR scaler records
    AliTriggerScalersRecord* record1 = scalers->GetScalersRecord(r);
    AliTriggerScalersRecord* record2 = scalers->GetScalersRecord(r+1);
    if (!record1) { printf("Null pointer to scalers record\n"); return TObjArray(); }
    if (!record2) { printf("Null pointer to scalers record\n"); return TObjArray(); }
    for (Int_t i=0;i<classes.GetEntriesFast();i++){
      // Extract SOR and EOR trigger counts
      Int_t classId = cfg->GetClassIndexFromName(classes.At(i)->GetName());
      const AliTriggerScalers* scaler1 = record1->GetTriggerScalersForClass(classId);
      const AliTriggerScalers* scaler2 = record2->GetTriggerScalersForClass(classId);
      if (!scaler1) { printf("Null pointer to scalers for class\n"); return TObjArray(); }
      if (!scaler2) { printf("Null pointer to scalers for class\n"); return TObjArray(); }

      LMB[i] += dif(scaler2->GetLMCB(),scaler1->GetLMCB());
      LMA[i] += dif(scaler2->GetLMCA(),scaler1->GetLMCA());
      L0B[i] += dif(scaler2->GetLOCB(),scaler1->GetLOCB());
      L0A[i] += dif(scaler2->GetLOCA(),scaler1->GetLOCA());
      L1B[i] += dif(scaler2->GetL1CB(),scaler1->GetL1CB());
      L1A[i] += dif(scaler2->GetL1CA(),scaler1->GetL1CA());
      L2B[i] += dif(scaler2->GetL2CB(),scaler1->GetL2CB());
      L2A[i] += dif(scaler2->GetL2CA(),scaler1->GetL2CA());
      if (L2A[i]==previousL2A[i]) continue;
      previousL2A[i]=L2A[i];
      class_duration[i]+=dif(record2->GetTimeStamp()->GetSeconds(),record1->GetTimeStamp()->GetSeconds());
    }
  }
  UInt_t t1 = scalers->GetScalersRecord(0         )->GetTimeStamp()->GetSeconds();
  UInt_t t2 = scalers->GetScalersRecord(nEntries-1)->GetTimeStamp()->GetSeconds();
  run_duration = dif(t2,t1);
  return classes;
}

Int_t triggerInfo(Int_t run, TString ocdbStorage, TString &lhcPeriod, TString &lhcState,
    Int_t &fill, Int_t &nBCsPerOrbit, Int_t &timeStart, Int_t &timeEnd){

  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage(ocdbStorage.Data());
  man->SetRun(run);

  AliGRPObject* grp = (AliGRPObject*) man->Get("GRP/GRP/Data")->GetObject();
  if (!grp) { printf("No GRP/GRP/Data object for run %i\n",run); return 1; }
  lhcState  = grp->GetLHCState();
  lhcPeriod = grp->GetLHCPeriod();
  timeStart = grp->GetTimeStart();
  timeEnd   = grp->GetTimeEnd();

  if (run==189694) return 1; // No GRP/GRP/LHCData for this run

  AliLHCData* lhc = (AliLHCData*) man->Get("GRP/GRP/LHCData")->GetObject();
  if (!lhc) { printf("No GRP/GRP/LHCData object for run %i\n",run); return 1; }
  fill = lhc->GetFillNumber();
  nBCsPerOrbit = lhc->GetNInteractingBunchesMeasured();

  return 0;
}
<commit_msg>triggerInfo.C using Includes.h<commit_after>#ifndef __CINT__
#include "Includes.h"
#endif

UInt_t dif(UInt_t stop, UInt_t start){
  UInt_t d;
  if(stop >= start) d=stop-start;
  else d = stop+(0xffffffff-start)+1;
  return d;
};

TObjArray GetClasses(Int_t run, TString ocdbStorage, TString &partition, TString &activeDetectors, Double_t& run_duration,
    ULong64_t* LMB, ULong64_t* LMA, ULong64_t* L0B, ULong64_t* L0A, ULong64_t* L1B, ULong64_t* L1A, ULong64_t* L2B, ULong64_t* L2A,ULong64_t* class_duration){
  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage(ocdbStorage.Data());
  man->SetRun(run);
  // Get scalers
  AliTriggerConfiguration* cfg = (AliTriggerConfiguration*) man->Get("GRP/CTP/Config")->GetObject();
  if (!cfg) { printf("No GRP/CTP/Config object for run %i\n",run); return TObjArray(); }

  partition = cfg->GetName();
  activeDetectors = cfg->GetActiveDetectors();

  TObjArray classes = cfg->GetClasses();

  AliTriggerRunScalers* scalers = (AliTriggerRunScalers*) man->Get("GRP/CTP/Scalers")->GetObject();
  if (!scalers) { printf("No GRP/CTP/Scalers object for run %i\n",run); return TObjArray(); }
  Int_t nEntries = scalers->GetScalersRecords()->GetEntriesFast();

  ULong64_t previousL2A[100];
  for (Int_t r=0;r<nEntries-1;r++){
    // Get SOR and EOR scaler records
    AliTriggerScalersRecord* record1 = scalers->GetScalersRecord(r);
    AliTriggerScalersRecord* record2 = scalers->GetScalersRecord(r+1);
    if (!record1) { printf("Null pointer to scalers record\n"); return TObjArray(); }
    if (!record2) { printf("Null pointer to scalers record\n"); return TObjArray(); }
    for (Int_t i=0;i<classes.GetEntriesFast();i++){
      // Extract SOR and EOR trigger counts
      Int_t classId = cfg->GetClassIndexFromName(classes.At(i)->GetName());
      const AliTriggerScalers* scaler1 = record1->GetTriggerScalersForClass(classId);
      const AliTriggerScalers* scaler2 = record2->GetTriggerScalersForClass(classId);
      if (!scaler1) { printf("Null pointer to scalers for class\n"); return TObjArray(); }
      if (!scaler2) { printf("Null pointer to scalers for class\n"); return TObjArray(); }

      LMB[i] += dif(scaler2->GetLMCB(),scaler1->GetLMCB());
      LMA[i] += dif(scaler2->GetLMCA(),scaler1->GetLMCA());
      L0B[i] += dif(scaler2->GetLOCB(),scaler1->GetLOCB());
      L0A[i] += dif(scaler2->GetLOCA(),scaler1->GetLOCA());
      L1B[i] += dif(scaler2->GetL1CB(),scaler1->GetL1CB());
      L1A[i] += dif(scaler2->GetL1CA(),scaler1->GetL1CA());
      L2B[i] += dif(scaler2->GetL2CB(),scaler1->GetL2CB());
      L2A[i] += dif(scaler2->GetL2CA(),scaler1->GetL2CA());
      if (L2A[i]==previousL2A[i]) continue;
      previousL2A[i]=L2A[i];
      class_duration[i]+=dif(record2->GetTimeStamp()->GetSeconds(),record1->GetTimeStamp()->GetSeconds());
    }
  }
  UInt_t t1 = scalers->GetScalersRecord(0         )->GetTimeStamp()->GetSeconds();
  UInt_t t2 = scalers->GetScalersRecord(nEntries-1)->GetTimeStamp()->GetSeconds();
  run_duration = dif(t2,t1);
  return classes;
}

Int_t triggerInfo(Int_t run, TString ocdbStorage, TString &lhcPeriod, TString &lhcState,
    Int_t &fill, Int_t &nBCsPerOrbit, Int_t &timeStart, Int_t &timeEnd){

  AliCDBManager* man = AliCDBManager::Instance();
  man->SetDefaultStorage(ocdbStorage.Data());
  man->SetRun(run);

  AliGRPObject* grp = (AliGRPObject*) man->Get("GRP/GRP/Data")->GetObject();
  if (!grp) { printf("No GRP/GRP/Data object for run %i\n",run); return 1; }
  lhcState  = grp->GetLHCState();
  lhcPeriod = grp->GetLHCPeriod();
  timeStart = grp->GetTimeStart();
  timeEnd   = grp->GetTimeEnd();

  if (run==189694) return 1; // No GRP/GRP/LHCData for this run

  AliLHCData* lhc = (AliLHCData*) man->Get("GRP/GRP/LHCData")->GetObject();
  if (!lhc) { printf("No GRP/GRP/LHCData object for run %i\n",run); return 1; }
  fill = lhc->GetFillNumber();
  nBCsPerOrbit = lhc->GetNInteractingBunchesMeasured();

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

class MyStack
{
public:
    void Push(int key);
    int Pop();
    int PeekMedian();
private:
    multiset<int, greater<int> > lower;
    multiset<int> higher;
    stack<int> s;
};

void MyStack::Push(int key)
{
    s.push(key);
    if (lower.size() == higher.size())
    {
        if (lower.size() == 0)
        {
            higher.insert(key);
        }
        else
        {
            int x = *lower.begin();
            int y = *higher.begin();
            if (key >= x)
            {
                higher.insert(key);
            }
            else
            {
                lower.insert(key);
            }
        }
    }
    else if (lower.size() + 1 == higher.size())
    {
        if (lower.size() == 0)
        {
            lower.insert(key);
            int x = *lower.begin();
            int y = *higher.begin();
            if (x > y)
            {
                lower.erase(x);
                lower.insert(y);
                higher.erase(y);
                higher.insert(x);
            }
        }
        else
        {
            int y = *higher.begin();
            if (key <= y)
            {
                lower.insert(key);
            }
            else
            {
                higher.insert(key);
                int yy = *higher.begin();
                higher.erase(yy);
                lower.insert(yy);
            }
        }
    }
    else if (lower.size() == higher.size() + 1)
    {
        int x = *lower.begin();
        if (key >= x)
        {
            higher.insert(key);
        }
        else
        {
            lower.insert(key);
            int xx = *lower.begin();
            lower.erase(xx);
            higher.insert(xx);
        }
    }
}

int MyStack::Pop()
{
    // empty stack
    if (s.size() == 0)
    {
        return -1;
    }

    int key = s.top();
    s.pop();

    if (lower.size() == higher.size())
    {
        if (lower.count(key) > 0)
        {
            lower.erase(key);
        }
        else
        {
            higher.erase(key);
        }
    }
    else if (lower.size() + 1 == higher.size())
    {
        if (higher.count(key) > 0)
        {
            higher.erase(key);
        }
        else
        {
            lower.erase(key);
            int y = *higher.begin();
            higher.erase(y);
            lower.insert(y);
        }
    }
    else if (lower.size() == 1 + higher.size())
    {
        if (lower.count(key) > 0)
        {
            lower.erase(key);
        }
        else
        {
            higher.erase(key);
            int x = *lower.begin();
            lower.erase(x);
            higher.insert(x);
        }
    }
    return key;
}

int MyStack::PeekMedian()
{
    // empty stack
    if (s.size() == 0)
    {
        return -1;
    }

    if (lower.size() == higher.size())
    {
        if (lower.size() == 0)
        {
            return -1;
        }
        else
        {
            return *lower.begin();
        }
    }
    else if (lower.size() + 1 == higher.size())
    {
        return *higher.begin();
    }
    else if (lower.size() == 1 + higher.size())
    {
        return *lower.begin();
    }
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    char keyword[20];
    int key;
    MyStack ms;
    for (int k = 0; k < n; ++k)
    {
        scanf("%s", keyword);
        if (strcmp(keyword, "Push") == 0)
        {
            scanf("%d", &key);
            ms.Push(key);
        }
        else if (strcmp(keyword, "Pop") == 0)
        {
            int ans = ms.Pop();
            if (ans == -1)
            {
                printf("Invalid\n");
            }
            else
            {
                printf("%d\n", ans);
            }
        }
        else if (strcmp(keyword, "PeekMedian") == 0)
        {
            int ans = ms.PeekMedian();
            if (ans == -1)
            {
                printf("Invalid\n");
            }
            else
            {
                printf("%d\n", ans);
            }
        }
        else
        {
            printf("Invalid\n");
        }

    }
    return 0;
}
<commit_msg>more elegant, but still have 2 samples WA, to debug<commit_after>#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

// special stack:
// Push: O(logn)
// Pop:	 O(logn)
// PeekMedian: O(1)
class MyStack
{
public:
    void Push(int key);
    int Pop();
    int PeekMedian();
private:
    multiset<int, greater<int> > lower; // numbers smaller than median, decrease order
    multiset<int> higher;				// numbers greater than median, increase order
    stack<int> s;						// normal stack
};

void MyStack::Push(int key)
{
    s.push(key);
    if (lower.size() == higher.size())
    {
        if (lower.size() == 0)
        {
            higher.insert(key);
        }
        else
        {
            int x = *lower.begin();
            int y = *higher.begin();
            if (key >= x)
            {
                higher.insert(key);
            }
            else
            {
                lower.insert(key);
            }
        }
    }
    else if (lower.size() + 1 == higher.size())
    {

		int y = *higher.begin();
		if (key <= y)
		{
			lower.insert(key);
		}
		else
		{
			// adjust lower and higher, keep lower.size() = higher.size()
			//                               lower.size() = higher.size() + 1
			//                               lower.size() = higher.size() - 1
			higher.insert(key);
			int yy = *higher.begin();
			higher.erase(yy);
			lower.insert(yy);
		}

    }
    else if (lower.size() == higher.size() + 1)
    {
        int x = *lower.begin();
        if (key >= x)
        {
            higher.insert(key);
        }
        else
        {
            lower.insert(key);
            int xx = *lower.begin();
            lower.erase(xx);
            higher.insert(xx);
        }
    }
}

int MyStack::Pop()
{
    // empty stack
    if (s.size() == 0)
    {
        return -1;
    }

    int key = s.top();
    s.pop();

    if (lower.size() == higher.size())
    {
        if (lower.count(key) > 0)
        {
            lower.erase(key);
        }
        else
        {
            higher.erase(key);
        }
    }
    else if (lower.size() + 1 == higher.size())
    {
        if (higher.count(key) > 0)
        {
            higher.erase(key);
        }
        else
        {
            lower.erase(key);
            int y = *higher.begin();
            higher.erase(y);
            lower.insert(y);
        }
    }
    else if (lower.size() == 1 + higher.size())
    {
        if (lower.count(key) > 0)
        {
            lower.erase(key);
        }
        else
        {
            higher.erase(key);
            int x = *lower.begin();
            lower.erase(x);
            higher.insert(x);
        }
    }
    return key;
}

int MyStack::PeekMedian()
{
    // empty stack
    if (s.size() == 0)
    {
        return -1;
    }

    if (lower.size() == higher.size())
    {
        return *lower.begin();
    }
    else if (lower.size() + 1 == higher.size())
    {
        return *higher.begin();
    }
    else if (lower.size() == 1 + higher.size())
    {
        return *lower.begin();
    }
}

int main()
{
    int n = 0;
    scanf("%d", &n);
    char keyword[50];
    int key;
    MyStack ms;
    for (int k = 0; k < n; ++k)
    {
        scanf("%s", keyword);
        if (strcmp(keyword, "Push") == 0)
        {
            scanf("%d", &key);
            ms.Push(key);
        }
        else if (strcmp(keyword, "Pop") == 0)
        {
            int ans = ms.Pop();
            if (ans == -1)
            {
                printf("Invalid\n");
            }
            else
            {
                printf("%d\n", ans);
            }
        }
        else if (strcmp(keyword, "PeekMedian") == 0)
        {
            int ans = ms.PeekMedian();
            if (ans == -1)
            {
                printf("Invalid\n");
            }
            else
            {
                printf("%d\n", ans);
            }
        }
        else
        {
            printf("Invalid\n");
        }

    }
    return 0;
}
<|endoftext|>


<commit_before>#include "Halide.h"

using namespace Halide;

#include <iostream>
#include <limits>

#include "benchmark.h"
#include "halide_image_io.h"

using namespace Halide::Tools;

using std::vector;

int main(int argc, char **argv) {
    if (argc < 3) {
        std::cerr << "Usage:\n\t./interpolate in.png out.png\n" << std::endl;
        return 1;
    }

    ImageParam input(Float(32), 3);

    const int levels = 10;

    Func downsampled[levels];
    Func downx[levels];
    Func interpolated[levels];
    Func upsampled[levels];
    Func upsampledx[levels];
    Var x("x"), y("y"), c("c");

    Func clamped = BoundaryConditions::repeat_edge(input);

    // This triggers a bug in llvm 3.3 (3.2 and trunk are fine), so we
    // rewrite it in a way that doesn't trigger the bug. The rewritten
    // form assumes the input alpha is zero or one.
    // downsampled[0](x, y, c) = select(c < 3, clamped(x, y, c) * clamped(x, y, 3), clamped(x, y, 3));
    downsampled[0](x, y, c) = clamped(x, y, c) * clamped(x, y, 3);

    for (int l = 1; l < levels; ++l) {
        Func prev = downsampled[l-1];

        if (l == 4) {
            // Also add a boundary condition at a middle pyramid level
            // to prevent the footprint of the downsamplings to extend
            // too far off the base image. Otherwise we look 512
            // pixels off each edge.
            Expr w = input.width()/(1 << l);
            Expr h = input.height()/(1 << l);
            prev = lambda(x, y, c, prev(clamp(x, 0, w), clamp(y, 0, h), c));
        }

        downx[l](x, y, c) = (prev(x*2-1, y, c) +
                             2.0f * prev(x*2, y, c) +
                             prev(x*2+1, y, c)) * 0.25f;
        downsampled[l](x, y, c) = (downx[l](x, y*2-1, c) +
                                   2.0f * downx[l](x, y*2, c) +
                                   downx[l](x, y*2+1, c)) * 0.25f;
    }
    interpolated[levels-1](x, y, c) = downsampled[levels-1](x, y, c);
    for (int l = levels-2; l >= 0; --l) {
        upsampledx[l](x, y, c) = (interpolated[l+1](x/2, y, c) +
                                  interpolated[l+1]((x+1)/2, y, c)) / 2.0f;
        upsampled[l](x, y, c) =  (upsampledx[l](x, y/2, c) +
                                  upsampledx[l](x, (y+1)/2, c)) / 2.0f;
        interpolated[l](x, y, c) = downsampled[l](x, y, c) + (1.0f - downsampled[l](x, y, 3)) * upsampled[l](x, y, c);
    }

    Func normalize("normalize");
    normalize(x, y, c) = interpolated[0](x, y, c) / interpolated[0](x, y, 3);

    Func final("final");
    final(x, y, c) = normalize(x, y, c);

    std::cout << "Finished function setup." << std::endl;

    int sched;
    Target target = get_target_from_environment();
    if (target.has_gpu_feature()) {
        sched = 4;
    } else {
        sched = 2;
    }

    switch (sched) {
    case 0:
    {
        std::cout << "Flat schedule." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root();
            interpolated[l].compute_root();
        }
        final.compute_root();
        break;
    }
    case 1:
    {
        std::cout << "Flat schedule with vectorization." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root().vectorize(x,4);
            interpolated[l].compute_root().vectorize(x,4);
        }
        final.compute_root();
        break;
    }
    case 2:
    {
        Var xi, yi;
        std::cout << "Flat schedule with parallelization + vectorization." << std::endl;
        for (int l = 1; l < levels-1; ++l) {
            if (l > 0) downsampled[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].compute_root().parallel(y).reorder(c, x, y).reorder_storage(c, x, y).vectorize(c, 4);
            interpolated[l].unroll(x, 2).unroll(y, 2);
        }
        final.reorder(c, x, y).bound(c, 0, 3).parallel(y);
        final.tile(x, y, xi, yi, 2, 2).unroll(xi).unroll(yi);
        final.bound(x, 0, input.width());
        final.bound(y, 0, input.height());
        break;
    }
    case 3:
    {
        std::cout << "Flat schedule with vectorization sometimes." << std::endl;
        for (int l = 0; l < levels; ++l) {
            if (l + 4 < levels) {
                Var yo,yi;
                downsampled[l].compute_root().vectorize(x,4);
                interpolated[l].compute_root().vectorize(x,4);
            } else {
                downsampled[l].compute_root();
                interpolated[l].compute_root();
            }
        }
        final.compute_root();
        break;
    }
    case 4:
    {
        std::cout << "GPU schedule." << std::endl;

        // Some gpus don't have enough memory to process the entire
        // image, so we process the image in tiles.
        Var yo, yi, xo, xi;
        final.reorder(c, x, y).bound(c, 0, 3).vectorize(x, 4);
        final.tile(x, y, xo, yo, xi, yi, input.width()/8, input.height()/8);
        normalize.compute_at(final, xo).reorder(c, x, y).gpu_tile(x, y, 16, 16, DeviceAPI::Default_GPU).unroll(c);

        // Start from level 1 to save memory - level zero will be computed on demand
        for (int l = 1; l < levels; ++l) {
            int tile_size = 32 >> l;
            if (tile_size < 1) tile_size = 1;
            if (tile_size > 8) tile_size = 8;
            downsampled[l].compute_root();
            if (false) {
                // Outer loop on CPU for the larger ones.
                downsampled[l].tile(x, y, xo, yo, x, y, 256, 256);
            }
            downsampled[l].gpu_tile(x, y, c, tile_size, tile_size, 4, DeviceAPI::Default_GPU);
            interpolated[l].compute_at(final, xo).gpu_tile(x, y, c, tile_size, tile_size, 4, DeviceAPI::Default_GPU);
        }
        break;
    }
    default:
        assert(0 && "No schedule with this number.");
    }

    // JIT compile the pipeline eagerly, so we don't interfere with timing
    final.compile_jit(target);

    Image<float> in_png = load_image(argv[1]);
    Image<float> out(in_png.width(), in_png.height(), 3);
    assert(in_png.channels() == 4);
    input.set(in_png);

    std::cout << "Running... " << std::endl;
    double best = benchmark(20, 1, [&]() { final.realize(out); });
    std::cout << " took " << best * 1e3 << " msec." << std::endl;

    vector<Argument> args;
    args.push_back(input);
    final.compile_to_assembly("test.s", args, target);

    save_image(out, argv[2]);

}
<commit_msg>Clean up interpolate schedule<commit_after>#include "Halide.h"

using namespace Halide;

#include <iostream>
#include <limits>

#include "benchmark.h"
#include "halide_image_io.h"

using namespace Halide::Tools;

using std::vector;

int main(int argc, char **argv) {
    if (argc < 3) {
        std::cerr << "Usage:\n\t./interpolate in.png out.png\n" << std::endl;
        return 1;
    }

    ImageParam input(Float(32), 3);

    // Input must have four color channels - rgba
    input.set_bounds(2, 0, 4);

    const int levels = 10;

    Func downsampled[levels];
    Func downx[levels];
    Func interpolated[levels];
    Func upsampled[levels];
    Func upsampledx[levels];
    Var x("x"), y("y"), c("c");

    Func clamped = BoundaryConditions::repeat_edge(input);

    // This triggers a bug in llvm 3.3 (3.2 and trunk are fine), so we
    // rewrite it in a way that doesn't trigger the bug. The rewritten
    // form assumes the input alpha is zero or one.
    // downsampled[0](x, y, c) = select(c < 3, clamped(x, y, c) * clamped(x, y, 3), clamped(x, y, 3));
    downsampled[0](x, y, c) = clamped(x, y, c) * clamped(x, y, 3);

    for (int l = 1; l < levels; ++l) {
        Func prev = downsampled[l-1];

        if (l == 4) {
            // Also add a boundary condition at a middle pyramid level
            // to prevent the footprint of the downsamplings to extend
            // too far off the base image. Otherwise we look 512
            // pixels off each edge.
            Expr w = input.width()/(1 << l);
            Expr h = input.height()/(1 << l);
            prev = lambda(x, y, c, prev(clamp(x, 0, w), clamp(y, 0, h), c));
        }

        downx[l](x, y, c) = (prev(x*2-1, y, c) +
                             2.0f * prev(x*2, y, c) +
                             prev(x*2+1, y, c)) * 0.25f;
        downsampled[l](x, y, c) = (downx[l](x, y*2-1, c) +
                                   2.0f * downx[l](x, y*2, c) +
                                   downx[l](x, y*2+1, c)) * 0.25f;
    }
    interpolated[levels-1](x, y, c) = downsampled[levels-1](x, y, c);
    for (int l = levels-2; l >= 0; --l) {
        upsampledx[l](x, y, c) = (interpolated[l+1](x/2, y, c) +
                                  interpolated[l+1]((x+1)/2, y, c)) / 2.0f;
        upsampled[l](x, y, c) =  (upsampledx[l](x, y/2, c) +
                                  upsampledx[l](x, (y+1)/2, c)) / 2.0f;
        interpolated[l](x, y, c) = downsampled[l](x, y, c) + (1.0f - downsampled[l](x, y, 3)) * upsampled[l](x, y, c);
    }

    Func normalize("normalize");
    normalize(x, y, c) = interpolated[0](x, y, c) / interpolated[0](x, y, 3);

    Func final("final");
    final(x, y, c) = normalize(x, y, c);

    std::cout << "Finished function setup." << std::endl;

    int sched;
    Target target = get_target_from_environment();
    if (target.has_gpu_feature()) {
        sched = 4;
    } else {
        sched = 2;
    }

    switch (sched) {
    case 0:
    {
        std::cout << "Flat schedule." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root();
            interpolated[l].compute_root();
        }
        final.compute_root();
        break;
    }
    case 1:
    {
        std::cout << "Flat schedule with vectorization." << std::endl;
        for (int l = 0; l < levels; ++l) {
            downsampled[l].compute_root().vectorize(x,4);
            interpolated[l].compute_root().vectorize(x,4);
        }
        final.compute_root();
        break;
    }
    case 2:
    {
        Var xi, yi;
        std::cout << "Flat schedule with parallelization + vectorization." << std::endl;
        for (int l = 1; l < levels-1; ++l) {
            downsampled[l]
                .compute_root()
                .parallel(y, 8)
                .vectorize(x, 4);
            interpolated[l]
                .compute_root()
                .parallel(y, 8)
                .unroll(x, 2)
                .unroll(y, 2)
                .vectorize(x, 8);
        }
        final
            .reorder(c, x, y)
            .bound(c, 0, 3)
            .unroll(c)
            .tile(x, y, xi, yi, 2, 2)
            .unroll(xi)
            .unroll(yi)
            .parallel(y, 8)
            .vectorize(x, 8)
            .bound(x, 0, input.width())
            .bound(y, 0, input.height());
        break;
    }
    case 3:
    {
        std::cout << "Flat schedule with vectorization sometimes." << std::endl;
        for (int l = 0; l < levels; ++l) {
            if (l + 4 < levels) {
                Var yo,yi;
                downsampled[l].compute_root().vectorize(x,4);
                interpolated[l].compute_root().vectorize(x,4);
            } else {
                downsampled[l].compute_root();
                interpolated[l].compute_root();
            }
        }
        final.compute_root();
        break;
    }
    case 4:
    {
        std::cout << "GPU schedule." << std::endl;

        // Some gpus don't have enough memory to process the entire
        // image, so we process the image in tiles.
        Var yo, yi, xo, xi;
        final.reorder(c, x, y).bound(c, 0, 3).vectorize(x, 4);
        final.tile(x, y, xo, yo, xi, yi, input.width()/8, input.height()/8);
        normalize.compute_at(final, xo).reorder(c, x, y).gpu_tile(x, y, 16, 16, DeviceAPI::Default_GPU).unroll(c);

        // Start from level 1 to save memory - level zero will be computed on demand
        for (int l = 1; l < levels; ++l) {
            int tile_size = 32 >> l;
            if (tile_size < 1) tile_size = 1;
            if (tile_size > 8) tile_size = 8;
            downsampled[l].compute_root();
            if (false) {
                // Outer loop on CPU for the larger ones.
                downsampled[l].tile(x, y, xo, yo, x, y, 256, 256);
            }
            downsampled[l].gpu_tile(x, y, c, tile_size, tile_size, 4, DeviceAPI::Default_GPU);
            interpolated[l].compute_at(final, xo).gpu_tile(x, y, c, tile_size, tile_size, 4, DeviceAPI::Default_GPU);
        }
        break;
    }
    default:
        assert(0 && "No schedule with this number.");
    }

    // JIT compile the pipeline eagerly, so we don't interfere with timing
    final.compile_jit(target);

    Image<float> in_png = load_image(argv[1]);
    Image<float> out(in_png.width(), in_png.height(), 3);
    assert(in_png.channels() == 4);
    input.set(in_png);

    std::cout << "Running... " << std::endl;
    double best = benchmark(20, 1, [&]() { final.realize(out); });
    std::cout << " took " << best * 1e3 << " msec." << std::endl;

    vector<Argument> args;
    args.push_back(input);
    final.compile_to_assembly("test.s", args, target);

    save_image(out, argv[2]);

}
<|endoftext|>