<commit_before>
#include <OgrePrerequisites.h> // for OGRE_THREAD_SUPPORT

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <OgreMeshManager.h>
#include <OgreMesh.h>
#include <OgreSubMesh.h>
#include <OgreMaterialManager.h>
#include <OgreMaterial.h>

#include "sleep.h"
#include "BackgroundMeshLoader.h"

BackgroundMeshLoader::BackgroundMeshLoader (void)
      : mNumBastards(0), mThread(NULL), mCurrent(NULL),
        mQuit(false), mAllowance(0)
{
        OGRE_LOCK_AUTO_MUTEX;

        mThread = new boost::thread(boost::ref(*this));
}

BackgroundMeshLoader::~BackgroundMeshLoader (void)
{
        shutdown();
}

void BackgroundMeshLoader::shutdown (void)
{
        // make sure a later destruction of this object doesn't touch ogre.
        if (mQuit) return;
        {
                OGRE_LOCK_AUTO_MUTEX;
                mQuit = true;
                OGRE_THREAD_NOTIFY_ONE(mCVar);
        }
        mThread->join();
        handleBastards();
        mDeathRow.clear();
        mDemands.clear();
        delete mThread;
}

void BackgroundMeshLoader::add (Demand *d)
{
        OGRE_LOCK_AUTO_MUTEX;
/*
        std::stringstream ss;
        ss << "adding demand: \""<<d->mMeshName<<"\" {";
        typedef std::set<Ogre::String>::const_iterator I;
        I begin = d->mMatNames.begin();
        I end = d->mMatNames.end();
        for (I i=begin ; i!=end ; ++i) {
                ss << (i==begin?"":", ")<<"\""<<*i<<"\"";
        }
        ss << "}";
        APP_VERBOSE(ss.str());
*/
        mDemands.insert(d);
        OGRE_THREAD_NOTIFY_ONE(mCVar);
}

void BackgroundMeshLoader::remove (Demand *d)
{
        OGRE_LOCK_AUTO_MUTEX;
        mDemands.erase(d);
        if (mCurrent == d)
                mCurrent = NULL;
}

void BackgroundMeshLoader::handleBastards (void)
{
        // access volatile field without taking lock first
        // worst case we return early, i.e. will pick up bastards next time
        if (mNumBastards==0) return;
        ResourcePtrSet s;
        {
                OGRE_LOCK_AUTO_MUTEX;
                if (mNumBastards==0) return;
                s = mBastards;
                mBastards.clear();
                mNumBastards = 0;
        }

        finishedWith(s);
}

void BackgroundMeshLoader::operator() (void)
{
        //APP_VERBOSE("BackgroundMeshLoader: thread started");
        ResourcePtrs pending;
        while (!mQuit) {
                {
                        OGRE_LOCK_AUTO_MUTEX;
                        if (mCurrent) {
                                // Usual case:
                                // demand wasn't retracted while we were
                                // processing it
                                mCurrent->mProcessed = true;
                                // cache in d to suppress compiler error
                                Demand *d = mCurrent;
                                mDemands.erase(d);
                                mCurrent = NULL;
                        } else {
                                // demand was retracted, and we actually
                                // loaded stuff
                                for (ResourcePtrs::const_iterator
                                        i=pending.begin(), i_=pending.end() ;
                                                                  i!=i_ ; ++i) {
                                        mBastards.insert(*i);
                                        mNumBastards = mBastards.size();
                                }
                               //asynchronously call sm.finishedWith(resource);
                        }
                        pending.clear();
                        if (mAllowance <= 0 || !nearestDemand(mCurrent)) {
                                OGRE_THREAD_WAIT(mCVar,OGRE_AUTO_MUTEX_NAME)
                                continue;
                        }
                        pending = mCurrent->rPtrs;
                }
                //APP_VERBOSE("BackgroundMeshLoader: loading: "+name);
                for (ResourcePtrs::iterator i=pending.begin(),
                                            i_=pending.end() ; i!=i_ ; ++i) {
                        Ogre::ResourcePtr &rp = *i;
                        if (!rp->isPrepared()) {
                                rp->prepare();
                                mAllowance--;
                        }
                }

                //mysleep(100000);
        }
        //APP_VERBOSE("BackgroundMeshLoader: thread terminated");
}

bool BackgroundMeshLoader::nearestDemand (Demand * volatile &return_demand)
{

        Ogre::Real closest_dist = 0;
        bool found = false;

        for (Demands::const_iterator i=mDemands.begin(),
                                     i_=mDemands.end()  ; i!=i_ ; ++i) {
                Demand *d = *i;

                Ogre::Real this_dist = (*i)->mDist;

                if (!found || this_dist<closest_dist) {
                        found = true;
                        closest_dist = this_dist;
                        return_demand = d;
                }

        }

        return found;

}

void BackgroundMeshLoader::setAllowance (Ogre::Real m)
{
        OGRE_LOCK_AUTO_MUTEX
        mAllowance = std::max(mAllowance+m, m);
        OGRE_THREAD_NOTIFY_ONE(mCVar);
}

// unloading of meshes /////////////////////////////////////////////////////////

template<typename T>
static inline bool is_unused (const Ogre::SharedPtr<T>& r)
{
        // if resource only used here, unload it
        return r.useCount() <=
             Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1;
}

void BackgroundMeshLoader::finishedWith (const ResourcePtrSet &s) {
        typedef ResourcePtrSet::const_iterator I;
        for (I i=s.begin(), i_=s.end() ; i!=i_ ; ++i) {
                finishedWith(*i);
        }
}

void BackgroundMeshLoader::finishedWith (const Ogre::ResourcePtr &rp)
{
        if (mQuit) return;
        if (rp.isNull()) return;
        if (!is_unused(rp)) return;
        mDeathRow.push(rp);
}

void BackgroundMeshLoader::finishedWith (const Ogre::MaterialPtr &mat)
{
        if (mQuit) return;
        if (mat.isNull()) return;
        if (!is_unused(mat)) return;
        mat->unload();
}

bool BackgroundMeshLoader::isGPUOversubscribed () const
{
        Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();
        Ogre::MeshManager &mm = Ogre::MeshManager::getSingleton();

        size_t budget = tm.getMemoryBudget() + mm.getMemoryBudget();

        size_t usage = tm.getMemoryUsage() + mm.getMemoryUsage();

        return usage >= budget;
}

void BackgroundMeshLoader::checkGPUUsage ()
{
        Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();
        Ogre::MeshManager &mm = Ogre::MeshManager::getSingleton();

        size_t budget = tm.getMemoryBudget() + mm.getMemoryBudget();

        while (true) {

                size_t usage = tm.getMemoryUsage() + mm.getMemoryUsage();

                if (usage < budget || mDeathRow.size() == 0) break;

                Ogre::ResourcePtr r = mDeathRow.pop();

                if (is_unused(r))
                        r->unload();
        }

}

template<>
BackgroundMeshLoader *Ogre::Singleton<BackgroundMeshLoader>::ms_Singleton =NULL;

// vim: shiftwidth=8:tabstop=8:expandtab
<commit_msg>Update for new OGRE svn head<commit_after>
#include <OgrePrerequisites.h> // for OGRE_THREAD_SUPPORT

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <OgreMeshManager.h>
#include <OgreMesh.h>
#include <OgreSubMesh.h>
#include <OgreMaterialManager.h>
#include <OgreMaterial.h>

#include "sleep.h"
#include "BackgroundMeshLoader.h"

BackgroundMeshLoader::BackgroundMeshLoader (void)
      : mNumBastards(0), mThread(NULL), mCurrent(NULL),
        mQuit(false), mAllowance(0)
{
        OGRE_LOCK_AUTO_MUTEX;

        mThread = new boost::thread(boost::ref(*this));
}

BackgroundMeshLoader::~BackgroundMeshLoader (void)
{
        shutdown();
}

void BackgroundMeshLoader::shutdown (void)
{
        // make sure a later destruction of this object doesn't touch ogre.
        if (mQuit) return;
        {
                OGRE_LOCK_AUTO_MUTEX;
                mQuit = true;
                OGRE_THREAD_NOTIFY_ONE(mCVar);
        }
        mThread->join();
        handleBastards();
        mDeathRow.clear();
        mDemands.clear();
        delete mThread;
}

void BackgroundMeshLoader::add (Demand *d)
{
        OGRE_LOCK_AUTO_MUTEX;
/*
        std::stringstream ss;
        ss << "adding demand: \""<<d->mMeshName<<"\" {";
        typedef std::set<Ogre::String>::const_iterator I;
        I begin = d->mMatNames.begin();
        I end = d->mMatNames.end();
        for (I i=begin ; i!=end ; ++i) {
                ss << (i==begin?"":", ")<<"\""<<*i<<"\"";
        }
        ss << "}";
        APP_VERBOSE(ss.str());
*/
        mDemands.insert(d);
        OGRE_THREAD_NOTIFY_ONE(mCVar);
}

void BackgroundMeshLoader::remove (Demand *d)
{
        OGRE_LOCK_AUTO_MUTEX;
        mDemands.erase(d);
        if (mCurrent == d)
                mCurrent = NULL;
}

void BackgroundMeshLoader::handleBastards (void)
{
        // access volatile field without taking lock first
        // worst case we return early, i.e. will pick up bastards next time
        if (mNumBastards==0) return;
        ResourcePtrSet s;
        {
                OGRE_LOCK_AUTO_MUTEX;
                if (mNumBastards==0) return;
                s = mBastards;
                mBastards.clear();
                mNumBastards = 0;
        }

        finishedWith(s);
}

void BackgroundMeshLoader::operator() (void)
{
        //APP_VERBOSE("BackgroundMeshLoader: thread started");
        ResourcePtrs pending;
        while (!mQuit) {
                {
                        OGRE_LOCK_AUTO_MUTEX;
                        if (mCurrent) {
                                // Usual case:
                                // demand wasn't retracted while we were
                                // processing it
                                mCurrent->mProcessed = true;
                                // cache in d to suppress compiler error
                                Demand *d = mCurrent;
                                mDemands.erase(d);
                                mCurrent = NULL;
                        } else {
                                // demand was retracted, and we actually
                                // loaded stuff
                                for (ResourcePtrs::const_iterator
                                        i=pending.begin(), i_=pending.end() ;
                                                                  i!=i_ ; ++i) {
                                        mBastards.insert(*i);
                                        mNumBastards = mBastards.size();
                                }
                               //asynchronously call sm.finishedWith(resource);
                        }
                        pending.clear();
                        if (mAllowance <= 0 || !nearestDemand(mCurrent)) {
                                OGRE_THREAD_WAIT(mCVar,OGRE_AUTO_MUTEX_NAME,ogreAutoMutexLock)
                                continue;
                        }
                        pending = mCurrent->rPtrs;
                }
                //APP_VERBOSE("BackgroundMeshLoader: loading: "+name);
                for (ResourcePtrs::iterator i=pending.begin(),
                                            i_=pending.end() ; i!=i_ ; ++i) {
                        Ogre::ResourcePtr &rp = *i;
                        if (!rp->isPrepared()) {
                                rp->prepare();
                                mAllowance--;
                        }
                }

                //mysleep(100000);
        }
        //APP_VERBOSE("BackgroundMeshLoader: thread terminated");
}

bool BackgroundMeshLoader::nearestDemand (Demand * volatile &return_demand)
{

        Ogre::Real closest_dist = 0;
        bool found = false;

        for (Demands::const_iterator i=mDemands.begin(),
                                     i_=mDemands.end()  ; i!=i_ ; ++i) {
                Demand *d = *i;

                Ogre::Real this_dist = (*i)->mDist;

                if (!found || this_dist<closest_dist) {
                        found = true;
                        closest_dist = this_dist;
                        return_demand = d;
                }

        }

        return found;

}

void BackgroundMeshLoader::setAllowance (Ogre::Real m)
{
        OGRE_LOCK_AUTO_MUTEX
        mAllowance = std::max(mAllowance+m, m);
        OGRE_THREAD_NOTIFY_ONE(mCVar);
}

// unloading of meshes /////////////////////////////////////////////////////////

template<typename T>
static inline bool is_unused (const Ogre::SharedPtr<T>& r)
{
        // if resource only used here, unload it
        return r.useCount() <=
             Ogre::ResourceGroupManager::RESOURCE_SYSTEM_NUM_REFERENCE_COUNTS+1;
}

void BackgroundMeshLoader::finishedWith (const ResourcePtrSet &s) {
        typedef ResourcePtrSet::const_iterator I;
        for (I i=s.begin(), i_=s.end() ; i!=i_ ; ++i) {
                finishedWith(*i);
        }
}

void BackgroundMeshLoader::finishedWith (const Ogre::ResourcePtr &rp)
{
        if (mQuit) return;
        if (rp.isNull()) return;
        if (!is_unused(rp)) return;
        mDeathRow.push(rp);
}

void BackgroundMeshLoader::finishedWith (const Ogre::MaterialPtr &mat)
{
        if (mQuit) return;
        if (mat.isNull()) return;
        if (!is_unused(mat)) return;
        mat->unload();
}

bool BackgroundMeshLoader::isGPUOversubscribed () const
{
        Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();
        Ogre::MeshManager &mm = Ogre::MeshManager::getSingleton();

        size_t budget = tm.getMemoryBudget() + mm.getMemoryBudget();

        size_t usage = tm.getMemoryUsage() + mm.getMemoryUsage();

        return usage >= budget;
}

void BackgroundMeshLoader::checkGPUUsage ()
{
        Ogre::TextureManager &tm = Ogre::TextureManager::getSingleton();
        Ogre::MeshManager &mm = Ogre::MeshManager::getSingleton();

        size_t budget = tm.getMemoryBudget() + mm.getMemoryBudget();

        while (true) {

                size_t usage = tm.getMemoryUsage() + mm.getMemoryUsage();

                if (usage < budget || mDeathRow.size() == 0) break;

                Ogre::ResourcePtr r = mDeathRow.pop();

                if (is_unused(r))
                        r->unload();
        }

}

template<>
BackgroundMeshLoader *Ogre::Singleton<BackgroundMeshLoader>::ms_Singleton =NULL;

// vim: shiftwidth=8:tabstop=8:expandtab
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/kernels/conv_weights_converter.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetConverterToConvWeightsCode(
    const OperationDef& op_def,
    const ConvWeightsDescription& conv_weights_desc) {
  TensorCodeGenerator src_tensor(
      "src_data",
      WHSBPoint{"src_size.x", "src_size.y", "src_size.z", "src_size.w"},
      op_def.src_tensors[0]);
  TensorCodeGenerator dst_tensor(
      "dst_data",
      WHSBPoint{"dst_size.x", "dst_size.y", "dst_size.z", "dst_size.w"},
      op_def.dst_tensors[0]);

  std::string c = GetCommonDefines(op_def.precision);
  c += "__kernel void main_function(\n";
  c += src_tensor.GetDeclaration(AccessType::READ) + ",\n";
  c += dst_tensor.GetDeclaration(AccessType::WRITE) + ",\n";
  c += "    int4 src_size,              \n";
  c += "    float4 mask\n";
  c += ") {\n";
  c += "  int GROUP_SIZE = " +
       std::to_string(conv_weights_desc.output_group_size) + ";\n";
  c += "  int O = get_global_id(0) * 4;\n";
  c += "  int I = get_global_id(1);\n";
  c += "  int Z = get_global_id(2);\n";
  c += "  int W = Z % src_size.x;\n";
  c += "  int H = Z / src_size.x;\n";
  c += "  if (O >= src_size.w || I >= src_size.z || H >= src_size.y) return;\n";
  c += "  FLT4 v0 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 0") + ";\n";
  c += "  FLT4 v1 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v2 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v3 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  if (O + 1 < src_size.w) {\n";
  c += "    v1 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 1") + ";\n";
  c += "  }\n";
  c += "  if (O + 2 < src_size.w) {\n";
  c += "    v2 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 2") + ";\n";
  c += "  }\n";
  c += "  if (O + 3 < src_size.w) {\n";
  c += "    v3 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 3") + ";\n";
  c += "  }\n";
  c += "  if (I == src_size.z - 1) {\n";
  c += "    FLT4 mask_t = TO_FLT4(mask);\n";
  c += "    v0 *= mask_t;\n";
  c += "    v1 *= mask_t;\n";
  c += "    v2 *= mask_t;\n";
  c += "    v3 *= mask_t;\n";
  c += "  }\n";
  c += "  FLT4 r0 = (FLT4)(v0.x, v1.x, v2.x, v3.x);\n";
  c += "  FLT4 r1 = (FLT4)(v0.y, v1.y, v2.y, v3.y);\n";
  c += "  FLT4 r2 = (FLT4)(v0.z, v1.z, v2.z, v3.z);\n";
  c += "  FLT4 r3 = (FLT4)(v0.w, v1.w, v2.w, v3.w);\n";
  c += "  int d_index = O / (GROUP_SIZE * 4);\n";
  c += "  int k_index = (O % (GROUP_SIZE * 4)) / 4;\n";
  c += "  int dst_offset = (((d_index * src_size.y + H) * src_size.x + W) * "
       "src_size.z + I) * GROUP_SIZE + "
       "k_index;\n";
  c += "  int address0 = dst_offset * 4 + 0;\n";
  c += "  int address1 = dst_offset * 4 + 1;\n";
  c += "  int address2 = dst_offset * 4 + 2;\n";
  c += "  int address3 = dst_offset * 4 + 3;\n";
  c += "  " + dst_tensor.Write("r0", "address0");
  c += "  " + dst_tensor.Write("r1", "address1");
  c += "  " + dst_tensor.Write("r2", "address2");
  c += "  " + dst_tensor.Write("r3", "address3");
  c += "}\n";
  return c;
}
}  // namespace

ConverterToConvWeights::ConverterToConvWeights(
    ConverterToConvWeights&& operation)
    : GPUOperation(std::move(operation)),
      conv_weights_desc_(operation.conv_weights_desc_),
      kernel_(std::move(operation.kernel_)),
      work_group_size_(operation.work_group_size_) {}

ConverterToConvWeights& ConverterToConvWeights::operator=(
    ConverterToConvWeights&& operation) {
  if (this != &operation) {
    conv_weights_desc_ = operation.conv_weights_desc_;
    kernel_ = std::move(operation.kernel_);
    std::swap(work_group_size_, operation.work_group_size_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

absl::Status ConverterToConvWeights::Compile(
    const CreationContext& creation_context) {
  std::string code =
      GetConverterToConvWeightsCode(definition_, conv_weights_desc_);
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status ConverterToConvWeights::BindArguments() {
  kernel_.ResetBindingCounter();
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(src_[0]->GetMemoryPtr()));
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(dst_[0]->GetMemoryPtrForWriting()));
  RETURN_IF_ERROR(kernel_.SetBytesAuto(src_[0]->GetWHSB()));
  RETURN_IF_ERROR(
      kernel_.SetBytesAuto(GetMaskForLastPlane(src_[0]->Channels())));
  return absl::OkStatus();
}

int3 ConverterToConvWeights::GetGridSize() const {
  const int grid_x = DivideRoundUp(src_[0]->Batch(), 4);
  const int grid_y = src_[0]->Slices();
  const int grid_z = src_[0]->Width() * src_[0]->Height();
  return int3(grid_x, grid_y, grid_z);
}

absl::Status ConverterToConvWeights::Tune(const TuningParameters& params) {
  RETURN_IF_ERROR(BindArguments());
  return GetBestWorkGroup(params, kernel_, GetGridSize(), &work_group_size_);
}

absl::Status ConverterToConvWeights::AddToQueue(CLCommandQueue* queue) {
  RETURN_IF_ERROR(BindArguments());
  return queue->DispatchImplicit(kernel_, GetGridSize(), work_group_size_);
}

ConverterToConvWeights CreateConverterToConvWeights(
    const OperationDef& definition,
    const ConvWeightsDescription& conv_weights_desc) {
  return ConverterToConvWeights(definition, conv_weights_desc);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<commit_msg>Internal change<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/delegates/gpu/cl/kernels/conv_weights_converter.h"

#include <string>

#include "tensorflow/lite/delegates/gpu/cl/kernels/util.h"
#include "tensorflow/lite/delegates/gpu/cl/kernels/work_group_picking.h"

namespace tflite {
namespace gpu {
namespace cl {
namespace {

std::string GetConverterToConvWeightsCode(
    const OperationDef& op_def,
    const ConvWeightsDescription& conv_weights_desc) {
  TensorCodeGenerator src_tensor(
      "src_data",
      WHSBPoint{"src_size.x", "src_size.y", "src_size.z", "src_size.w"},
      op_def.src_tensors[0]);
  TensorCodeGenerator dst_tensor(
      "dst_data",
      WHSBPoint{"dst_size.x", "dst_size.y", "dst_size.z", "dst_size.w"},
      op_def.dst_tensors[0]);

  std::string c = GetCommonDefines(op_def.precision);
  c += "__kernel void main_function(\n";
  c += src_tensor.GetDeclaration(AccessType::READ) + ",\n";
  c += dst_tensor.GetDeclaration(AccessType::WRITE) + ",\n";
  c += "    int4 src_size,              \n";
  c += "    float4 mask\n";
  c += ") {\n";
  c += "  int GROUP_SIZE = " +
       std::to_string(conv_weights_desc.output_group_size) + ";\n";
  c += "  int O = get_global_id(0) * 4;\n";
  c += "  int I = get_global_id(1);\n";
  c += "  int Z = get_global_id(2);\n";
  c += "  int W = Z % src_size.x;\n";
  c += "  int H = Z / src_size.x;\n";
  c += "  if (O >= src_size.w || I >= src_size.z || H >= src_size.y) return;\n";
  c += "  FLT4 v0 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 0") + ";\n";
  c += "  FLT4 v1 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v2 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  FLT4 v3 = (FLT4)(0.0f, 0.0f, 0.0f, 0.0f);\n";
  c += "  if (O + 1 < src_size.w) {\n";
  c += "    v1 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 1") + ";\n";
  c += "  }\n";
  c += "  if (O + 2 < src_size.w) {\n";
  c += "    v2 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 2") + ";\n";
  c += "  }\n";
  c += "  if (O + 3 < src_size.w) {\n";
  c += "    v3 =" + src_tensor.ReadWHSB("W", "H", "I", "O + 3") + ";\n";
  c += "  }\n";
  c += "  if (I == src_size.z - 1) {\n";
  c += "    FLT4 mask_t = TO_FLT4(mask);\n";
  c += "    v0 *= mask_t;\n";
  c += "    v1 *= mask_t;\n";
  c += "    v2 *= mask_t;\n";
  c += "    v3 *= mask_t;\n";
  c += "  }\n";
  c += "  FLT4 r0 = (FLT4)(v0.x, v1.x, v2.x, v3.x);\n";
  c += "  FLT4 r1 = (FLT4)(v0.y, v1.y, v2.y, v3.y);\n";
  c += "  FLT4 r2 = (FLT4)(v0.z, v1.z, v2.z, v3.z);\n";
  c += "  FLT4 r3 = (FLT4)(v0.w, v1.w, v2.w, v3.w);\n";
  c += "  int d_index = O / (GROUP_SIZE * 4);\n";
  c += "  int k_index = (O % (GROUP_SIZE * 4)) / 4;\n";
  c += "  int dst_offset = (((d_index * src_size.y + H) * src_size.x + W) * "
       "src_size.z + I) * GROUP_SIZE + "
       "k_index;\n";
  c += "  int address0 = dst_offset * 4 + 0;\n";
  c += "  int address1 = dst_offset * 4 + 1;\n";
  c += "  int address2 = dst_offset * 4 + 2;\n";
  c += "  int address3 = dst_offset * 4 + 3;\n";
  c += "  " + dst_tensor.Write("r0", "address0");
  c += "  " + dst_tensor.Write("r1", "address1");
  c += "  " + dst_tensor.Write("r2", "address2");
  c += "  " + dst_tensor.Write("r3", "address3");
  c += "}\n";
  return c;
}
}  // namespace

ConverterToConvWeights::ConverterToConvWeights(
    ConverterToConvWeights&& operation)
    : GPUOperation(std::move(operation)),
      conv_weights_desc_(operation.conv_weights_desc_),
      kernel_(std::move(operation.kernel_)),
      work_group_size_(operation.work_group_size_) {}

ConverterToConvWeights& ConverterToConvWeights::operator=(
    ConverterToConvWeights&& operation) {
  if (this != &operation) {
    conv_weights_desc_ = operation.conv_weights_desc_;
    kernel_ = std::move(operation.kernel_);
    std::swap(work_group_size_, operation.work_group_size_);
    GPUOperation::operator=(std::move(operation));
  }
  return *this;
}

absl::Status ConverterToConvWeights::Compile(
    const CreationContext& creation_context) {
  std::string code =
      GetConverterToConvWeightsCode(definition_, conv_weights_desc_);
  return creation_context.cache->GetOrCreateCLKernel(
      code, "main_function", *creation_context.context,
      *creation_context.device, &kernel_);
}

absl::Status ConverterToConvWeights::BindArguments() {
  kernel_.ResetBindingCounter();
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(src_[0]->GetMemoryPtr()));
  RETURN_IF_ERROR(kernel_.SetMemoryAuto(dst_[0]->GetMemoryPtrForWriting()));
  RETURN_IF_ERROR(kernel_.SetBytesAuto(src_[0]->GetWHSB()));
  RETURN_IF_ERROR(
      kernel_.SetBytesAuto(GetMaskForLastPlane(src_[0]->Channels())));
  return absl::OkStatus();
}

int3 ConverterToConvWeights::GetGridSize() const {
  const int grid_x = DivideRoundUp(
      AlignByN(src_[0]->Batch(), 4 * conv_weights_desc_.output_group_size), 4);
  const int grid_y = src_[0]->Slices();
  const int grid_z = src_[0]->Width() * src_[0]->Height();
  return int3(grid_x, grid_y, grid_z);
}

absl::Status ConverterToConvWeights::Tune(const TuningParameters& params) {
  RETURN_IF_ERROR(BindArguments());
  return GetBestWorkGroup(params, kernel_, GetGridSize(), &work_group_size_);
}

absl::Status ConverterToConvWeights::AddToQueue(CLCommandQueue* queue) {
  RETURN_IF_ERROR(BindArguments());
  return queue->DispatchImplicit(kernel_, GetGridSize(), work_group_size_);
}

ConverterToConvWeights CreateConverterToConvWeights(
    const OperationDef& definition,
    const ConvWeightsDescription& conv_weights_desc) {
  return ConverterToConvWeights(definition, conv_weights_desc);
}

}  // namespace cl
}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>//===- Pass.cpp - LLVM Pass Infrastructure Implementation -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LLVM Pass infrastructure.  It is primarily
// responsible with ensuring that passes are executed and batched together
// optimally.
//
//===----------------------------------------------------------------------===//

#include "llvm/PassManager.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TypeInfo.h"
#include <algorithm>
#include <set>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Pass Implementation
//

// Force out-of-line virtual method.
Pass::~Pass() {
  delete Resolver;
}

// Force out-of-line virtual method.
ModulePass::~ModulePass() { }

bool Pass::mustPreserveAnalysisID(const PassInfo *AnalysisID) const {
  return Resolver->getAnalysisToUpdate(AnalysisID, true) != 0;
}

// dumpPassStructure - Implement the -debug-passes=Structure option
void Pass::dumpPassStructure(unsigned Offset) {
  cerr << std::string(Offset*2, ' ') << getPassName() << "\n";
}

// getPassName - Use C++ RTTI to get a SOMEWHAT intelligible name for the pass.
//
const char *Pass::getPassName() const {
  if (const PassInfo *PI = getPassInfo())
    return PI->getPassName();
  return typeid(*this).name();
}

// print - Print out the internal state of the pass.  This is called by Analyze
// to print out the contents of an analysis.  Otherwise it is not necessary to
// implement this method.
//
void Pass::print(std::ostream &O,const Module*) const {
  O << "Pass::print not implemented for pass: '" << getPassName() << "'!\n";
}

// dump - call print(cerr);
void Pass::dump() const {
  print(*cerr.stream(), 0);
}

//===----------------------------------------------------------------------===//
// ImmutablePass Implementation
//
// Force out-of-line virtual method.
ImmutablePass::~ImmutablePass() { }

//===----------------------------------------------------------------------===//
// FunctionPass Implementation
//

// run - On a module, we run this pass by initializing, runOnFunction'ing once
// for every function in the module, then by finalizing.
//
bool FunctionPass::runOnModule(Module &M) {
  bool Changed = doInitialization(M);

  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (!I->isDeclaration())      // Passes are not run on external functions!
    Changed |= runOnFunction(*I);

  return Changed | doFinalization(M);
}

// run - On a function, we simply initialize, run the function, then finalize.
//
bool FunctionPass::run(Function &F) {
  if (F.isDeclaration()) return false;// Passes are not run on external functions!

  bool Changed = doInitialization(*F.getParent());
  Changed |= runOnFunction(F);
  return Changed | doFinalization(*F.getParent());
}

//===----------------------------------------------------------------------===//
// BasicBlockPass Implementation
//

// To run this pass on a function, we simply call runOnBasicBlock once for each
// function.
//
bool BasicBlockPass::runOnFunction(Function &F) {
  bool Changed = doInitialization(F);
  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
    Changed |= runOnBasicBlock(*I);
  return Changed | doFinalization(F);
}

// To run directly on the basic block, we initialize, runOnBasicBlock, then
// finalize.
//
bool BasicBlockPass::runPass(BasicBlock &BB) {
  Function &F = *BB.getParent();
  Module &M = *F.getParent();
  bool Changed = doInitialization(M);
  Changed |= doInitialization(F);
  Changed |= runOnBasicBlock(BB);
  Changed |= doFinalization(F);
  Changed |= doFinalization(M);
  return Changed;
}

//===----------------------------------------------------------------------===//
// Pass Registration mechanism
//
namespace {
class PassRegistrar {
  /// PassInfoMap - Keep track of the passinfo object for each registered llvm
  /// pass.
  std::map<intptr_t, PassInfo*> PassInfoMap;

  /// AnalysisGroupInfo - Keep track of information for each analysis group.
  struct AnalysisGroupInfo {
    const PassInfo *DefaultImpl;
    std::set<const PassInfo *> Implementations;
    AnalysisGroupInfo() : DefaultImpl(0) {}
  };

  /// AnalysisGroupInfoMap - Information for each analysis group.
  std::map<const PassInfo *, AnalysisGroupInfo> AnalysisGroupInfoMap;

public:

  const PassInfo *GetPassInfo(intptr_t TI) const {
    std::map<intptr_t, PassInfo*>::const_iterator I = PassInfoMap.find(TI);
    return I != PassInfoMap.end() ? I->second : 0;
  }

  void RegisterPass(PassInfo &PI) {
    bool Inserted =
      PassInfoMap.insert(std::make_pair(PI.getTypeInfo(),&PI)).second;
    assert(Inserted && "Pass registered multiple times!");
  }

  void UnregisterPass(PassInfo &PI) {
    std::map<intptr_t, PassInfo*>::iterator I =
      PassInfoMap.find(PI.getTypeInfo());
    assert(I != PassInfoMap.end() && "Pass registered but not in map!");

    // Remove pass from the map.
    PassInfoMap.erase(I);
  }

  void EnumerateWith(PassRegistrationListener *L) {
    for (std::map<intptr_t, PassInfo*>::const_iterator I = PassInfoMap.begin(),
         E = PassInfoMap.end(); I != E; ++I)
      L->passEnumerate(I->second);
  }

  /// Analysis Group Mechanisms.
  void RegisterAnalysisGroup(PassInfo *InterfaceInfo,
                             const PassInfo *ImplementationInfo,
                             bool isDefault) {
    AnalysisGroupInfo &AGI = AnalysisGroupInfoMap[InterfaceInfo];
    assert(AGI.Implementations.count(ImplementationInfo) == 0 &&
           "Cannot add a pass to the same analysis group more than once!");
    AGI.Implementations.insert(ImplementationInfo);
    if (isDefault) {
      assert(AGI.DefaultImpl == 0 && InterfaceInfo->getNormalCtor() == 0 &&
             "Default implementation for analysis group already specified!");
      assert(ImplementationInfo->getNormalCtor() &&
           "Cannot specify pass as default if it does not have a default ctor");
      AGI.DefaultImpl = ImplementationInfo;
      InterfaceInfo->setNormalCtor(ImplementationInfo->getNormalCtor());
    }
  }
};
}

static std::vector<PassRegistrationListener*> *Listeners = 0;

// FIXME: This should use ManagedStatic to manage the pass registrar.
// Unfortunately, we can't do this, because passes are registered with static
// ctors, and having llvm_shutdown clear this map prevents successful
// ressurection after llvm_shutdown is run.
static PassRegistrar *getPassRegistrar() {
  static PassRegistrar *PassRegistrarObj = 0;
  if (!PassRegistrarObj)
    PassRegistrarObj = new PassRegistrar();
  return PassRegistrarObj;
}

// getPassInfo - Return the PassInfo data structure that corresponds to this
// pass...
const PassInfo *Pass::getPassInfo() const {
  return lookupPassInfo(PassID);
}

const PassInfo *Pass::lookupPassInfo(intptr_t TI) {
  return getPassRegistrar()->GetPassInfo(TI);
}

void RegisterPassBase::registerPass() {
  getPassRegistrar()->RegisterPass(PIObj);

  // Notify any listeners.
  if (Listeners)
    for (std::vector<PassRegistrationListener*>::iterator
           I = Listeners->begin(), E = Listeners->end(); I != E; ++I)
      (*I)->passRegistered(&PIObj);
}

void RegisterPassBase::unregisterPass() {
  getPassRegistrar()->UnregisterPass(PIObj);
}

//===----------------------------------------------------------------------===//
//                  Analysis Group Implementation Code
//===----------------------------------------------------------------------===//

// RegisterAGBase implementation
//
RegisterAGBase::RegisterAGBase(intptr_t InterfaceID,
                               intptr_t PassID, bool isDefault)
  : RegisterPassBase(InterfaceID),
    ImplementationInfo(0), isDefaultImplementation(isDefault) {

  InterfaceInfo = const_cast<PassInfo*>(Pass::lookupPassInfo(InterfaceID));
  if (InterfaceInfo == 0) {
    // First reference to Interface, register it now.
    registerPass();
    InterfaceInfo = &PIObj;
  }
  assert(PIObj.isAnalysisGroup() &&
         "Trying to join an analysis group that is a normal pass!");

  if (PassID) {
    ImplementationInfo = Pass::lookupPassInfo(PassID);
    assert(ImplementationInfo &&
           "Must register pass before adding to AnalysisGroup!");

    // Make sure we keep track of the fact that the implementation implements
    // the interface.
    PassInfo *IIPI = const_cast<PassInfo*>(ImplementationInfo);
    IIPI->addInterfaceImplemented(InterfaceInfo);

    getPassRegistrar()->RegisterAnalysisGroup(InterfaceInfo, IIPI, isDefault);
  }
}

void RegisterAGBase::setGroupName(const char *Name) {
  assert(InterfaceInfo->getPassName()[0] == 0 && "Interface Name already set!");
  InterfaceInfo->setPassName(Name);
}

//===----------------------------------------------------------------------===//
// PassRegistrationListener implementation
//

// PassRegistrationListener ctor - Add the current object to the list of
// PassRegistrationListeners...
PassRegistrationListener::PassRegistrationListener() {
  if (!Listeners) Listeners = new std::vector<PassRegistrationListener*>();
  Listeners->push_back(this);
}

// dtor - Remove object from list of listeners...
PassRegistrationListener::~PassRegistrationListener() {
  std::vector<PassRegistrationListener*>::iterator I =
    std::find(Listeners->begin(), Listeners->end(), this);
  assert(Listeners && I != Listeners->end() &&
         "PassRegistrationListener not registered!");
  Listeners->erase(I);

  if (Listeners->empty()) {
    delete Listeners;
    Listeners = 0;
  }
}

// enumeratePasses - Iterate over the registered passes, calling the
// passEnumerate callback on each PassInfo object.
//
void PassRegistrationListener::enumeratePasses() {
  getPassRegistrar()->EnumerateWith(this);
}

//===----------------------------------------------------------------------===//
//   AnalysisUsage Class Implementation
//

namespace {
  struct GetCFGOnlyPasses : public PassRegistrationListener {
    std::vector<AnalysisID> &CFGOnlyList;
    GetCFGOnlyPasses(std::vector<AnalysisID> &L) : CFGOnlyList(L) {}

    void passEnumerate(const PassInfo *P) {
      if (P->isCFGOnlyPass())
        CFGOnlyList.push_back(P);
    }
  };
}

// setPreservesCFG - This function should be called to by the pass, iff they do
// not:
//
//  1. Add or remove basic blocks from the function
//  2. Modify terminator instructions in any way.
//
// This function annotates the AnalysisUsage info object to say that analyses
// that only depend on the CFG are preserved by this pass.
//
void AnalysisUsage::setPreservesCFG() {
  // Since this transformation doesn't modify the CFG, it preserves all analyses
  // that only depend on the CFG (like dominators, loop info, etc...)
  GetCFGOnlyPasses(Preserved).enumeratePasses();
}

<commit_msg>disable this assertion as a hack to get the build more unbroken :(<commit_after>//===- Pass.cpp - LLVM Pass Infrastructure Implementation -----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the LLVM Pass infrastructure.  It is primarily
// responsible with ensuring that passes are executed and batched together
// optimally.
//
//===----------------------------------------------------------------------===//

#include "llvm/PassManager.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TypeInfo.h"
#include <algorithm>
#include <set>
using namespace llvm;

//===----------------------------------------------------------------------===//
// Pass Implementation
//

// Force out-of-line virtual method.
Pass::~Pass() {
  delete Resolver;
}

// Force out-of-line virtual method.
ModulePass::~ModulePass() { }

bool Pass::mustPreserveAnalysisID(const PassInfo *AnalysisID) const {
  return Resolver->getAnalysisToUpdate(AnalysisID, true) != 0;
}

// dumpPassStructure - Implement the -debug-passes=Structure option
void Pass::dumpPassStructure(unsigned Offset) {
  cerr << std::string(Offset*2, ' ') << getPassName() << "\n";
}

// getPassName - Use C++ RTTI to get a SOMEWHAT intelligible name for the pass.
//
const char *Pass::getPassName() const {
  if (const PassInfo *PI = getPassInfo())
    return PI->getPassName();
  return typeid(*this).name();
}

// print - Print out the internal state of the pass.  This is called by Analyze
// to print out the contents of an analysis.  Otherwise it is not necessary to
// implement this method.
//
void Pass::print(std::ostream &O,const Module*) const {
  O << "Pass::print not implemented for pass: '" << getPassName() << "'!\n";
}

// dump - call print(cerr);
void Pass::dump() const {
  print(*cerr.stream(), 0);
}

//===----------------------------------------------------------------------===//
// ImmutablePass Implementation
//
// Force out-of-line virtual method.
ImmutablePass::~ImmutablePass() { }

//===----------------------------------------------------------------------===//
// FunctionPass Implementation
//

// run - On a module, we run this pass by initializing, runOnFunction'ing once
// for every function in the module, then by finalizing.
//
bool FunctionPass::runOnModule(Module &M) {
  bool Changed = doInitialization(M);

  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (!I->isDeclaration())      // Passes are not run on external functions!
    Changed |= runOnFunction(*I);

  return Changed | doFinalization(M);
}

// run - On a function, we simply initialize, run the function, then finalize.
//
bool FunctionPass::run(Function &F) {
  if (F.isDeclaration()) return false;// Passes are not run on external functions!

  bool Changed = doInitialization(*F.getParent());
  Changed |= runOnFunction(F);
  return Changed | doFinalization(*F.getParent());
}

//===----------------------------------------------------------------------===//
// BasicBlockPass Implementation
//

// To run this pass on a function, we simply call runOnBasicBlock once for each
// function.
//
bool BasicBlockPass::runOnFunction(Function &F) {
  bool Changed = doInitialization(F);
  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
    Changed |= runOnBasicBlock(*I);
  return Changed | doFinalization(F);
}

// To run directly on the basic block, we initialize, runOnBasicBlock, then
// finalize.
//
bool BasicBlockPass::runPass(BasicBlock &BB) {
  Function &F = *BB.getParent();
  Module &M = *F.getParent();
  bool Changed = doInitialization(M);
  Changed |= doInitialization(F);
  Changed |= runOnBasicBlock(BB);
  Changed |= doFinalization(F);
  Changed |= doFinalization(M);
  return Changed;
}

//===----------------------------------------------------------------------===//
// Pass Registration mechanism
//
namespace {
class PassRegistrar {
  /// PassInfoMap - Keep track of the passinfo object for each registered llvm
  /// pass.
  std::map<intptr_t, PassInfo*> PassInfoMap;

  /// AnalysisGroupInfo - Keep track of information for each analysis group.
  struct AnalysisGroupInfo {
    const PassInfo *DefaultImpl;
    std::set<const PassInfo *> Implementations;
    AnalysisGroupInfo() : DefaultImpl(0) {}
  };

  /// AnalysisGroupInfoMap - Information for each analysis group.
  std::map<const PassInfo *, AnalysisGroupInfo> AnalysisGroupInfoMap;

public:

  const PassInfo *GetPassInfo(intptr_t TI) const {
    std::map<intptr_t, PassInfo*>::const_iterator I = PassInfoMap.find(TI);
    return I != PassInfoMap.end() ? I->second : 0;
  }

  void RegisterPass(PassInfo &PI) {
    bool Inserted =
      PassInfoMap.insert(std::make_pair(PI.getTypeInfo(),&PI)).second;
    //assert(Inserted && "Pass registered multiple times!");
  }

  void UnregisterPass(PassInfo &PI) {
    std::map<intptr_t, PassInfo*>::iterator I =
      PassInfoMap.find(PI.getTypeInfo());
    assert(I != PassInfoMap.end() && "Pass registered but not in map!");

    // Remove pass from the map.
    PassInfoMap.erase(I);
  }

  void EnumerateWith(PassRegistrationListener *L) {
    for (std::map<intptr_t, PassInfo*>::const_iterator I = PassInfoMap.begin(),
         E = PassInfoMap.end(); I != E; ++I)
      L->passEnumerate(I->second);
  }

  /// Analysis Group Mechanisms.
  void RegisterAnalysisGroup(PassInfo *InterfaceInfo,
                             const PassInfo *ImplementationInfo,
                             bool isDefault) {
    AnalysisGroupInfo &AGI = AnalysisGroupInfoMap[InterfaceInfo];
    assert(AGI.Implementations.count(ImplementationInfo) == 0 &&
           "Cannot add a pass to the same analysis group more than once!");
    AGI.Implementations.insert(ImplementationInfo);
    if (isDefault) {
      assert(AGI.DefaultImpl == 0 && InterfaceInfo->getNormalCtor() == 0 &&
             "Default implementation for analysis group already specified!");
      assert(ImplementationInfo->getNormalCtor() &&
           "Cannot specify pass as default if it does not have a default ctor");
      AGI.DefaultImpl = ImplementationInfo;
      InterfaceInfo->setNormalCtor(ImplementationInfo->getNormalCtor());
    }
  }
};
}

static std::vector<PassRegistrationListener*> *Listeners = 0;

// FIXME: This should use ManagedStatic to manage the pass registrar.
// Unfortunately, we can't do this, because passes are registered with static
// ctors, and having llvm_shutdown clear this map prevents successful
// ressurection after llvm_shutdown is run.
static PassRegistrar *getPassRegistrar() {
  static PassRegistrar *PassRegistrarObj = 0;
  if (!PassRegistrarObj)
    PassRegistrarObj = new PassRegistrar();
  return PassRegistrarObj;
}

// getPassInfo - Return the PassInfo data structure that corresponds to this
// pass...
const PassInfo *Pass::getPassInfo() const {
  return lookupPassInfo(PassID);
}

const PassInfo *Pass::lookupPassInfo(intptr_t TI) {
  return getPassRegistrar()->GetPassInfo(TI);
}

void RegisterPassBase::registerPass() {
  getPassRegistrar()->RegisterPass(PIObj);

  // Notify any listeners.
  if (Listeners)
    for (std::vector<PassRegistrationListener*>::iterator
           I = Listeners->begin(), E = Listeners->end(); I != E; ++I)
      (*I)->passRegistered(&PIObj);
}

void RegisterPassBase::unregisterPass() {
  getPassRegistrar()->UnregisterPass(PIObj);
}

//===----------------------------------------------------------------------===//
//                  Analysis Group Implementation Code
//===----------------------------------------------------------------------===//

// RegisterAGBase implementation
//
RegisterAGBase::RegisterAGBase(intptr_t InterfaceID,
                               intptr_t PassID, bool isDefault)
  : RegisterPassBase(InterfaceID),
    ImplementationInfo(0), isDefaultImplementation(isDefault) {

  InterfaceInfo = const_cast<PassInfo*>(Pass::lookupPassInfo(InterfaceID));
  if (InterfaceInfo == 0) {
    // First reference to Interface, register it now.
    registerPass();
    InterfaceInfo = &PIObj;
  }
  assert(PIObj.isAnalysisGroup() &&
         "Trying to join an analysis group that is a normal pass!");

  if (PassID) {
    ImplementationInfo = Pass::lookupPassInfo(PassID);
    assert(ImplementationInfo &&
           "Must register pass before adding to AnalysisGroup!");

    // Make sure we keep track of the fact that the implementation implements
    // the interface.
    PassInfo *IIPI = const_cast<PassInfo*>(ImplementationInfo);
    IIPI->addInterfaceImplemented(InterfaceInfo);

    getPassRegistrar()->RegisterAnalysisGroup(InterfaceInfo, IIPI, isDefault);
  }
}

void RegisterAGBase::setGroupName(const char *Name) {
  assert(InterfaceInfo->getPassName()[0] == 0 && "Interface Name already set!");
  InterfaceInfo->setPassName(Name);
}

//===----------------------------------------------------------------------===//
// PassRegistrationListener implementation
//

// PassRegistrationListener ctor - Add the current object to the list of
// PassRegistrationListeners...
PassRegistrationListener::PassRegistrationListener() {
  if (!Listeners) Listeners = new std::vector<PassRegistrationListener*>();
  Listeners->push_back(this);
}

// dtor - Remove object from list of listeners...
PassRegistrationListener::~PassRegistrationListener() {
  std::vector<PassRegistrationListener*>::iterator I =
    std::find(Listeners->begin(), Listeners->end(), this);
  assert(Listeners && I != Listeners->end() &&
         "PassRegistrationListener not registered!");
  Listeners->erase(I);

  if (Listeners->empty()) {
    delete Listeners;
    Listeners = 0;
  }
}

// enumeratePasses - Iterate over the registered passes, calling the
// passEnumerate callback on each PassInfo object.
//
void PassRegistrationListener::enumeratePasses() {
  getPassRegistrar()->EnumerateWith(this);
}

//===----------------------------------------------------------------------===//
//   AnalysisUsage Class Implementation
//

namespace {
  struct GetCFGOnlyPasses : public PassRegistrationListener {
    std::vector<AnalysisID> &CFGOnlyList;
    GetCFGOnlyPasses(std::vector<AnalysisID> &L) : CFGOnlyList(L) {}

    void passEnumerate(const PassInfo *P) {
      if (P->isCFGOnlyPass())
        CFGOnlyList.push_back(P);
    }
  };
}

// setPreservesCFG - This function should be called to by the pass, iff they do
// not:
//
//  1. Add or remove basic blocks from the function
//  2. Modify terminator instructions in any way.
//
// This function annotates the AnalysisUsage info object to say that analyses
// that only depend on the CFG are preserved by this pass.
//
void AnalysisUsage::setPreservesCFG() {
  // Since this transformation doesn't modify the CFG, it preserves all analyses
  // that only depend on the CFG (like dominators, loop info, etc...)
  GetCFGOnlyPasses(Preserved).enumeratePasses();
}

<|endoftext|>


<commit_before>/*
 * TableSelectionTx.cpp
 *
 * Copyright (C) 2020 by VISUS (University of Stuttgart)
 * Alle Rechte vorbehalten.
 */

#include "stdafx.h"
#include "TableSelectionTx.h"

#include "mmcore/param/BoolParam.h"
#include "vislib/sys/Log.h"

using namespace megamol::stdplugin::datatools;
using namespace megamol::stdplugin::datatools::table;
using namespace megamol;

TableSelectionTx::TableSelectionTx()
    : core::Module()
    , tableInSlot("getTableIn", "Float table input")
    , flagStorageReadInSlot("readFlagStorageIn", "Flag storage read input")
    , flagStorageWriteInSlot("writeFlagStorageIn", "Flag storage write input")
    , flagStorageReadOutSlot("readFlagStorageOut", "Flag storage read output")
    , flagStorageWriteOutSlot("writeFlagStorageOut", "Flag storage write output")
    , updateSelectionParam("updateSelectionParam", "Enable selection update")
    , senderThreadQuit_(false)
    , senderThreadNotified_(false)
    , receiverThreadQuit_(false)
    , receivedSelectionUpdate_(false)
{
    this->tableInSlot.SetCompatibleCall<TableDataCallDescription>();
    this->MakeSlotAvailable(&this->tableInSlot);

    this->flagStorageReadInSlot.SetCompatibleCall<core::FlagCallRead_GLDescription>();
    this->MakeSlotAvailable(&this->flagStorageReadInSlot);

    this->flagStorageWriteInSlot.SetCompatibleCall<core::FlagCallWrite_GLDescription>();
    this->MakeSlotAvailable(&this->flagStorageWriteInSlot);

    this->flagStorageReadOutSlot.SetCallback(core::FlagCallRead_GL::ClassName(), core::FlagCallRead_GL::FunctionName(core::FlagCallRead_GL::CallGetData), &TableSelectionTx::readDataCallback);
    this->flagStorageReadOutSlot.SetCallback(core::FlagCallRead_GL::ClassName(), core::FlagCallRead_GL::FunctionName(core::FlagCallRead_GL::CallGetMetaData), &TableSelectionTx::readMetaDataCallback);
    this->MakeSlotAvailable(&this->flagStorageReadOutSlot);

    this->flagStorageWriteOutSlot.SetCallback(core::FlagCallWrite_GL::ClassName(), core::FlagCallWrite_GL::FunctionName(core::FlagCallWrite_GL::CallGetData), &TableSelectionTx::writeDataCallback);
    this->flagStorageWriteOutSlot.SetCallback(core::FlagCallWrite_GL::ClassName(), core::FlagCallWrite_GL::FunctionName(core::FlagCallWrite_GL::CallGetMetaData), &TableSelectionTx::writeMetaDataCallback);
    this->MakeSlotAvailable(&this->flagStorageWriteOutSlot);

    this->updateSelectionParam << new core::param::BoolParam(true);
    this->MakeSlotAvailable(&this->updateSelectionParam);
}

TableSelectionTx::~TableSelectionTx() {
    this->Release();
}

bool TableSelectionTx::create() {
    context_ = std::make_unique<zmq::context_t>(1);

    senderThreadQuit_ = false;
    if (!senderThread_.joinable()) {
        senderThread_ = std::thread(&TableSelectionTx::selectionSender, this);
    }

    receiverThreadQuit_ = false;
    if (!receiverThread_.joinable()) {
        receiverThread_ = std::thread(&TableSelectionTx::selectionReceiver, this);
    }

    return true;
}

void TableSelectionTx::release() {
    senderThreadQuit_ = true;
    receiverThreadQuit_ = true;
    senderThreadNotified_ = true;
    condVar_.notify_one();
    context_->close();
    context_.reset();
    if (senderThread_.joinable()) {
        senderThread_.join();
    }
    if (receiverThread_.joinable()) {
        receiverThread_.join();
    }
}

bool TableSelectionTx::readDataCallback(core::Call& call) {
    auto *flagsReadOutCall = dynamic_cast<core::FlagCallRead_GL*>(&call);
    if (flagsReadOutCall == nullptr) {
        return false;
    }

    if (!validateCalls()) {
        return false;
    }

    if (!validateSelectionUpdate()) {
        return false;
    }

    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();

    (*flagsReadInCall)(core::FlagCallRead_GL::CallGetData);
    flagsReadOutCall->setData(flagsReadInCall->getData(), flagsReadInCall->version());

    return true;
}

bool TableSelectionTx::readMetaDataCallback(core::Call& call) {
    // FlagCall_GL has empty meta data
    return true;
}

bool TableSelectionTx::writeDataCallback(core::Call& call) {
    auto *flagsWriteOutCall = dynamic_cast<core::FlagCallWrite_GL*>(&call);
    if (flagsWriteOutCall == nullptr) {
        return false;
    }

    if (!validateCalls()) {
        return false;
    }

    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();

    flagsWriteInCall->setData(flagsWriteOutCall->getData(), flagsWriteOutCall->version());
    (*flagsWriteInCall)(core::FlagCallWrite_GL::CallGetData);

    // Send data

    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();

    tableInCall->SetFrameID(0);
    (*tableInCall)(1);
    (*tableInCall)(0);

    auto flags = flagsWriteOutCall->getData()->flags;
    size_t numberOfFlags = flags->getByteSize() / sizeof(uint32_t);
    size_t numberOfRows = tableInCall->GetRowsCount();

    // validateFlagCount() only increases the buffer, therefore numberOfFlags > numberOfRows is also valid.
    if (numberOfFlags < numberOfRows) {
        vislib::sys::Log::DefaultLog.WriteMsg(vislib::sys::Log::LEVEL_ERROR, "TableSelectionTx: invalid table/flag storage size!");
        return false;
    }

    std::vector<uint32_t> flagsData(numberOfFlags);
    flags->bind();
    glGetBufferSubData(flags->getTarget(), 0, flags->getByteSize(), flagsData.data());

    core::FlagStorage::FlagItemType testMask = core::FlagStorage::ENABLED | core::FlagStorage::FILTERED;
    core::FlagStorage::FlagItemType passMask = core::FlagStorage::ENABLED;

    std::unique_lock<std::mutex> lock(selectedMutex_);
    selected_.clear();
    for (size_t i = 0; i < numberOfRows; ++i) {
        if ((flagsData[i] & testMask) == passMask) {
            if (flagsData[i] & core::FlagStorage::SELECTED) {
                selected_.push_back(static_cast<uint64_t>(i));
            } else {
                // not selected
            }
        }
    }
    senderThreadNotified_ = true;
    condVar_.notify_one();
    lock.unlock();

    return true;
}

bool TableSelectionTx::writeMetaDataCallback(core::Call& call) {
    // FlagCall_GL has empty meta data
    return true;
}

bool TableSelectionTx::validateCalls() {
    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();
    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();
    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();

    if (tableInCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteMsg(vislib::sys::Log::LEVEL_ERROR, "TableSelectionTx requires a table!");
        return false;
    }

    if (flagsReadInCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteMsg(vislib::sys::Log::LEVEL_ERROR, "TableSelectionTx requires a read flag storage!");
        return false;
    }

    if (flagsWriteInCall == nullptr) {
        vislib::sys::Log::DefaultLog.WriteMsg(vislib::sys::Log::LEVEL_ERROR, "TableSelectionTx requires a write flag storage!");
        return false;
    }

    return true;
}

bool TableSelectionTx::validateSelectionUpdate() {
    std::lock_guard<std::mutex> lock(receivedSelectionMutex_);
    if (!receivedSelectionUpdate_) {
        return true;
    }

    receivedSelectionUpdate_ = false;

    if (!this->updateSelectionParam.Param<core::param::BoolParam>()->Value()) {
        return true;
    }

    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();
    (*flagsReadInCall)(core::FlagCallRead_GL::CallGetData);
    auto flagCollection = flagsReadInCall->getData();
    auto version = flagsReadInCall->version();

    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();
    tableInCall->SetFrameID(0);
    (*tableInCall)(1);
    (*tableInCall)(0);

    size_t numberOfRows = tableInCall->GetRowsCount();

    std::vector<uint32_t> flags_data(numberOfRows, core::FlagStorage::ENABLED);

    // Select received rows
    for (auto id : receivedSelection_) {
        if (id >= 0 && id < numberOfRows) {
            flags_data[id] = core::FlagStorage::ENABLED | core::FlagStorage::SELECTED;
        }
    }

    flagCollection->flags = std::make_shared<glowl::BufferObject>(GL_SHADER_STORAGE_BUFFER, flags_data, GL_DYNAMIC_DRAW);

    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();
    flagsWriteInCall->setData(flagCollection, version + 1);
    (*flagsWriteInCall)(core::FlagCallWrite_GL::CallGetData);

    return true;
}

void TableSelectionTx::selectionSender() {
    zmq::socket_t socket{*context_, ZMQ_REQ};
    socket.setsockopt(ZMQ_LINGER, 0);
    socket.connect("tcp://localhost:10001");

    std::unique_lock<std::mutex> lock(selectedMutex_);
    while (!senderThreadQuit_) {
        while (!senderThreadNotified_ && !senderThreadQuit_) {
            condVar_.wait(lock);
        }
        while (senderThreadNotified_ && !senderThreadQuit_) {
            senderThreadNotified_ = false;
            try {
                zmq::message_t request{selected_.cbegin(), selected_.cend()};
                lock.unlock();
                socket.send(request, zmq::send_flags::none);

                zmq::message_t reply{};
                socket.recv(reply, zmq::recv_flags::none);
            } catch (const zmq::error_t& e) {
                if (e.num() != ETERM) {
                    std::cerr << e.what() << std::endl;
                }
            }
            lock.lock();
        }
    }
}

void TableSelectionTx::selectionReceiver() {
    zmq::socket_t socket{*context_, ZMQ_REP};
    socket.bind("tcp://*:10002");

    const std::string okString{"Ok!"};

    while (!receiverThreadQuit_) {
        try {
            zmq::message_t request;
            socket.recv(request, zmq::recv_flags::none);
            size_t size = request.size() / sizeof(uint64_t);

            if (size > 0) {
                std::lock_guard<std::mutex> lock(receivedSelectionMutex_);
                uint64_t* data_ptr = static_cast<uint64_t*>(request.data());
                receivedSelection_ = std::vector<uint64_t>(data_ptr, data_ptr + size);
                receivedSelectionUpdate_ = true;
            }

            zmq::message_t reply{okString.cbegin(), okString.cend()};
            socket.send(reply, zmq::send_flags::none);
        } catch (const zmq::error_t& e) {
            if (e.num() != ETERM) {
                std::cerr << e.what() << std::endl;
            }
        }
    }
}
<commit_msg>Update log for TableSelectionTx<commit_after>/*
 * TableSelectionTx.cpp
 *
 * Copyright (C) 2020 by VISUS (University of Stuttgart)
 * Alle Rechte vorbehalten.
 */

#include "stdafx.h"
#include "TableSelectionTx.h"

#include "mmcore/param/BoolParam.h"
#include "mmcore/utility/log/Log.h"

using namespace megamol::stdplugin::datatools;
using namespace megamol::stdplugin::datatools::table;
using namespace megamol;

TableSelectionTx::TableSelectionTx()
    : core::Module()
    , tableInSlot("getTableIn", "Float table input")
    , flagStorageReadInSlot("readFlagStorageIn", "Flag storage read input")
    , flagStorageWriteInSlot("writeFlagStorageIn", "Flag storage write input")
    , flagStorageReadOutSlot("readFlagStorageOut", "Flag storage read output")
    , flagStorageWriteOutSlot("writeFlagStorageOut", "Flag storage write output")
    , updateSelectionParam("updateSelectionParam", "Enable selection update")
    , senderThreadQuit_(false)
    , senderThreadNotified_(false)
    , receiverThreadQuit_(false)
    , receivedSelectionUpdate_(false)
{
    this->tableInSlot.SetCompatibleCall<TableDataCallDescription>();
    this->MakeSlotAvailable(&this->tableInSlot);

    this->flagStorageReadInSlot.SetCompatibleCall<core::FlagCallRead_GLDescription>();
    this->MakeSlotAvailable(&this->flagStorageReadInSlot);

    this->flagStorageWriteInSlot.SetCompatibleCall<core::FlagCallWrite_GLDescription>();
    this->MakeSlotAvailable(&this->flagStorageWriteInSlot);

    this->flagStorageReadOutSlot.SetCallback(core::FlagCallRead_GL::ClassName(), core::FlagCallRead_GL::FunctionName(core::FlagCallRead_GL::CallGetData), &TableSelectionTx::readDataCallback);
    this->flagStorageReadOutSlot.SetCallback(core::FlagCallRead_GL::ClassName(), core::FlagCallRead_GL::FunctionName(core::FlagCallRead_GL::CallGetMetaData), &TableSelectionTx::readMetaDataCallback);
    this->MakeSlotAvailable(&this->flagStorageReadOutSlot);

    this->flagStorageWriteOutSlot.SetCallback(core::FlagCallWrite_GL::ClassName(), core::FlagCallWrite_GL::FunctionName(core::FlagCallWrite_GL::CallGetData), &TableSelectionTx::writeDataCallback);
    this->flagStorageWriteOutSlot.SetCallback(core::FlagCallWrite_GL::ClassName(), core::FlagCallWrite_GL::FunctionName(core::FlagCallWrite_GL::CallGetMetaData), &TableSelectionTx::writeMetaDataCallback);
    this->MakeSlotAvailable(&this->flagStorageWriteOutSlot);

    this->updateSelectionParam << new core::param::BoolParam(true);
    this->MakeSlotAvailable(&this->updateSelectionParam);
}

TableSelectionTx::~TableSelectionTx() {
    this->Release();
}

bool TableSelectionTx::create() {
    context_ = std::make_unique<zmq::context_t>(1);

    senderThreadQuit_ = false;
    if (!senderThread_.joinable()) {
        senderThread_ = std::thread(&TableSelectionTx::selectionSender, this);
    }

    receiverThreadQuit_ = false;
    if (!receiverThread_.joinable()) {
        receiverThread_ = std::thread(&TableSelectionTx::selectionReceiver, this);
    }

    return true;
}

void TableSelectionTx::release() {
    senderThreadQuit_ = true;
    receiverThreadQuit_ = true;
    senderThreadNotified_ = true;
    condVar_.notify_one();
    context_->close();
    context_.reset();
    if (senderThread_.joinable()) {
        senderThread_.join();
    }
    if (receiverThread_.joinable()) {
        receiverThread_.join();
    }
}

bool TableSelectionTx::readDataCallback(core::Call& call) {
    auto *flagsReadOutCall = dynamic_cast<core::FlagCallRead_GL*>(&call);
    if (flagsReadOutCall == nullptr) {
        return false;
    }

    if (!validateCalls()) {
        return false;
    }

    if (!validateSelectionUpdate()) {
        return false;
    }

    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();

    (*flagsReadInCall)(core::FlagCallRead_GL::CallGetData);
    flagsReadOutCall->setData(flagsReadInCall->getData(), flagsReadInCall->version());

    return true;
}

bool TableSelectionTx::readMetaDataCallback(core::Call& call) {
    // FlagCall_GL has empty meta data
    return true;
}

bool TableSelectionTx::writeDataCallback(core::Call& call) {
    auto *flagsWriteOutCall = dynamic_cast<core::FlagCallWrite_GL*>(&call);
    if (flagsWriteOutCall == nullptr) {
        return false;
    }

    if (!validateCalls()) {
        return false;
    }

    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();

    flagsWriteInCall->setData(flagsWriteOutCall->getData(), flagsWriteOutCall->version());
    (*flagsWriteInCall)(core::FlagCallWrite_GL::CallGetData);

    // Send data

    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();

    tableInCall->SetFrameID(0);
    (*tableInCall)(1);
    (*tableInCall)(0);

    auto flags = flagsWriteOutCall->getData()->flags;
    size_t numberOfFlags = flags->getByteSize() / sizeof(uint32_t);
    size_t numberOfRows = tableInCall->GetRowsCount();

    // validateFlagCount() only increases the buffer, therefore numberOfFlags > numberOfRows is also valid.
    if (numberOfFlags < numberOfRows) {
        megamol::core::utility::log::Log::DefaultLog.WriteError("TableSelectionTx: invalid table/flag storage size!");
        return false;
    }

    std::vector<uint32_t> flagsData(numberOfFlags);
    flags->bind();
    glGetBufferSubData(flags->getTarget(), 0, flags->getByteSize(), flagsData.data());

    core::FlagStorage::FlagItemType testMask = core::FlagStorage::ENABLED | core::FlagStorage::FILTERED;
    core::FlagStorage::FlagItemType passMask = core::FlagStorage::ENABLED;

    std::unique_lock<std::mutex> lock(selectedMutex_);
    selected_.clear();
    for (size_t i = 0; i < numberOfRows; ++i) {
        if ((flagsData[i] & testMask) == passMask) {
            if (flagsData[i] & core::FlagStorage::SELECTED) {
                selected_.push_back(static_cast<uint64_t>(i));
            } else {
                // not selected
            }
        }
    }
    senderThreadNotified_ = true;
    condVar_.notify_one();
    lock.unlock();

    return true;
}

bool TableSelectionTx::writeMetaDataCallback(core::Call& call) {
    // FlagCall_GL has empty meta data
    return true;
}

bool TableSelectionTx::validateCalls() {
    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();
    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();
    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();

    if (tableInCall == nullptr) {
        megamol::core::utility::log::Log::DefaultLog.WriteError("TableSelectionTx requires a table!");
        return false;
    }

    if (flagsReadInCall == nullptr) {
        megamol::core::utility::log::Log::DefaultLog.WriteError("TableSelectionTx requires a read flag storage!");
        return false;
    }

    if (flagsWriteInCall == nullptr) {
        megamol::core::utility::log::Log::DefaultLog.WriteError("TableSelectionTx requires a write flag storage!");
        return false;
    }

    return true;
}

bool TableSelectionTx::validateSelectionUpdate() {
    std::lock_guard<std::mutex> lock(receivedSelectionMutex_);
    if (!receivedSelectionUpdate_) {
        return true;
    }

    receivedSelectionUpdate_ = false;

    if (!this->updateSelectionParam.Param<core::param::BoolParam>()->Value()) {
        return true;
    }

    auto *flagsReadInCall = this->flagStorageReadInSlot.CallAs<core::FlagCallRead_GL>();
    (*flagsReadInCall)(core::FlagCallRead_GL::CallGetData);
    auto flagCollection = flagsReadInCall->getData();
    auto version = flagsReadInCall->version();

    auto *tableInCall = this->tableInSlot.CallAs<TableDataCall>();
    tableInCall->SetFrameID(0);
    (*tableInCall)(1);
    (*tableInCall)(0);

    size_t numberOfRows = tableInCall->GetRowsCount();

    std::vector<uint32_t> flags_data(numberOfRows, core::FlagStorage::ENABLED);

    // Select received rows
    for (auto id : receivedSelection_) {
        if (id >= 0 && id < numberOfRows) {
            flags_data[id] = core::FlagStorage::ENABLED | core::FlagStorage::SELECTED;
        }
    }

    flagCollection->flags = std::make_shared<glowl::BufferObject>(GL_SHADER_STORAGE_BUFFER, flags_data, GL_DYNAMIC_DRAW);

    auto *flagsWriteInCall = this->flagStorageWriteInSlot.CallAs<core::FlagCallWrite_GL>();
    flagsWriteInCall->setData(flagCollection, version + 1);
    (*flagsWriteInCall)(core::FlagCallWrite_GL::CallGetData);

    return true;
}

void TableSelectionTx::selectionSender() {
    zmq::socket_t socket{*context_, ZMQ_REQ};
    socket.setsockopt(ZMQ_LINGER, 0);
    socket.connect("tcp://localhost:10001");

    std::unique_lock<std::mutex> lock(selectedMutex_);
    while (!senderThreadQuit_) {
        while (!senderThreadNotified_ && !senderThreadQuit_) {
            condVar_.wait(lock);
        }
        while (senderThreadNotified_ && !senderThreadQuit_) {
            senderThreadNotified_ = false;
            try {
                zmq::message_t request{selected_.cbegin(), selected_.cend()};
                lock.unlock();
                socket.send(request, zmq::send_flags::none);

                zmq::message_t reply{};
                socket.recv(reply, zmq::recv_flags::none);
            } catch (const zmq::error_t& e) {
                if (e.num() != ETERM) {
                    std::cerr << e.what() << std::endl;
                }
            }
            lock.lock();
        }
    }
}

void TableSelectionTx::selectionReceiver() {
    zmq::socket_t socket{*context_, ZMQ_REP};
    socket.bind("tcp://*:10002");

    const std::string okString{"Ok!"};

    while (!receiverThreadQuit_) {
        try {
            zmq::message_t request;
            socket.recv(request, zmq::recv_flags::none);
            size_t size = request.size() / sizeof(uint64_t);

            if (size > 0) {
                std::lock_guard<std::mutex> lock(receivedSelectionMutex_);
                uint64_t* data_ptr = static_cast<uint64_t*>(request.data());
                receivedSelection_ = std::vector<uint64_t>(data_ptr, data_ptr + size);
                receivedSelectionUpdate_ = true;
            }

            zmq::message_t reply{okString.cbegin(), okString.cend()};
            socket.send(reply, zmq::send_flags::none);
        } catch (const zmq::error_t& e) {
            if (e.num() != ETERM) {
                std::cerr << e.what() << std::endl;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/shared_memory_object.hpp"
#include "iceoryx_hoofs/cxx/attributes.hpp"
#include "iceoryx_hoofs/cxx/helplets.hpp"
#include "iceoryx_hoofs/log/logging.hpp"
#include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp"
#include "iceoryx_hoofs/posix_wrapper/types.hpp"
#include "iceoryx_platform/fcntl.hpp"
#include "iceoryx_platform/unistd.hpp"

#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>

namespace iox
{
namespace posix
{
constexpr const void* const SharedMemoryObject::NO_ADDRESS_HINT;
constexpr uint64_t SIGBUS_ERROR_MESSAGE_LENGTH = 1024U + platform::IOX_MAX_SHM_NAME_LENGTH;

/// NOLINTJUSTIFICATION global variables are only accessible from within this compilation unit
/// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
///
/// NOLINTJUSTIFICATION c array required to print a signal safe error message in memsetSigbusHandler
/// NOLINTNEXTLINE(hicpp-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
static char sigbusErrorMessage[SIGBUS_ERROR_MESSAGE_LENGTH];
static std::mutex sigbusHandlerMutex;
/// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)

static void memsetSigbusHandler(int) noexcept
{
    auto result =
        write(STDERR_FILENO, &sigbusErrorMessage[0], strnlen(&sigbusErrorMessage[0], SIGBUS_ERROR_MESSAGE_LENGTH));
    IOX_DISCARD_RESULT(result);
    _exit(EXIT_FAILURE);
}

// NOLINTJUSTIFICATION the function size is related to the error handling and the cognitive complexity
// results from the expanded log macro
// NOLINTNEXTLINE(readability-function-size,readability-function-cognitive-complexity)
cxx::expected<SharedMemoryObject, SharedMemoryObjectError> SharedMemoryObjectBuilder::create() noexcept
{
    auto printErrorDetails = [this] {
        LogError() << "Unable to create a shared memory object with the following properties [ name = " << m_name
                   << ", sizeInBytes = " << m_memorySizeInBytes << ", access mode = " << asStringLiteral(m_accessMode)
                   << ", open mode = " << asStringLiteral(m_openMode) << ", baseAddressHint = "
                   << ((m_baseAddressHint) ? iox::log::hex(m_baseAddressHint.value())
                                           : iox::log::hex(static_cast<uint64_t>(0U)))
                   << ((m_baseAddressHint) ? "" : " (no hint set)")
                   << ", permissions = " << iox::log::hex(static_cast<mode_t>(m_permissions)) << " ]";
    };

    auto sharedMemory = SharedMemoryBuilder()
                            .name(m_name)
                            .accessMode(m_accessMode)
                            .openMode(m_openMode)
                            .filePermissions(m_permissions)
                            .size(m_memorySizeInBytes)
                            .create();

    if (!sharedMemory)
    {
        printErrorDetails();
        LogError() << "Unable to create SharedMemoryObject since we could not acquire a SharedMemory resource";
        return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::SHARED_MEMORY_CREATION_FAILED);
    }

    auto memoryMap = MemoryMapBuilder()
                         .baseAddressHint((m_baseAddressHint) ? *m_baseAddressHint : nullptr)
                         .length(m_memorySizeInBytes)
                         .fileDescriptor(sharedMemory->getHandle())
                         .accessMode(m_accessMode)
                         .flags(MemoryMapFlags::SHARE_CHANGES)
                         .offset(0)
                         .create();

    if (!memoryMap)
    {
        printErrorDetails();
        LogError() << "Failed to map created shared memory into process!";
        return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::MAPPING_SHARED_MEMORY_FAILED);
    }

    Allocator allocator(memoryMap->getBaseAddress(), m_memorySizeInBytes);

    if (sharedMemory->hasOwnership())
    {
        LogDebug() << "Trying to reserve " << m_memorySizeInBytes << " bytes in the shared memory [" << m_name << "]";
        if (platform::IOX_SHM_WRITE_ZEROS_ON_CREATION)
        {
            // this lock is required for the case that multiple threads are creating multiple
            // shared memory objects concurrently
            std::lock_guard<std::mutex> lock(sigbusHandlerMutex);
            auto memsetSigbusGuard = registerSignalHandler(Signal::BUS, memsetSigbusHandler);
            if (memsetSigbusGuard.has_error())
            {
                printErrorDetails();
                LogError() << "Failed to temporarily override SIGBUS to safely zero the shared memory";
                return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::INTERNAL_LOGIC_FAILURE);
            }

            // NOLINTJUSTIFICATION snprintf required to populate char array so that it can be used signal safe in
            //                     a possible signal call
            // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
            IOX_DISCARD_RESULT(snprintf(
                &sigbusErrorMessage[0],
                SIGBUS_ERROR_MESSAGE_LENGTH,
                "While setting the acquired shared memory to zero a fatal SIGBUS signal appeared caused by memset. The "
                "shared memory object with the following properties [ name = %s, sizeInBytes = %llu, access mode = %s, "
                "open mode = %s, baseAddressHint = %p, permissions = %lu ] maybe requires more memory than it is "
                "currently available in the system.\n",
                m_name.c_str(),
                static_cast<unsigned long long>(m_memorySizeInBytes),
                asStringLiteral(m_accessMode),
                asStringLiteral(m_openMode),
                (m_baseAddressHint) ? *m_baseAddressHint : nullptr,
                std::bitset<sizeof(mode_t)>(static_cast<mode_t>(m_permissions)).to_ulong()));

            memset(memoryMap->getBaseAddress(), 0, m_memorySizeInBytes);
        }
        LogDebug() << "Acquired " << m_memorySizeInBytes << " bytes successfully in the shared memory [" << m_name
                   << "]";
    }

    return cxx::success<SharedMemoryObject>(
        SharedMemoryObject(std::move(*sharedMemory), std::move(*memoryMap), std::move(allocator), m_memorySizeInBytes));
}

SharedMemoryObject::SharedMemoryObject(SharedMemory&& sharedMemory,
                                       MemoryMap&& memoryMap,
                                       Allocator&& allocator,
                                       const uint64_t memorySizeInBytes) noexcept
    : m_memorySizeInBytes(memorySizeInBytes)
    , m_sharedMemory(std::move(sharedMemory))
    , m_memoryMap(std::move(memoryMap))
    , m_allocator(std::move(allocator))
{
}

void* SharedMemoryObject::allocate(const uint64_t size, const uint64_t alignment) noexcept
{
    return m_allocator.allocate(size, alignment);
}

void SharedMemoryObject::finalizeAllocation() noexcept
{
    m_allocator.finalizeAllocation();
}

Allocator& SharedMemoryObject::getAllocator() noexcept
{
    return m_allocator;
}

const void* SharedMemoryObject::getBaseAddress() const noexcept
{
    return m_memoryMap.getBaseAddress();
}

void* SharedMemoryObject::getBaseAddress() noexcept
{
    return m_memoryMap.getBaseAddress();
}

uint64_t SharedMemoryObject::getSizeInBytes() const noexcept
{
    return m_memorySizeInBytes;
}

int32_t SharedMemoryObject::getFileHandle() const noexcept
{
    return m_sharedMemory.getHandle();
}

bool SharedMemoryObject::hasOwnership() const noexcept
{
    return m_sharedMemory.hasOwnership();
}

} // namespace posix
} // namespace iox
<commit_msg>iox-#1345 Use octal format to print permission<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/shared_memory_object.hpp"
#include "iceoryx_hoofs/cxx/attributes.hpp"
#include "iceoryx_hoofs/cxx/helplets.hpp"
#include "iceoryx_hoofs/log/logging.hpp"
#include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp"
#include "iceoryx_hoofs/posix_wrapper/types.hpp"
#include "iceoryx_platform/fcntl.hpp"
#include "iceoryx_platform/unistd.hpp"

#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>

namespace iox
{
namespace posix
{
constexpr const void* const SharedMemoryObject::NO_ADDRESS_HINT;
constexpr uint64_t SIGBUS_ERROR_MESSAGE_LENGTH = 1024U + platform::IOX_MAX_SHM_NAME_LENGTH;

/// NOLINTJUSTIFICATION global variables are only accessible from within this compilation unit
/// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
///
/// NOLINTJUSTIFICATION c array required to print a signal safe error message in memsetSigbusHandler
/// NOLINTNEXTLINE(hicpp-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
static char sigbusErrorMessage[SIGBUS_ERROR_MESSAGE_LENGTH];
static std::mutex sigbusHandlerMutex;
/// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)

static void memsetSigbusHandler(int) noexcept
{
    auto result =
        write(STDERR_FILENO, &sigbusErrorMessage[0], strnlen(&sigbusErrorMessage[0], SIGBUS_ERROR_MESSAGE_LENGTH));
    IOX_DISCARD_RESULT(result);
    _exit(EXIT_FAILURE);
}

// NOLINTJUSTIFICATION the function size is related to the error handling and the cognitive complexity
// results from the expanded log macro
// NOLINTNEXTLINE(readability-function-size,readability-function-cognitive-complexity)
cxx::expected<SharedMemoryObject, SharedMemoryObjectError> SharedMemoryObjectBuilder::create() noexcept
{
    auto printErrorDetails = [this] {
        LogError() << "Unable to create a shared memory object with the following properties [ name = " << m_name
                   << ", sizeInBytes = " << m_memorySizeInBytes << ", access mode = " << asStringLiteral(m_accessMode)
                   << ", open mode = " << asStringLiteral(m_openMode) << ", baseAddressHint = "
                   << ((m_baseAddressHint) ? iox::log::hex(m_baseAddressHint.value())
                                           : iox::log::hex(static_cast<uint64_t>(0U)))
                   << ((m_baseAddressHint) ? "" : " (no hint set)")
                   << ", permissions = " << iox::log::oct(static_cast<mode_t>(m_permissions)) << " ]";
    };

    auto sharedMemory = SharedMemoryBuilder()
                            .name(m_name)
                            .accessMode(m_accessMode)
                            .openMode(m_openMode)
                            .filePermissions(m_permissions)
                            .size(m_memorySizeInBytes)
                            .create();

    if (!sharedMemory)
    {
        printErrorDetails();
        LogError() << "Unable to create SharedMemoryObject since we could not acquire a SharedMemory resource";
        return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::SHARED_MEMORY_CREATION_FAILED);
    }

    auto memoryMap = MemoryMapBuilder()
                         .baseAddressHint((m_baseAddressHint) ? *m_baseAddressHint : nullptr)
                         .length(m_memorySizeInBytes)
                         .fileDescriptor(sharedMemory->getHandle())
                         .accessMode(m_accessMode)
                         .flags(MemoryMapFlags::SHARE_CHANGES)
                         .offset(0)
                         .create();

    if (!memoryMap)
    {
        printErrorDetails();
        LogError() << "Failed to map created shared memory into process!";
        return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::MAPPING_SHARED_MEMORY_FAILED);
    }

    Allocator allocator(memoryMap->getBaseAddress(), m_memorySizeInBytes);

    if (sharedMemory->hasOwnership())
    {
        LogDebug() << "Trying to reserve " << m_memorySizeInBytes << " bytes in the shared memory [" << m_name << "]";
        if (platform::IOX_SHM_WRITE_ZEROS_ON_CREATION)
        {
            // this lock is required for the case that multiple threads are creating multiple
            // shared memory objects concurrently
            std::lock_guard<std::mutex> lock(sigbusHandlerMutex);
            auto memsetSigbusGuard = registerSignalHandler(Signal::BUS, memsetSigbusHandler);
            if (memsetSigbusGuard.has_error())
            {
                printErrorDetails();
                LogError() << "Failed to temporarily override SIGBUS to safely zero the shared memory";
                return cxx::error<SharedMemoryObjectError>(SharedMemoryObjectError::INTERNAL_LOGIC_FAILURE);
            }

            // NOLINTJUSTIFICATION snprintf required to populate char array so that it can be used signal safe in
            //                     a possible signal call
            // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
            IOX_DISCARD_RESULT(snprintf(
                &sigbusErrorMessage[0],
                SIGBUS_ERROR_MESSAGE_LENGTH,
                "While setting the acquired shared memory to zero a fatal SIGBUS signal appeared caused by memset. The "
                "shared memory object with the following properties [ name = %s, sizeInBytes = %llu, access mode = %s, "
                "open mode = %s, baseAddressHint = %p, permissions = %lu ] maybe requires more memory than it is "
                "currently available in the system.\n",
                m_name.c_str(),
                static_cast<unsigned long long>(m_memorySizeInBytes),
                asStringLiteral(m_accessMode),
                asStringLiteral(m_openMode),
                (m_baseAddressHint) ? *m_baseAddressHint : nullptr,
                std::bitset<sizeof(mode_t)>(static_cast<mode_t>(m_permissions)).to_ulong()));

            memset(memoryMap->getBaseAddress(), 0, m_memorySizeInBytes);
        }
        LogDebug() << "Acquired " << m_memorySizeInBytes << " bytes successfully in the shared memory [" << m_name
                   << "]";
    }

    return cxx::success<SharedMemoryObject>(
        SharedMemoryObject(std::move(*sharedMemory), std::move(*memoryMap), std::move(allocator), m_memorySizeInBytes));
}

SharedMemoryObject::SharedMemoryObject(SharedMemory&& sharedMemory,
                                       MemoryMap&& memoryMap,
                                       Allocator&& allocator,
                                       const uint64_t memorySizeInBytes) noexcept
    : m_memorySizeInBytes(memorySizeInBytes)
    , m_sharedMemory(std::move(sharedMemory))
    , m_memoryMap(std::move(memoryMap))
    , m_allocator(std::move(allocator))
{
}

void* SharedMemoryObject::allocate(const uint64_t size, const uint64_t alignment) noexcept
{
    return m_allocator.allocate(size, alignment);
}

void SharedMemoryObject::finalizeAllocation() noexcept
{
    m_allocator.finalizeAllocation();
}

Allocator& SharedMemoryObject::getAllocator() noexcept
{
    return m_allocator;
}

const void* SharedMemoryObject::getBaseAddress() const noexcept
{
    return m_memoryMap.getBaseAddress();
}

void* SharedMemoryObject::getBaseAddress() noexcept
{
    return m_memoryMap.getBaseAddress();
}

uint64_t SharedMemoryObject::getSizeInBytes() const noexcept
{
    return m_memorySizeInBytes;
}

int32_t SharedMemoryObject::getFileHandle() const noexcept
{
    return m_sharedMemory.getHandle();
}

bool SharedMemoryObject::hasOwnership() const noexcept
{
    return m_sharedMemory.hasOwnership();
}

} // namespace posix
} // namespace iox
<|endoftext|>