<commit_before>#include "../tlang.h"
#include <taichi/system/timer.h>
#include <openvdb/openvdb.h>
#include <openvdb/io/Stream.h>
#include <openvdb/tools/Filter.h>
#include <openvdb/tools/ChangeBackground.h>

TLANG_NAMESPACE_BEGIN

TC_TEST("hashed_3d") {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog;

  Global(x, i32);
  Global(sum, i32);

  int n = 256;

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);
    root.hashed({i, j, k}, n).place(x);
    root.place(sum);
  });

  x.val<int>(2, 5, 9) = 10;
  x.val<int>(12, 5, 9) = 30;
  x.val<int>(2, 115, 9) = 11;

  auto reduce = kernel([&] {
    Declare(i);
    For(i, x, [&]() { sum[Expr(0)] += x[i]; });
  });

  reduce();

  TC_ASSERT(sum.val<int>() == 51);
};

auto benchmark_vdb = [](std::vector<std::string> param) {
  TC_ASSERT(param.size() == 1);
  auto fn = param[0];

  CoreState::set_trigger_gdb_when_crash(true);
  Program prog;

  AmbientGlobal(x, f32, 0.0f);
  Global(y, f32);
  Global(sum, i32);

  int tree_config[] = {5, 4, 3};

  for (int i = 0; i < 3; i++) {
    tree_config[i] = 1 << tree_config[i];
  }

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);

    int int1_size = tree_config[0];
    int int2_size = tree_config[1];
    int leaf_size = tree_config[2];

    root.hashed({i, j, k}, 1024)
        .fixed({i, j, k}, int1_size)
        .pointer()
        .fixed({i, j, k}, int2_size)
        .pointer()
        .fixed({i, j, k}, leaf_size)
        .place(x, y);

    root.place(sum);
  });

  int num_leaves = 0;

  using GridType = openvdb::FloatGrid;
  using TreeType = GridType::TreeType;
  using RootType = TreeType::RootNodeType;  // level 3 RootNode
  TC_ASSERT(RootType::LEVEL == 3);
  using Int1Type = RootType::ChildNodeType;  // level 2 InternalNode
  using Int2Type = Int1Type::ChildNodeType;  // level 1 InternalNode
  using LeafType = TreeType::LeafNodeType;   // level 0 LeafNode

  // Initialize the OpenVDB library.  This must be called at least
  // once per program and may safely be called multiple times.
  openvdb::initialize();
  // Create an empty floating-point grid with background value 0.

  std::ifstream ifile(fn, std::ios_base::binary);
  auto grids = openvdb::io::Stream(ifile).getGrids();

  auto grid = static_cast<GridType *>((*grids)[0].get());
  openvdb::tools::changeBackground(grid->tree(), 0.0f);

  auto dsl_value = [&](Expr var, openvdb::Coord coord) -> float32 & {
    int offset = 1024;
    int i = coord.x() + offset, j = coord.y() + offset, k = coord.z() + offset;

    TC_ASSERT(i >= 0);
    TC_ASSERT(j >= 0);
    TC_ASSERT(k >= 0);

    return var.val<float32>(i, j, k);
  };

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      real value;
      if (!leaf.probeValue(t, value)) {
        leaf.setValueOn(t, 1.0f);
      }
      auto coord = leaf.offsetToGlobalCoord(t);
      dsl_value(x, coord) = leaf.getValue(t);
    }
    num_leaves += 1;
  }

  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    float sum = 0;
    for (int i = 0; i < 1; i++) {
      for (int j = -1; j < 2; j++) {
        for (int k = 0; k < 1; k++) {
          auto coord = leaf.offsetToGlobalCoord(0);
          coord.x() = -288;
          coord.y() = -8;
          coord.z() = -23;

          coord.x() += i;
          coord.y() += j;
          coord.z() += k;

          auto tmp = grid->tree().getValue(coord);
          TC_P(tmp);
          sum += tmp;
        }
      }
    }
    TC_P(sum / 3);
    break;
  }

  TC_P(grid->tree().getValue(openvdb::Coord(-288, -9, -23)));

  int counter[4] = {0};
  for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) {
    switch (iter.getDepth()) {
      case 0: {
        RootType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[0]++;
        break;
      }
      case 1: {
        Int1Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[1]++;
        break;
      }
      case 2: {
        Int2Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[2]++;
        break;
      }
      case 3: {
        LeafType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[3]++;
        break;
      }
    }
  }
  TC_P(grid->activeVoxelCount());
  for (int i = 0; i < 4; i++) {
    TC_INFO("Depth {}: nodes {}", i, counter[i]);
  }

  openvdb::tools::Filter<GridType> filter(*grid);

  TC_P(grid->tree().getValue(openvdb::Coord(-288, -9, -23)));
  tbb::task_arena limited(1);

  limited.execute([&] {
    for (int i = 0; i < 1; i++)
      TC_TIME(filter.mean(1));
  });

  auto count = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { sum[Expr(0)] += 1; });
  });

  count();

  TC_P(num_leaves);
  TC_ASSERT(num_leaves * pow<3>(8) == sum.val<int>());

  auto mean_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i - 1, j, k] + x[i, j, k] + x[i + 1, j, k]);
    });
  });

  auto mean_y = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j - 1, k] + x[i, j, k] + x[i, j + 1, k]);
    });
  });

  auto mean_z = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j, k - 1] + x[i, j, k] + x[i, j, k + 1]);
    });
  });

  auto copy_y_to_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { x[i, j, k] = y[i, j, k]; });
  });

  auto mean = [&]() {
    mean_x();
    copy_y_to_x();
    mean_y();
    copy_y_to_x();
    mean_z();
    copy_y_to_x();
  };

  for (int i = 0; i < 1; i++)
    TC_TIME(mean());

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      // TC_P(t);
      auto coord = leaf.offsetToGlobalCoord(t);
      // fmt::print("{} {} {}\n", coord.x(), coord.y(), coord.z());
      auto dsl = dsl_value(x, coord), vdb = leaf.getValue(t);
      TC_ASSERT_EQUAL(dsl, vdb, 1e-5_f);
    }
    num_leaves += 1;
  }
};

TC_REGISTER_TASK(benchmark_vdb);

TLANG_NAMESPACE_END
<commit_msg>fixed tests<commit_after>#include "../tlang.h"
#include <taichi/system/timer.h>
#include <openvdb/openvdb.h>
#include <openvdb/io/Stream.h>
#include <openvdb/tools/Filter.h>
#include <openvdb/tools/ChangeBackground.h>

TLANG_NAMESPACE_BEGIN

TC_TEST("hashed_3d") {
  CoreState::set_trigger_gdb_when_crash(true);

  Program prog;

  Global(x, i32);
  Global(sum, i32);

  int n = 256;

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);
    root.hashed({i, j, k}, n).place(x);
    root.place(sum);
  });

  x.val<int>(2, 5, 9) = 10;
  x.val<int>(12, 5, 9) = 30;
  x.val<int>(2, 115, 9) = 11;

  auto reduce = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { sum[Expr(0)] += x[i, j, k]; });
  });

  reduce();

  TC_ASSERT(sum.val<int>() == 51);
};

auto benchmark_vdb = [](std::vector<std::string> param) {
  TC_ASSERT(param.size() == 1);
  auto fn = param[0];

  CoreState::set_trigger_gdb_when_crash(true);
  Program prog;

  AmbientGlobal(x, f32, 0.0f);
  Global(y, f32);
  Global(sum, i32);

  int tree_config[] = {5, 4, 3};

  for (int i = 0; i < 3; i++) {
    tree_config[i] = 1 << tree_config[i];
  }

  layout([&] {
    auto i = Index(0), j = Index(1), k = Index(2);

    int int1_size = tree_config[0];
    int int2_size = tree_config[1];
    int leaf_size = tree_config[2];

    root.hashed({i, j, k}, 1024)
        .fixed({i, j, k}, int1_size)
        .pointer()
        .fixed({i, j, k}, int2_size)
        .pointer()
        .fixed({i, j, k}, leaf_size)
        .place(x, y);

    root.place(sum);
  });

  int num_leaves = 0;

  using GridType = openvdb::FloatGrid;
  using TreeType = GridType::TreeType;
  using RootType = TreeType::RootNodeType;  // level 3 RootNode
  TC_ASSERT(RootType::LEVEL == 3);
  using Int1Type = RootType::ChildNodeType;  // level 2 InternalNode
  using Int2Type = Int1Type::ChildNodeType;  // level 1 InternalNode
  using LeafType = TreeType::LeafNodeType;   // level 0 LeafNode

  // Initialize the OpenVDB library.  This must be called at least
  // once per program and may safely be called multiple times.
  openvdb::initialize();
  // Create an empty floating-point grid with background value 0.

  std::ifstream ifile(fn, std::ios_base::binary);
  auto grids = openvdb::io::Stream(ifile).getGrids();

  auto grid = static_cast<GridType *>((*grids)[0].get());
  openvdb::tools::changeBackground(grid->tree(), 0.0f);

  auto dsl_value = [&](Expr var, openvdb::Coord coord) -> float32 & {
    int offset = 1024;
    int i = coord.x() + offset, j = coord.y() + offset, k = coord.z() + offset;

    TC_ASSERT(i >= 0);
    TC_ASSERT(j >= 0);
    TC_ASSERT(k >= 0);

    return var.val<float32>(i, j, k);
  };

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      real value;
      if (!leaf.probeValue(t, value)) {
        leaf.setValueOn(t, 1.0f);
      }
      auto coord = leaf.offsetToGlobalCoord(t);
      dsl_value(x, coord) = leaf.getValue(t);
    }
    num_leaves += 1;
  }

  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    float sum = 0;
    for (int i = 0; i < 1; i++) {
      for (int j = -1; j < 2; j++) {
        for (int k = 0; k < 1; k++) {
          auto coord = leaf.offsetToGlobalCoord(0);
          coord.x() = -288;
          coord.y() = -8;
          coord.z() = -23;

          coord.x() += i;
          coord.y() += j;
          coord.z() += k;

          auto tmp = grid->tree().getValue(coord);
          TC_P(tmp);
          sum += tmp;
        }
      }
    }
    TC_P(sum / 3);
    break;
  }

  TC_P(grid->tree().getValue(openvdb::Coord(-288, -9, -23)));

  int counter[4] = {0};
  for (TreeType::NodeIter iter = grid->tree().beginNode(); iter; ++iter) {
    switch (iter.getDepth()) {
      case 0: {
        RootType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[0]++;
        break;
      }
      case 1: {
        Int1Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[1]++;
        break;
      }
      case 2: {
        Int2Type *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[2]++;
        break;
      }
      case 3: {
        LeafType *node = nullptr;
        iter.getNode(node);
        if (node)
          counter[3]++;
        break;
      }
    }
  }
  TC_P(grid->activeVoxelCount());
  for (int i = 0; i < 4; i++) {
    TC_INFO("Depth {}: nodes {}", i, counter[i]);
  }

  openvdb::tools::Filter<GridType> filter(*grid);

  TC_P(grid->tree().getValue(openvdb::Coord(-288, -9, -23)));
  tbb::task_arena limited(1);

  limited.execute([&] {
    for (int i = 0; i < 1; i++)
      TC_TIME(filter.mean(1));
  });

  auto count = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { sum[Expr(0)] += 1; });
  });

  count();

  TC_P(num_leaves);
  TC_ASSERT(num_leaves * pow<3>(8) == sum.val<int>());

  auto mean_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i - 1, j, k] + x[i, j, k] + x[i + 1, j, k]);
    });
  });

  auto mean_y = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j - 1, k] + x[i, j, k] + x[i, j + 1, k]);
    });
  });

  auto mean_z = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() {
      y[i, j, k] = (1.0_f / 3) * (x[i, j, k - 1] + x[i, j, k] + x[i, j, k + 1]);
    });
  });

  auto copy_y_to_x = kernel([&] {
    Declare(i);
    Declare(j);
    Declare(k);
    For((i, j, k), x, [&]() { x[i, j, k] = y[i, j, k]; });
  });

  auto mean = [&]() {
    mean_x();
    copy_y_to_x();
    mean_y();
    copy_y_to_x();
    mean_z();
    copy_y_to_x();
  };

  for (int i = 0; i < 1; i++)
    TC_TIME(mean());

  // densely fill voxel
  for (auto iter = grid->tree().beginLeaf(); iter; ++iter) {
    auto &leaf = *iter;
    for (int t = 0; t < 512; t++) {
      // TC_P(t);
      auto coord = leaf.offsetToGlobalCoord(t);
      // fmt::print("{} {} {}\n", coord.x(), coord.y(), coord.z());
      auto dsl = dsl_value(x, coord), vdb = leaf.getValue(t);
      TC_ASSERT_EQUAL(dsl, vdb, 1e-5_f);
    }
    num_leaves += 1;
  }
};

TC_REGISTER_TASK(benchmark_vdb);

TLANG_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 * Author: Brad Beckmann, Marc Orr
 */

#include "gpu-compute/dispatcher.hh"

#include "cpu/base.hh"
#include "debug/GPUDisp.hh"
#include "gpu-compute/cl_driver.hh"
#include "gpu-compute/cl_event.hh"
#include "gpu-compute/shader.hh"
#include "gpu-compute/wavefront.hh"
#include "mem/packet_access.hh"

GpuDispatcher *GpuDispatcher::instance = nullptr;

GpuDispatcher::GpuDispatcher(const Params *p)
    : DmaDevice(p), _masterId(p->system->getMasterId(name() + ".disp")),
      pioAddr(p->pio_addr), pioSize(4096), pioDelay(p->pio_latency),
      dispatchCount(0), dispatchActive(false), cpu(p->cpu),
      shader(p->shader_pointer), driver(p->cl_driver), tickEvent(this)
{
    shader->handshake(this);
    driver->handshake(this);

    ndRange.wg_disp_rem = false;
    ndRange.globalWgId = 0;

    schedule(&tickEvent, 0);

    // translation port for the dispatcher
    tlbPort = new TLBPort(csprintf("%s-port%d", name()), this);

    num_kernelLaunched
    .name(name() + ".num_kernel_launched")
    .desc("number of kernel launched")
    ;
}

GpuDispatcher *GpuDispatcherParams::create()
{
    GpuDispatcher *dispatcher = new GpuDispatcher(this);
    GpuDispatcher::setInstance(dispatcher);

    return GpuDispatcher::getInstance();
}

void
GpuDispatcher::serialize(CheckpointOut &cp) const
{
    Tick event_tick = 0;

    if (ndRange.wg_disp_rem)
        fatal("Checkpointing not supported during active workgroup execution");

    if (tickEvent.scheduled())
        event_tick = tickEvent.when();

    SERIALIZE_SCALAR(event_tick);

}

void
GpuDispatcher::unserialize(CheckpointIn &cp)
{
    Tick event_tick;

    if (tickEvent.scheduled())
        deschedule(&tickEvent);

    UNSERIALIZE_SCALAR(event_tick);

    if (event_tick)
        schedule(&tickEvent, event_tick);
}

AddrRangeList
GpuDispatcher::getAddrRanges() const
{
    AddrRangeList ranges;

    DPRINTF(GPUDisp, "dispatcher registering addr range at %#x size %#x\n",
            pioAddr, pioSize);

    ranges.push_back(RangeSize(pioAddr, pioSize));

    return ranges;
}

Tick
GpuDispatcher::read(PacketPtr pkt)
{
    assert(pkt->getAddr() >= pioAddr);
    assert(pkt->getAddr() < pioAddr + pioSize);

    int offset = pkt->getAddr() - pioAddr;
    pkt->allocate();

    DPRINTF(GPUDisp, " read register %#x size=%d\n", offset, pkt->getSize());

    if (offset < 8) {
        assert(!offset);
        assert(pkt->getSize() == 8);

        uint64_t retval = dispatchActive;
        pkt->set(retval);
    } else {
        offset -= 8;
        assert(offset + pkt->getSize() < sizeof(HsaQueueEntry));
        char *curTaskPtr = (char*)&curTask;

        memcpy(pkt->getPtr<const void*>(), curTaskPtr + offset, pkt->getSize());
    }

    pkt->makeAtomicResponse();

    return pioDelay;
}

Tick
GpuDispatcher::write(PacketPtr pkt)
{
    assert(pkt->getAddr() >= pioAddr);
    assert(pkt->getAddr() < pioAddr + pioSize);

    int offset = pkt->getAddr() - pioAddr;

#if TRACING_ON
    uint64_t data_val = 0;

    switch (pkt->getSize()) {
      case 1:
        data_val = pkt->get<uint8_t>();
        break;
      case 2:
        data_val = pkt->get<uint16_t>();
        break;
      case 4:
        data_val = pkt->get<uint32_t>();
        break;
      case 8:
        data_val = pkt->get<uint64_t>();
        break;
      default:
        DPRINTF(GPUDisp, "bad size %d\n", pkt->getSize());
    }

    DPRINTF(GPUDisp, "write register %#x value %#x size=%d\n", offset, data_val,
            pkt->getSize());
#endif
    if (!offset) {
        static int nextId = 0;

        // The depends field of the qstruct, which was previously unused, is
        // used to communicate with simulated application.
        if (curTask.depends) {
            HostState hs;
            shader->ReadMem((uint64_t)(curTask.depends), &hs,
                            sizeof(HostState), 0);

            // update event start time (in nano-seconds)
            uint64_t start = curTick() / 1000;

            shader->WriteMem((uint64_t)(&((_cl_event*)hs.event)->start),
                             &start, sizeof(uint64_t), 0);
        }

        // launch kernel
        ++num_kernelLaunched;

        NDRange *ndr = &(ndRangeMap[nextId]);
        // copy dispatch info
        ndr->q = curTask;

        // update the numDispTask polled by the runtime
        accessUserVar(cpu, (uint64_t)(curTask.numDispLeft), 0, 1);

        ndr->numWgTotal = 1;

        for (int i = 0; i < 3; ++i) {
            ndr->wgId[i] = 0;
            ndr->numWg[i] = divCeil(curTask.gdSize[i], curTask.wgSize[i]);
            ndr->numWgTotal *= ndr->numWg[i];
        }

        ndr->numWgCompleted = 0;
        ndr->globalWgId = 0;
        ndr->wg_disp_rem = true;
        ndr->execDone = false;
        ndr->addrToNotify = (volatile bool*)curTask.addrToNotify;
        ndr->numDispLeft = (volatile uint32_t*)curTask.numDispLeft;
        ndr->dispatchId = nextId;
        ndr->curCid = pkt->req->contextId();
        DPRINTF(GPUDisp, "launching kernel %d\n",nextId);
        execIds.push(nextId);
        ++nextId;

        dispatchActive = true;

        if (!tickEvent.scheduled()) {
            schedule(&tickEvent, curTick() + shader->ticks(1));
        }
    } else {
        // populate current task struct
        // first 64 bits are launch reg
        offset -= 8;
        assert(offset < sizeof(HsaQueueEntry));
        char *curTaskPtr = (char*)&curTask;
        memcpy(curTaskPtr + offset, pkt->getPtr<const void*>(), pkt->getSize());
    }

    pkt->makeAtomicResponse();

    return pioDelay;
}

BaseMasterPort&
GpuDispatcher::getMasterPort(const std::string &if_name, PortID idx)
{
    if (if_name == "translation_port") {
        return *tlbPort;
    }

    return DmaDevice::getMasterPort(if_name, idx);
}

void
GpuDispatcher::exec()
{
    int fail_count = 0;

    // There are potentially multiple outstanding kernel launches.
    // It is possible that the workgroups in a different kernel
    // can fit on the GPU even if another kernel's workgroups cannot
    DPRINTF(GPUDisp, "Launching %d Kernels\n", execIds.size());

    while (execIds.size() > fail_count) {
        int execId = execIds.front();

        while (ndRangeMap[execId].wg_disp_rem) {
            //update the thread context
            shader->updateContext(ndRangeMap[execId].curCid);

            // attempt to dispatch_workgroup
            if (!shader->dispatch_workgroups(&ndRangeMap[execId])) {
                // if we failed try the next kernel,
                // it may have smaller workgroups.
                // put it on the queue to rety latter
                DPRINTF(GPUDisp, "kernel %d failed to launch\n", execId);
                execIds.push(execId);
                ++fail_count;
                break;
            }
        }
        // let's try the next kernel_id
        execIds.pop();
    }

    DPRINTF(GPUDisp, "Returning %d Kernels\n", doneIds.size());

    if (doneIds.size() && cpu) {
        shader->hostWakeUp(cpu);
    }

    while (doneIds.size()) {
        // wakeup the CPU if any Kernels completed this cycle
        DPRINTF(GPUDisp, "WorkGroup %d completed\n", doneIds.front());
        doneIds.pop();
    }
}

void
GpuDispatcher::notifyWgCompl(Wavefront *w)
{
    int kern_id = w->kernId;
    DPRINTF(GPUDisp, "notify WgCompl %d\n",kern_id);
    assert(ndRangeMap[kern_id].dispatchId == kern_id);
    ndRangeMap[kern_id].numWgCompleted++;

    if (ndRangeMap[kern_id].numWgCompleted == ndRangeMap[kern_id].numWgTotal) {
        ndRangeMap[kern_id].execDone = true;
        doneIds.push(kern_id);

        if (ndRangeMap[kern_id].addrToNotify) {
            accessUserVar(cpu, (uint64_t)(ndRangeMap[kern_id].addrToNotify), 1,
                          0);
        }

        accessUserVar(cpu, (uint64_t)(ndRangeMap[kern_id].numDispLeft), 0, -1);

        // update event end time (in nano-seconds)
        if (ndRangeMap[kern_id].q.depends) {
            HostState *host_state = (HostState*)ndRangeMap[kern_id].q.depends;
            uint64_t event;
            shader->ReadMem((uint64_t)(&host_state->event), &event,
                            sizeof(uint64_t), 0);

            uint64_t end = curTick() / 1000;

            shader->WriteMem((uint64_t)(&((_cl_event*)event)->end), &end,
                             sizeof(uint64_t), 0);
        }
    }

    if (!tickEvent.scheduled()) {
        schedule(&tickEvent, curTick() + shader->ticks(1));
    }
}

void
GpuDispatcher::scheduleDispatch()
{
    if (!tickEvent.scheduled())
        schedule(&tickEvent, curTick() + shader->ticks(1));
}

void
GpuDispatcher::accessUserVar(BaseCPU *cpu, uint64_t addr, int val, int off)
{
    if (cpu) {
        if (off) {
            shader->AccessMem(addr, &val, sizeof(int), 0, MemCmd::ReadReq,
                              true);
            val += off;
        }

        shader->AccessMem(addr, &val, sizeof(int), 0, MemCmd::WriteReq, true);
    } else {
        panic("Cannot find host");
    }
}

GpuDispatcher::TickEvent::TickEvent(GpuDispatcher *_dispatcher)
    : Event(CPU_Tick_Pri), dispatcher(_dispatcher)
{
}

void
GpuDispatcher::TickEvent::process()
{
    dispatcher->exec();
}

const char*
GpuDispatcher::TickEvent::description() const
{
    return "GPU Dispatcher tick";
}

// helper functions for driver to retrieve GPU attributes
int
GpuDispatcher::getNumCUs()
{
    return shader->cuList.size();
}

int
GpuDispatcher::wfSize() const
{
    return shader->cuList[0]->wfSize();
}

void
GpuDispatcher::setFuncargsSize(int funcargs_size)
{
    shader->funcargs_size = funcargs_size;
}

uint32_t
GPUDispatcher::getStaticContextSize() const
{
    return shader->cuList[0]->wfList[0][0]->getStaticContextSize();
}
<commit_msg>gpu-compute: fix typo in GPUDispatcher<commit_after>/*
 * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * For use for simulation and test purposes only
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. Neither the name of the copyright holder 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 HOLDER 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.
 *
 * Author: Brad Beckmann, Marc Orr
 */

#include "gpu-compute/dispatcher.hh"

#include "cpu/base.hh"
#include "debug/GPUDisp.hh"
#include "gpu-compute/cl_driver.hh"
#include "gpu-compute/cl_event.hh"
#include "gpu-compute/shader.hh"
#include "gpu-compute/wavefront.hh"
#include "mem/packet_access.hh"

GpuDispatcher *GpuDispatcher::instance = nullptr;

GpuDispatcher::GpuDispatcher(const Params *p)
    : DmaDevice(p), _masterId(p->system->getMasterId(name() + ".disp")),
      pioAddr(p->pio_addr), pioSize(4096), pioDelay(p->pio_latency),
      dispatchCount(0), dispatchActive(false), cpu(p->cpu),
      shader(p->shader_pointer), driver(p->cl_driver), tickEvent(this)
{
    shader->handshake(this);
    driver->handshake(this);

    ndRange.wg_disp_rem = false;
    ndRange.globalWgId = 0;

    schedule(&tickEvent, 0);

    // translation port for the dispatcher
    tlbPort = new TLBPort(csprintf("%s-port%d", name()), this);

    num_kernelLaunched
    .name(name() + ".num_kernel_launched")
    .desc("number of kernel launched")
    ;
}

GpuDispatcher *GpuDispatcherParams::create()
{
    GpuDispatcher *dispatcher = new GpuDispatcher(this);
    GpuDispatcher::setInstance(dispatcher);

    return GpuDispatcher::getInstance();
}

void
GpuDispatcher::serialize(CheckpointOut &cp) const
{
    Tick event_tick = 0;

    if (ndRange.wg_disp_rem)
        fatal("Checkpointing not supported during active workgroup execution");

    if (tickEvent.scheduled())
        event_tick = tickEvent.when();

    SERIALIZE_SCALAR(event_tick);

}

void
GpuDispatcher::unserialize(CheckpointIn &cp)
{
    Tick event_tick;

    if (tickEvent.scheduled())
        deschedule(&tickEvent);

    UNSERIALIZE_SCALAR(event_tick);

    if (event_tick)
        schedule(&tickEvent, event_tick);
}

AddrRangeList
GpuDispatcher::getAddrRanges() const
{
    AddrRangeList ranges;

    DPRINTF(GPUDisp, "dispatcher registering addr range at %#x size %#x\n",
            pioAddr, pioSize);

    ranges.push_back(RangeSize(pioAddr, pioSize));

    return ranges;
}

Tick
GpuDispatcher::read(PacketPtr pkt)
{
    assert(pkt->getAddr() >= pioAddr);
    assert(pkt->getAddr() < pioAddr + pioSize);

    int offset = pkt->getAddr() - pioAddr;
    pkt->allocate();

    DPRINTF(GPUDisp, " read register %#x size=%d\n", offset, pkt->getSize());

    if (offset < 8) {
        assert(!offset);
        assert(pkt->getSize() == 8);

        uint64_t retval = dispatchActive;
        pkt->set(retval);
    } else {
        offset -= 8;
        assert(offset + pkt->getSize() < sizeof(HsaQueueEntry));
        char *curTaskPtr = (char*)&curTask;

        memcpy(pkt->getPtr<const void*>(), curTaskPtr + offset, pkt->getSize());
    }

    pkt->makeAtomicResponse();

    return pioDelay;
}

Tick
GpuDispatcher::write(PacketPtr pkt)
{
    assert(pkt->getAddr() >= pioAddr);
    assert(pkt->getAddr() < pioAddr + pioSize);

    int offset = pkt->getAddr() - pioAddr;

#if TRACING_ON
    uint64_t data_val = 0;

    switch (pkt->getSize()) {
      case 1:
        data_val = pkt->get<uint8_t>();
        break;
      case 2:
        data_val = pkt->get<uint16_t>();
        break;
      case 4:
        data_val = pkt->get<uint32_t>();
        break;
      case 8:
        data_val = pkt->get<uint64_t>();
        break;
      default:
        DPRINTF(GPUDisp, "bad size %d\n", pkt->getSize());
    }

    DPRINTF(GPUDisp, "write register %#x value %#x size=%d\n", offset, data_val,
            pkt->getSize());
#endif
    if (!offset) {
        static int nextId = 0;

        // The depends field of the qstruct, which was previously unused, is
        // used to communicate with simulated application.
        if (curTask.depends) {
            HostState hs;
            shader->ReadMem((uint64_t)(curTask.depends), &hs,
                            sizeof(HostState), 0);

            // update event start time (in nano-seconds)
            uint64_t start = curTick() / 1000;

            shader->WriteMem((uint64_t)(&((_cl_event*)hs.event)->start),
                             &start, sizeof(uint64_t), 0);
        }

        // launch kernel
        ++num_kernelLaunched;

        NDRange *ndr = &(ndRangeMap[nextId]);
        // copy dispatch info
        ndr->q = curTask;

        // update the numDispTask polled by the runtime
        accessUserVar(cpu, (uint64_t)(curTask.numDispLeft), 0, 1);

        ndr->numWgTotal = 1;

        for (int i = 0; i < 3; ++i) {
            ndr->wgId[i] = 0;
            ndr->numWg[i] = divCeil(curTask.gdSize[i], curTask.wgSize[i]);
            ndr->numWgTotal *= ndr->numWg[i];
        }

        ndr->numWgCompleted = 0;
        ndr->globalWgId = 0;
        ndr->wg_disp_rem = true;
        ndr->execDone = false;
        ndr->addrToNotify = (volatile bool*)curTask.addrToNotify;
        ndr->numDispLeft = (volatile uint32_t*)curTask.numDispLeft;
        ndr->dispatchId = nextId;
        ndr->curCid = pkt->req->contextId();
        DPRINTF(GPUDisp, "launching kernel %d\n",nextId);
        execIds.push(nextId);
        ++nextId;

        dispatchActive = true;

        if (!tickEvent.scheduled()) {
            schedule(&tickEvent, curTick() + shader->ticks(1));
        }
    } else {
        // populate current task struct
        // first 64 bits are launch reg
        offset -= 8;
        assert(offset < sizeof(HsaQueueEntry));
        char *curTaskPtr = (char*)&curTask;
        memcpy(curTaskPtr + offset, pkt->getPtr<const void*>(), pkt->getSize());
    }

    pkt->makeAtomicResponse();

    return pioDelay;
}

BaseMasterPort&
GpuDispatcher::getMasterPort(const std::string &if_name, PortID idx)
{
    if (if_name == "translation_port") {
        return *tlbPort;
    }

    return DmaDevice::getMasterPort(if_name, idx);
}

void
GpuDispatcher::exec()
{
    int fail_count = 0;

    // There are potentially multiple outstanding kernel launches.
    // It is possible that the workgroups in a different kernel
    // can fit on the GPU even if another kernel's workgroups cannot
    DPRINTF(GPUDisp, "Launching %d Kernels\n", execIds.size());

    while (execIds.size() > fail_count) {
        int execId = execIds.front();

        while (ndRangeMap[execId].wg_disp_rem) {
            //update the thread context
            shader->updateContext(ndRangeMap[execId].curCid);

            // attempt to dispatch_workgroup
            if (!shader->dispatch_workgroups(&ndRangeMap[execId])) {
                // if we failed try the next kernel,
                // it may have smaller workgroups.
                // put it on the queue to rety latter
                DPRINTF(GPUDisp, "kernel %d failed to launch\n", execId);
                execIds.push(execId);
                ++fail_count;
                break;
            }
        }
        // let's try the next kernel_id
        execIds.pop();
    }

    DPRINTF(GPUDisp, "Returning %d Kernels\n", doneIds.size());

    if (doneIds.size() && cpu) {
        shader->hostWakeUp(cpu);
    }

    while (doneIds.size()) {
        // wakeup the CPU if any Kernels completed this cycle
        DPRINTF(GPUDisp, "WorkGroup %d completed\n", doneIds.front());
        doneIds.pop();
    }
}

void
GpuDispatcher::notifyWgCompl(Wavefront *w)
{
    int kern_id = w->kernId;
    DPRINTF(GPUDisp, "notify WgCompl %d\n",kern_id);
    assert(ndRangeMap[kern_id].dispatchId == kern_id);
    ndRangeMap[kern_id].numWgCompleted++;

    if (ndRangeMap[kern_id].numWgCompleted == ndRangeMap[kern_id].numWgTotal) {
        ndRangeMap[kern_id].execDone = true;
        doneIds.push(kern_id);

        if (ndRangeMap[kern_id].addrToNotify) {
            accessUserVar(cpu, (uint64_t)(ndRangeMap[kern_id].addrToNotify), 1,
                          0);
        }

        accessUserVar(cpu, (uint64_t)(ndRangeMap[kern_id].numDispLeft), 0, -1);

        // update event end time (in nano-seconds)
        if (ndRangeMap[kern_id].q.depends) {
            HostState *host_state = (HostState*)ndRangeMap[kern_id].q.depends;
            uint64_t event;
            shader->ReadMem((uint64_t)(&host_state->event), &event,
                            sizeof(uint64_t), 0);

            uint64_t end = curTick() / 1000;

            shader->WriteMem((uint64_t)(&((_cl_event*)event)->end), &end,
                             sizeof(uint64_t), 0);
        }
    }

    if (!tickEvent.scheduled()) {
        schedule(&tickEvent, curTick() + shader->ticks(1));
    }
}

void
GpuDispatcher::scheduleDispatch()
{
    if (!tickEvent.scheduled())
        schedule(&tickEvent, curTick() + shader->ticks(1));
}

void
GpuDispatcher::accessUserVar(BaseCPU *cpu, uint64_t addr, int val, int off)
{
    if (cpu) {
        if (off) {
            shader->AccessMem(addr, &val, sizeof(int), 0, MemCmd::ReadReq,
                              true);
            val += off;
        }

        shader->AccessMem(addr, &val, sizeof(int), 0, MemCmd::WriteReq, true);
    } else {
        panic("Cannot find host");
    }
}

GpuDispatcher::TickEvent::TickEvent(GpuDispatcher *_dispatcher)
    : Event(CPU_Tick_Pri), dispatcher(_dispatcher)
{
}

void
GpuDispatcher::TickEvent::process()
{
    dispatcher->exec();
}

const char*
GpuDispatcher::TickEvent::description() const
{
    return "GPU Dispatcher tick";
}

// helper functions for driver to retrieve GPU attributes
int
GpuDispatcher::getNumCUs()
{
    return shader->cuList.size();
}

int
GpuDispatcher::wfSize() const
{
    return shader->cuList[0]->wfSize();
}

void
GpuDispatcher::setFuncargsSize(int funcargs_size)
{
    shader->funcargs_size = funcargs_size;
}

uint32_t
GpuDispatcher::getStaticContextSize() const
{
    return shader->cuList[0]->wfList[0][0]->getStaticContextSize();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#ifndef BASE_RESOURCE_HPP
#define BASE_RESOURCE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <iostream>
#include <string>
#include<memory>

namespace rm
{
    ///////////////////////////////////////////////////////////
    /// \brief An abstract resource class
    ///
    /// This abstract base class needs to be inherited by a
    /// ManagedResource class. It contains three pure virtual
    /// functions that require a specific body of code for each
    /// resource type.
    ///
    ///////////////////////////////////////////////////////////
    class BaseResource;
    typedef std::shared_ptr<BaseResource> ResourcePtr;
    class BaseResource
	{

    public:
        BaseResource();
        virtual ~BaseResource();

        ///////////////////////////////////////////////////////////
        /// \brief Loads the resource from the file path
        ///
        /// \returns Whether or not the resource loaded successfully
        ///
        /// pure virtual function that has a specific load
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool load() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief unloads the resource
        ///
        /// \returns Whether or not the resource unloaded
        ///     successfully
        ///
        /// a pure virtual function that has a specific unload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool unload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Reloads the resource from the file path
        ///
        /// \returns Whether or not the resource reloaded
        ///     successfully
        ///
        /// a pure virtual function that has a specific reload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool reload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the alias of type string
        ///
        ///////////////////////////////////////////////////////////
        std::string getAlias() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the resource type string
        ///
        ///////////////////////////////////////////////////////////
        std::string getResourceType() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the file path string
        ///
        ///////////////////////////////////////////////////////////
        std::string getFilePath() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns true if resource is loaded
        ///
        ///////////////////////////////////////////////////////////
        bool isLoaded() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the memory usage
        ///
        ///////////////////////////////////////////////////////////
        virtual size_t getMemUsage() const = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Sets the alias member
        ///
        /// \param newalias The new Alias
        ///
        ///////////////////////////////////////////////////////////
        void setAlias(const std::string& newalias);

        ///////////////////////////////////////////////////////////
        /// \brief Sets the file path member
        ///
        ///////////////////////////////////////////////////////////
        void setFilePath(const std::string& newFilePath);

        ///////////////////////////////////////////////////////////
        /// \brief Sets the isLoaded member
        ///
        ///////////////////////////////////////////////////////////
        void setIsLoaded(bool isLoaded);

    private:
        std::string alias, type, filePath;
        bool isResourceLoaded;
	};
}

#endif //BASE_RESOURCE_HPP
<commit_msg>Changed baseResource members to protected<commit_after>////////////////////////////////////////////////////////////
//
// The MIT License (MIT)
//
// Copyright (c) 2014 stevehalliwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
////////////////////////////////////////////////////////////

#ifndef BASE_RESOURCE_HPP
#define BASE_RESOURCE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include <iostream>
#include <string>
#include<memory>

namespace rm
{
    ///////////////////////////////////////////////////////////
    /// \brief An abstract resource class
    ///
    /// This abstract base class needs to be inherited by a
    /// ManagedResource class. It contains three pure virtual
    /// functions that require a specific body of code for each
    /// resource type.
    ///
    ///////////////////////////////////////////////////////////
    class BaseResource;
    typedef std::shared_ptr<BaseResource> ResourcePtr;
    class BaseResource
	{

    public:
        BaseResource();
        virtual ~BaseResource();

        ///////////////////////////////////////////////////////////
        /// \brief Loads the resource from the file path
        ///
        /// \returns Whether or not the resource loaded successfully
        ///
        /// pure virtual function that has a specific load
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool load() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief unloads the resource
        ///
        /// \returns Whether or not the resource unloaded
        ///     successfully
        ///
        /// a pure virtual function that has a specific unload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool unload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Reloads the resource from the file path
        ///
        /// \returns Whether or not the resource reloaded
        ///     successfully
        ///
        /// a pure virtual function that has a specific reload
        /// function body for each resource type.
        ///
        ///////////////////////////////////////////////////////////
        virtual bool reload() = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the alias of type string
        ///
        ///////////////////////////////////////////////////////////
        std::string getAlias() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the resource type string
        ///
        ///////////////////////////////////////////////////////////
        std::string getResourceType() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the file path string
        ///
        ///////////////////////////////////////////////////////////
        std::string getFilePath() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns true if resource is loaded
        ///
        ///////////////////////////////////////////////////////////
        bool isLoaded() const;

        ///////////////////////////////////////////////////////////
        /// \brief Returns the memory usage
        ///
        ///////////////////////////////////////////////////////////
        virtual size_t getMemUsage() const = 0;

        ///////////////////////////////////////////////////////////
        /// \brief Sets the alias member
        ///
        /// \param newalias The new Alias
        ///
        ///////////////////////////////////////////////////////////
        void setAlias(const std::string& newalias);

        ///////////////////////////////////////////////////////////
        /// \brief Sets the file path member
        ///
        ///////////////////////////////////////////////////////////
        void setFilePath(const std::string& newFilePath);

        ///////////////////////////////////////////////////////////
        /// \brief Sets the isLoaded member
        ///
        ///////////////////////////////////////////////////////////
        void setIsLoaded(bool isLoaded);

    protected:
        std::string alias, type, filePath;
        bool isResourceLoaded;
	};
}

#endif //BASE_RESOURCE_HPP
<|endoftext|>


<commit_before>//
//  use_future.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-31.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_asio_use_future_hpp
#define fibio_asio_use_future_hpp

#include <memory>

#include <boost/config.hpp>
#include <boost/asio/detail/config.hpp>

namespace fibio {
namespace fibers {
namespace asio {

    namespace detail {
        /**
         * HACK: Dummy allocator for void, as std::allocator<void> doesn't have construct and destroy
         */
        struct dummy_void_allocator : std::allocator<void> {
            template<typename T>
            void construct(void *, T) const {}
            void destroy(void *) const {}
        };
    }

/**
 * class use_future_t
 *
 * Instance of the class can be used as completion handler for Boost.ASIO async_* call,
 * makes calls return a fibio::future.
 *
 * @see fibio::future
 */
template <typename Allocator = detail::dummy_void_allocator>
class use_future_t
{
public:
    typedef Allocator allocator_type;

    /// Construct using default-constructed allocator.
    BOOST_CONSTEXPR use_future_t() {}

    /// Construct using specified allocator.
    explicit use_future_t(Allocator const& allocator) : allocator_(allocator) {}

    /// Specify an alternate allocator.
    template <typename OtherAllocator>
    use_future_t<OtherAllocator> operator[](OtherAllocator const& allocator) const
    {
        return use_future_t<OtherAllocator>(allocator);
    }

    /// Obtain allocator.
    allocator_type get_allocator() const { return allocator_; }

private:
    Allocator allocator_;
};

/// The predefined instance of use_future_t can be used directly.
BOOST_CONSTEXPR_OR_CONST use_future_t<> use_future;

} // End of namespace asio
} // End of namespace fibers

namespace asio {

using fibers::asio::use_future;

} // End of namespace asio
} // End of namespace fibio

#include <fibio/fibers/asio/detail/use_future.hpp>

#endif
<commit_msg>Compiles on VS2017<commit_after>//
//  use_future.hpp
//  fibio
//
//  Created by Chen Xu on 14-3-31.
//  Copyright (c) 2014 0d0a.com. All rights reserved.
//

#ifndef fibio_asio_use_future_hpp
#define fibio_asio_use_future_hpp

#include <memory>

#include <boost/config.hpp>
#include <boost/asio/detail/config.hpp>

namespace fibio {
namespace fibers {
namespace asio {

    namespace detail {
        /**
         * HACK: Dummy allocator for void, as std::allocator<void> doesn't have construct and destroy
         */
        struct dummy_void_allocator : std::allocator<void> {
            template<typename T>
            void construct(void *, T) const {}
            void destroy(void *) const {}
        };
    }

/**
 * class use_future_t
 *
 * Instance of the class can be used as completion handler for Boost.ASIO async_* call,
 * makes calls return a fibio::future.
 *
 * @see fibio::future
 */
template <typename Allocator = detail::dummy_void_allocator>
class use_future_t
{
public:
    typedef Allocator allocator_type;

    /// Construct using default-constructed allocator.
    constexpr use_future_t() {}

    /// Construct using specified allocator.
    explicit use_future_t(Allocator const& allocator) : allocator_(allocator) {}

    /// Specify an alternate allocator.
    template <typename OtherAllocator>
    use_future_t<OtherAllocator> operator[](OtherAllocator const& allocator) const
    {
        return use_future_t<OtherAllocator>(allocator);
    }

    /// Obtain allocator.
    allocator_type get_allocator() const { return allocator_; }

private:
    const Allocator allocator_;
};

/// The predefined instance of use_future_t can be used directly.
#ifdef _MSC_VER
// Visual Studio still has bug about constexpr
__declspec(selectany) use_future_t<> use_future;
#else
constexpr use_future_t<> use_future;
#endif

} // End of namespace asio
} // End of namespace fibers

namespace asio {

using fibers::asio::use_future;

} // End of namespace asio
} // End of namespace fibio

#include <fibio/fibers/asio/detail/use_future.hpp>

#endif
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(BOOST_PP_EXPAND(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x), _ELIM)

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (6, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    0,                     /* constructor arity */ \
    ~full_name~,           /* full name */ \
    BOOST_PP_NIL,          /* methods */ \
    0                      /* augment constructor */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__augment_constructor    5

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_augment_constructor \
) \
  class p_cpp_name : public ::flusspferd::native_object_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_SEQ_FOR_EACH( \
          FLUSSPFERD_CD_METHOD, \
          p_cpp_name, \
          p_methods) \
        return proto; \
      } \
      BOOST_PP_EXPR_IF( \
        p_augment_constructor, \
        static void augment_constructor(::flusspferd::object &); \
      ) \
    }; \
  private: \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, element) \
  ::flusspferd::create_native_method( \
      proto, \
      BOOST_PP_STRINGIZE(element), \
      & p_cpp_name :: element); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<commit_msg>class_macros: add no_methods parameters for disabling method generation<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#include "native_object_base.hpp"
#endif
#include <boost/preprocessor.hpp>

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(BOOST_PP_EXPAND(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x), _ELIM)

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (7, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    0,                     /* constructor arity */ \
    ~full_name~,           /* full name */ \
    ~methods~,             /* methods */ \
    0,                     /* NO methods */ \
    0                      /* augment constructor */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__no_methods             5
#define FLUSSPFERD_CD_PARAM__augment_constructor    6

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_no_methods, \
  p_augment_constructor \
) \
  class p_cpp_name : public ::flusspferd::native_object_base { \
  public: \
    struct class_info : ::flusspferd::class_info { \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_IIF( \
          p_no_methods, \
          BOOST_PP_TUPLE_EAT(2), \
          FLUSSPFERD_CD_METHODS \
        ) (p_cpp_name, p_methods) \
        return proto; \
      } \
      BOOST_PP_EXPR_IF( \
        p_augment_constructor, \
        static void augment_constructor(::flusspferd::object &); \
      ) \
    }; \
  private: \
  /* */

#define FLUSSPFERD_CD_METHODS(p_cpp_name, p_methods) \
  BOOST_PP_SEQ_FOR_EACH( \
    FLUSSPFERD_CD_METHOD, \
    p_cpp_name, \
    p_methods) \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, element) \
  ::flusspferd::create_native_method( \
      proto, \
      BOOST_PP_STRINGIZE(element), \
      & p_cpp_name :: element); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <exception>
#include <locale>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// to define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class csv_error_info;

class csv_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit csv_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    csv_error(const csv_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // according to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    csv_error(csv_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    csv_error& operator=(const csv_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // according to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    csv_error& operator=(csv_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t row = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(row, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    csv_error_info info() const noexcept;
};

namespace detail {

// the number of letters of a non-negative integer in the decimal system
template <class T, T N, class = void>
struct Width;

template <class T, T N>
struct Width<T, N, std::enable_if_t<10 <= N>> :
    std::integral_constant<std::size_t, 1 + Width<T, N / 10>::value>
{};

template <class T, T N>
struct Width<T, N, std::enable_if_t<(0 <= N) && (N < 10)>> :
    std::integral_constant<std::size_t, 1>
{};

// prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != csv_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <class Tr>
std::nullptr_t getloc(std::basic_ostream<char, Tr>&)
{
    return nullptr;
}

template <class Ch, class Tr>
std::locale getloc(std::basic_ostream<Ch, Tr>& os)
{
    return os.getloc();
}

template <class Tr>
bool sputn(std::nullptr_t,
    std::basic_streambuf<char, Tr>* sb, const char* s, std::streamsize n)
{
    return sb->sputn(s, n) == n;
}

template <class Ch, class Tr>
bool sputn(const std::locale& loc,
    std::basic_streambuf<Ch, Tr>* sb, const char* s, std::streamsize n)
{
    const auto& facet = std::use_facet<std::ctype<Ch>>(loc);
    for (std::streamsize i = 0; i < n; ++i) {
        const auto c = s[i];
        if (sb->sputc(facet.widen(c)) == Tr::eof()) {
            return false;
        }
    }
    return true;
}

} // end namespace detail

class csv_error_info
{
    const csv_error* ex_;

public:
    explicit csv_error_info(const csv_error& ex) noexcept :
        ex_(&ex)
    {}

private:
    template <class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(
        std::basic_ostream<Ch, Tr>& os, const csv_error_info& i);
};

template <class Ch, class Tr>
std::basic_ostream<Ch, Tr>& operator<<(
    std::basic_ostream<Ch, Tr>& os, const csv_error_info& i)
{
    const auto w = i.ex_->what();
    if (const auto p = i.ex_->get_physical_position()) {
        char l[detail::Width<std::size_t, csv_error::npos>::value + 1];
        char c[sizeof(l)];
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));
        const auto l_len = detail::print_pos(l, p->first);
        const auto c_len = detail::print_pos(c, p->second);
        const auto n = w_len + l_len + c_len + 15/* =7+8. See below */;
        const auto loc = detail::getloc(os);
        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len, &loc]
            (auto* sb) {
                return detail::sputn(loc, sb, w, w_len)
                    && detail::sputn(loc, sb, "; line ", 7)
                    && detail::sputn(loc, sb, l, l_len)
                    && detail::sputn(loc, sb, " column ", 8)
                    && detail::sputn(loc, sb, c, c_len);
            });
    } else {
        return os << w;
    }
}

inline csv_error_info csv_error::info() const noexcept
{
    return csv_error_info(*this);
}

inline std::string to_string(const csv_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const csv_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<commit_msg>Use numeric_limits to count digits of integer types<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#ifndef FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7
#define FURFURYLIC_GUARD_E8F031F6_10D8_4585_9012_CFADC2F95BA7

#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <exception>
#include <limits>
#include <locale>
#include <memory>
#include <ostream>
#include <sstream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>

#include "formatted_output.hpp"

namespace furfurylic {
namespace commata {
namespace detail {

template <class T>
struct npos_impl
{
    constexpr static T npos = static_cast<T>(-1);
};

// to define this in a header, npos_impl is a template
template <class T>
constexpr T npos_impl<T>::npos;

} // end namespace detail

class csv_error_info;

class csv_error :
    public std::exception, public detail::npos_impl<std::size_t>
{
    std::shared_ptr<std::string> what_;
    std::pair<std::size_t, std::size_t> physical_position_;

public:
    template <class T,
        class = std::enable_if_t<std::is_constructible<std::string, T>::value>>
    explicit csv_error(T&& what_arg) :
        what_(std::make_shared<std::string>(std::forward<T>(what_arg))),
        physical_position_(npos, npos)
    {}

    // copy/move ctors and copy/move assignment ops are explicitly defined
    // so that they are noexcept

    csv_error(const csv_error& other) noexcept :
        std::exception(other),
        what_(other.what_),
        physical_position_(other.physical_position_)
        // according to C++14 20.3.2 (1), pair's copy ctor is noexcept
    {}

    csv_error(csv_error&& other) noexcept :
        std::exception(std::move(other)),
        what_(std::move(other.what_)),
        physical_position_(other.physical_position_)
        // ditto
    {}

    csv_error& operator=(const csv_error& other) noexcept
    {
        std::exception::operator=(other);
        what_ = other.what_;
        physical_position_ = other.physical_position_;
        // according to C++14 20.3.2 (1), pair's assignments are noexcept
        return *this;
    }

    csv_error& operator=(csv_error&& other) noexcept
    {
        std::exception::operator=(std::move(other));
        what_ = std::move(other.what_);
        physical_position_ = other.physical_position_;
        // ditto
        return *this;
    }

    const char* what() const noexcept override
    {
        return what_->c_str(); // std::string::c_str is noexcept
    }

    void set_physical_position(std::size_t row = npos, std::size_t col = npos)
    {
        physical_position_ = std::make_pair(row, col);
    }

    const std::pair<std::size_t, std::size_t>* get_physical_position() const
        noexcept
    {
        // std::make_pair<std::size_t, std::size_t> shall not throw exceptions
        return (physical_position_ != std::make_pair(npos, npos)) ?
            &physical_position_ : nullptr;
    }

    csv_error_info info() const noexcept;
};

namespace detail {

// prints a non-negative integer value in the decimal system
// into a sufficient-length buffer
template <std::size_t N>
std::streamsize print_pos(char (&s)[N], std::size_t pos)
{
    const auto len = (pos != csv_error::npos) ?
        std::snprintf(s, N, "%zu", pos + 1) :
        std::snprintf(s, N, "n/a");
    assert((len > 0 ) && (static_cast<std::size_t>(len) < N));
    return static_cast<std::streamsize>(len);
}

template <class Tr>
std::nullptr_t getloc(std::basic_ostream<char, Tr>&)
{
    return nullptr;
}

template <class Ch, class Tr>
std::locale getloc(std::basic_ostream<Ch, Tr>& os)
{
    return os.getloc();
}

template <class Tr>
bool sputn(std::nullptr_t,
    std::basic_streambuf<char, Tr>* sb, const char* s, std::streamsize n)
{
    return sb->sputn(s, n) == n;
}

template <class Ch, class Tr>
bool sputn(const std::locale& loc,
    std::basic_streambuf<Ch, Tr>* sb, const char* s, std::streamsize n)
{
    const auto& facet = std::use_facet<std::ctype<Ch>>(loc);
    for (std::streamsize i = 0; i < n; ++i) {
        const auto c = s[i];
        if (sb->sputc(facet.widen(c)) == Tr::eof()) {
            return false;
        }
    }
    return true;
}

} // end namespace detail

class csv_error_info
{
    const csv_error* ex_;

public:
    explicit csv_error_info(const csv_error& ex) noexcept :
        ex_(&ex)
    {}

private:
    template <class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(
        std::basic_ostream<Ch, Tr>& os, const csv_error_info& i);
};

template <class Ch, class Tr>
std::basic_ostream<Ch, Tr>& operator<<(
    std::basic_ostream<Ch, Tr>& os, const csv_error_info& i)
{
    const auto w = i.ex_->what();
    if (const auto p = i.ex_->get_physical_position()) {
        char l[std::numeric_limits<std::size_t>::digits10 + 2];
        char c[sizeof(l)];
        const auto w_len = static_cast<std::streamsize>(std::strlen(w));
        const auto l_len = detail::print_pos(l, p->first);
        const auto c_len = detail::print_pos(c, p->second);
        const auto n = w_len + l_len + c_len + 15/* =7+8. See below */;
        const auto loc = detail::getloc(os);
        return detail::formatted_output(os, n,
            [w, w_len, l = &l[0], l_len, c = &c[0], c_len, &loc]
            (auto* sb) {
                return detail::sputn(loc, sb, w, w_len)
                    && detail::sputn(loc, sb, "; line ", 7)
                    && detail::sputn(loc, sb, l, l_len)
                    && detail::sputn(loc, sb, " column ", 8)
                    && detail::sputn(loc, sb, c, c_len);
            });
    } else {
        return os << w;
    }
}

inline csv_error_info csv_error::info() const noexcept
{
    return csv_error_info(*this);
}

inline std::string to_string(const csv_error_info& i)
{
    std::ostringstream s;
    s << i;
    return s.str();
}

inline std::wstring to_wstring(const csv_error_info& i)
{
    std::wostringstream s;
    s << i;
    return s.str();
}

}}

#endif
<|endoftext|>


<commit_before>/******************************************************************************
 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
 *                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
 *                                                                             *
 * This program is free software; you can redistribute it and/or modify it     *
 * under the terms of the GNU General Public License as published by the Free  *
 * Software Foundation; either version 2 of the License, or (at your option)   *
 * any later version.                                                          *
 *                                                                             *
 * This program is distributed in the hope that it will be useful, but WITHOUT *
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
 * more details.                                                               *
 *                                                                             *
 * You should have received a copy of the GNU General Public License along     *
 * with this program; if not, write to the Free Software Foundation, Inc., 51  *
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
 *******************************************************************************
 *                            SOFA :: Applications                             *
 *                                                                             *
 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
 *                                                                             *
 * Contact information: contact@sofa-framework.org                             *
 ******************************************************************************/
#include <sofa/simulation/tree/TreeSimulation.h>
#include <sofa/simulation/tree/GNode.h>
#include <sofa/component/misc/ReadState.h>
#include <sofa/component/misc/WriteState.h>
#include <sofa/component/misc/CompareState.h>
#include <sofa/component/misc/ReadTopology.h>
#include <sofa/component/misc/WriteTopology.h>
#include <sofa/component/misc/CompareTopology.h>
#include <sofa/component/init.h>
#include <sofa/helper/system/thread/TimeoutWatchdog.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/helper/system/SetDirectory.h>
#include <sofa/helper/ArgumentParser.h>
#include <sofa/helper/Factory.h>
#include <sofa/helper/BackTrace.h>
#include <iostream>
#include <fstream>
#include <ctime>

using sofa::helper::system::DataRepository;
using sofa::helper::system::SetDirectory;
using sofa::simulation::tree::GNode;

// ---------------------------------------------------------------------
// ---
// ---------------------------------------------------------------------

void apply(const std::string& directory, std::vector<std::string>& files,
        unsigned int iterations, bool reinit, bool useTopology)
{

    sofa::component::init(); // ensures all components are initialized, also introduce a dependency to all libraries, avoiding problems with -Wl,--as-needed flag

    sofa::simulation::Simulation* simulation = sofa::simulation::getSimulation();

    //Launch the comparison for each scenes
    for (unsigned int i = 0; i < files.size(); ++i)
    {

        const std::string& currentFile = files[i];
        GNode* groot = dynamic_cast<GNode*> (simulation->load(currentFile.c_str()));
        if (groot == NULL)
        {
            std::cerr << "CANNOT open " << currentFile << " !" << std::endl;
            continue;
        }

        simulation->init(groot);

        //Filename where the simulation of the current scene will be saved (in Sofa/applications/projects/sofaVerification/simulation/)
        std::string refFile;
        if(directory.empty())
        {
            refFile += SetDirectory::GetParentDir(DataRepository.getFirstPath().c_str());
            refFile += "/applications/projects/sofaVerification/simulation/";
            refFile += SetDirectory::GetFileName(currentFile.c_str());
        }
        else
        {
            refFile += directory;
            refFile += '/';
            refFile += SetDirectory::GetFileName(currentFile.c_str());
        }

        //If we initialize the system, we add only WriteState components, to store the reference states
        if (reinit)
        {
            if (useTopology)
            {
                sofa::component::misc::WriteTopologyCreator writeVisitor(sofa::core::ExecParams::defaultInstance());

                writeVisitor.setCreateInMapping(true);
                writeVisitor.setSceneName(refFile);
                writeVisitor.execute(groot);

                sofa::component::misc::WriteTopologyActivator v_write(true,sofa::core::ExecParams::defaultInstance());
                v_write.execute(groot);
            }
            else
            {
                sofa::component::misc::WriteStateCreator writeVisitor(sofa::core::ExecParams::defaultInstance());

                writeVisitor.setCreateInMapping(true);
                writeVisitor.setSceneName(refFile);
                writeVisitor.execute(groot);

                sofa::component::misc::WriteStateActivator v_write(true,sofa::core::ExecParams::defaultInstance());
                v_write.execute(groot);
            }

        }
        else
        {
            if (useTopology)
            {
                //We add CompareTopology components: as it derives from the ReadTopology, we use the ReadTopologyActivator to enable them.
                sofa::component::misc::CompareTopologyCreator compareVisitor(sofa::core::ExecParams::defaultInstance());
                compareVisitor.setCreateInMapping(true);
                compareVisitor.setSceneName(refFile);
                compareVisitor.execute(groot);

                sofa::component::misc::ReadTopologyActivator v_read(sofa::core::ExecParams::defaultInstance(),true);
                v_read.execute(groot);
            }
            else
            {
                //We add CompareState components: as it derives from the ReadState, we use the ReadStateActivator to enable them.
                sofa::component::misc::CompareStateCreator compareVisitor(sofa::core::ExecParams::defaultInstance());
                compareVisitor.setCreateInMapping(true);
                compareVisitor.setSceneName(refFile);
                compareVisitor.execute(groot);

                sofa::component::misc::ReadStateActivator v_read(true,sofa::core::ExecParams::defaultInstance());
                v_read.execute(groot);
            }
        }

        //Do as many iterations as specified in entry of the program. At each step, the compare state will compare the computed states to the recorded states
        std::cout << "Computing " << iterations << " for " << currentFile << std::endl;

        //Save the initial time
        clock_t curtime = clock();
        for (unsigned int i = 0; i < iterations; i++)
        {
            simulation->animate(groot);
        }
        double t = static_cast<double>(clock() - curtime) / CLOCKS_PER_SEC;

        std::cout << "ITERATIONS " << iterations << " TIME " << t << " seconds ";

        //We read the final error: the summation of all the error made at each time step
        if (!reinit)
        {
            if (useTopology)
            {
                sofa::component::misc::CompareTopologyResult result(sofa::core::ExecParams::defaultInstance());
                result.execute(groot);
                std::cout << "ERROR " << result.getTotalError() << ' ';

                const std::vector<unsigned int>& listResult = result.getErrors();
                if (listResult.size() != 5)
                {
                    std::cerr
                            << "ERROR while reading detail of errors by topological element."
                                    << std::endl;
                    break;
                }

                std::cout
                        << "ERROR by element type "
                                << " EDGES "      << static_cast<double>(listResult[0])
                                / result.getNumCompareTopology()
                                << " TRIANGLES "  << static_cast<double>(listResult[1])
                                / result.getNumCompareTopology()
                                << " QUADS "      << static_cast<double>(listResult[2])
                                / result.getNumCompareTopology()
                                << " TETRAHEDRA " << static_cast<double>(listResult[3])
                                / result.getNumCompareTopology()
                                << " HEXAHEDRA "  << static_cast<double>(listResult[4])
                                / result.getNumCompareTopology();
            }
            else
            {
                sofa::component::misc::CompareStateResult result(sofa::core::ExecParams::defaultInstance());
                result.execute(groot);
                std::cout
                        << "ERROR " << result.getTotalError() << " ERRORBYDOF "
                                << static_cast<double>(result.getErrorByDof())
                                / result.getNumCompareState() << std::endl;
            }
        }
        std::cout << std::endl;

        //Clear and prepare for next scene
        simulation->unload(groot);
        delete groot;
    }
}

int main(int argc, char** argv)
{
    sofa::helper::BackTrace::autodump();

    std::string directory;
    std::vector<std::string> fileArguments;
    std::vector<std::string> sceneFiles;
    unsigned int iterations = 100;
    bool reinit = false;
    bool topology = false;
    unsigned lifetime = 0;

    sofa::simulation::setSimulation(new sofa::simulation::tree::TreeSimulation());

    sofa::helper::parse(
        &fileArguments,
        "This is SOFA verification. "
        "To use it, specify in the command line the scene files you want to test, "
        "or a \".ini\" file containing the path to the scenes.")
    .option(&reinit, 'r', "reinit", "Recreate the references state files")
    .option(&iterations, 'i', "iteration", "Number of iterations for testing")
    .option(&directory, 'd', "directory", "The directory for reference files")
    .option(&topology, 't', "topology", "Specific mode to run tests on topology")
    .option(&lifetime, 'l', "lifetime", "Maximum execution time in seconds (default: 0 -> no limit")
    (argc, argv);

#ifdef SOFA_HAVE_BOOST
    sofa::helper::system::thread::TimeoutWatchdog watchdog;
    if(lifetime > 0)
    {
        watchdog.start(lifetime);
    }
#endif

    for(size_t i = 0; i < fileArguments.size(); ++i)
    {
        std::string currentFile = fileArguments[i];
        DataRepository.findFile(currentFile);

        if (currentFile.compare(currentFile.size() - 4, 4, ".ini") == 0)
        {
            //This is an ini file: get the list of scenes to test
            std::ifstream iniFileStream(currentFile.c_str());
            while (!iniFileStream.eof())
            {
                std::string line;
                std::string currentScene;
                // extracting the filename line by line because each line can contain
                // extra data, ignored by this program but that may be useful for
                // other tools.
                getline(iniFileStream, line);
                std::istringstream lineStream(line);
                lineStream >> currentScene;
                DataRepository.findFile(currentScene);
                sceneFiles.push_back(currentScene);
            }
        }
        else
        {
            // this is supposed to be a scene file
            sceneFiles.push_back(currentFile);
        }
    }

    std::cout
            << "*********************************************************************\n"
                    << "******* Arguments ***************************************************\n"
                    << "iterations: "  << iterations << '\n'
                    << "reinit: "      << reinit     << '\n'
                    << "useTopology: " << topology   << '\n'
                    << "files : "                    << '\n';
    for(size_t i = 0; i < sceneFiles.size(); ++i)
    {
        std::cout << "  " << sceneFiles[i] << '\n';
    }

    apply(directory, sceneFiles, iterations, reinit, topology);

    return 0;
}
<commit_msg>r9279/sofa-dev : UPDATE : add loading plugin possibility for sofaVerification using -p(plugin) option <commit_after>/******************************************************************************
 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 4      *
 *                (c) 2006-2009 MGH, INRIA, USTL, UJF, CNRS                    *
 *                                                                             *
 * This program is free software; you can redistribute it and/or modify it     *
 * under the terms of the GNU General Public License as published by the Free  *
 * Software Foundation; either version 2 of the License, or (at your option)   *
 * any later version.                                                          *
 *                                                                             *
 * This program is distributed in the hope that it will be useful, but WITHOUT *
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
 * more details.                                                               *
 *                                                                             *
 * You should have received a copy of the GNU General Public License along     *
 * with this program; if not, write to the Free Software Foundation, Inc., 51  *
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
 *******************************************************************************
 *                            SOFA :: Applications                             *
 *                                                                             *
 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
 *                                                                             *
 * Contact information: contact@sofa-framework.org                             *
 ******************************************************************************/
#include <sofa/simulation/tree/TreeSimulation.h>
#include <sofa/simulation/tree/GNode.h>
#include <sofa/component/misc/ReadState.h>
#include <sofa/component/misc/WriteState.h>
#include <sofa/component/misc/CompareState.h>
#include <sofa/component/misc/ReadTopology.h>
#include <sofa/component/misc/WriteTopology.h>
#include <sofa/component/misc/CompareTopology.h>
#include <sofa/component/init.h>
#include <sofa/helper/system/thread/TimeoutWatchdog.h>
#include <sofa/helper/system/FileRepository.h>
#include <sofa/helper/system/SetDirectory.h>
#include <sofa/helper/ArgumentParser.h>
#include <sofa/helper/Factory.h>
#include <sofa/helper/BackTrace.h>
#include <iostream>
#include <fstream>
#include <ctime>

using sofa::helper::system::DataRepository;
using sofa::helper::system::SetDirectory;
using sofa::simulation::tree::GNode;

#ifndef WIN32
#include <dlfcn.h>
bool loadPlugin(const char* filename)
{
    void *handle;
    handle=dlopen(filename, RTLD_LAZY);
    if (!handle)
    {
        std::cerr<<"Error loading plugin "<<filename<<": "<<dlerror()<<std::endl;
        return false;
    }
    std::cerr<<"Plugin "<<filename<<" loaded."<<std::endl;
    return true;
}
#else
bool loadPlugin(const char* filename)
{
    HINSTANCE DLLHandle;
    DLLHandle = LoadLibraryA(filename); //warning: issue between unicode and ansi encoding on Visual c++ -> force to ansi-> dirty!
    if (DLLHandle == NULL)
    {
        std::cerr<<"Error loading plugin "<<filename<<std::endl;
        return false;
    }
    std::cerr<<"Plugin "<<filename<<" loaded."<<std::endl;
    return true;
}
#endif

// ---------------------------------------------------------------------
// ---
// ---------------------------------------------------------------------

void apply(const std::string& directory, std::vector<std::string>& files,
        unsigned int iterations, bool reinit, bool useTopology)
{

    sofa::component::init(); // ensures all components are initialized, also introduce a dependency to all libraries, avoiding problems with -Wl,--as-needed flag

    sofa::simulation::Simulation* simulation = sofa::simulation::getSimulation();

    //Launch the comparison for each scenes
    for (unsigned int i = 0; i < files.size(); ++i)
    {

        const std::string& currentFile = files[i];
        GNode* groot = dynamic_cast<GNode*> (simulation->load(currentFile.c_str()));
        if (groot == NULL)
        {
            std::cerr << "CANNOT open " << currentFile << " !" << std::endl;
            continue;
        }

        simulation->init(groot);

        //Filename where the simulation of the current scene will be saved (in Sofa/applications/projects/sofaVerification/simulation/)
        std::string refFile;
        if(directory.empty())
        {
            refFile += SetDirectory::GetParentDir(DataRepository.getFirstPath().c_str());
            refFile += "/applications/projects/sofaVerification/simulation/";
            refFile += SetDirectory::GetFileName(currentFile.c_str());
        }
        else
        {
            refFile += directory;
            refFile += '/';
            refFile += SetDirectory::GetFileName(currentFile.c_str());
        }

        //If we initialize the system, we add only WriteState components, to store the reference states
        if (reinit)
        {
            if (useTopology)
            {
                sofa::component::misc::WriteTopologyCreator writeVisitor(sofa::core::ExecParams::defaultInstance());

                writeVisitor.setCreateInMapping(true);
                writeVisitor.setSceneName(refFile);
                writeVisitor.execute(groot);

                sofa::component::misc::WriteTopologyActivator v_write(true,sofa::core::ExecParams::defaultInstance());
                v_write.execute(groot);
            }
            else
            {
                sofa::component::misc::WriteStateCreator writeVisitor(sofa::core::ExecParams::defaultInstance());

                writeVisitor.setCreateInMapping(true);
                writeVisitor.setSceneName(refFile);
                writeVisitor.execute(groot);

                sofa::component::misc::WriteStateActivator v_write(true,sofa::core::ExecParams::defaultInstance());
                v_write.execute(groot);
            }

        }
        else
        {
            if (useTopology)
            {
                //We add CompareTopology components: as it derives from the ReadTopology, we use the ReadTopologyActivator to enable them.
                sofa::component::misc::CompareTopologyCreator compareVisitor(sofa::core::ExecParams::defaultInstance());
                compareVisitor.setCreateInMapping(true);
                compareVisitor.setSceneName(refFile);
                compareVisitor.execute(groot);

                sofa::component::misc::ReadTopologyActivator v_read(sofa::core::ExecParams::defaultInstance(),true);
                v_read.execute(groot);
            }
            else
            {
                //We add CompareState components: as it derives from the ReadState, we use the ReadStateActivator to enable them.
                sofa::component::misc::CompareStateCreator compareVisitor(sofa::core::ExecParams::defaultInstance());
                compareVisitor.setCreateInMapping(true);
                compareVisitor.setSceneName(refFile);
                compareVisitor.execute(groot);

                sofa::component::misc::ReadStateActivator v_read(true,sofa::core::ExecParams::defaultInstance());
                v_read.execute(groot);
            }
        }

        //Do as many iterations as specified in entry of the program. At each step, the compare state will compare the computed states to the recorded states
        std::cout << "Computing " << iterations << " for " << currentFile << std::endl;

        //Save the initial time
        clock_t curtime = clock();
        for (unsigned int i = 0; i < iterations; i++)
        {
            simulation->animate(groot);
        }
        double t = static_cast<double>(clock() - curtime) / CLOCKS_PER_SEC;

        std::cout << "ITERATIONS " << iterations << " TIME " << t << " seconds ";

        //We read the final error: the summation of all the error made at each time step
        if (!reinit)
        {
            if (useTopology)
            {
                sofa::component::misc::CompareTopologyResult result(sofa::core::ExecParams::defaultInstance());
                result.execute(groot);
                std::cout << "ERROR " << result.getTotalError() << ' ';

                const std::vector<unsigned int>& listResult = result.getErrors();
                if (listResult.size() != 5)
                {
                    std::cerr
                            << "ERROR while reading detail of errors by topological element."
                                    << std::endl;
                    break;
                }

                std::cout
                        << "ERROR by element type "
                                << " EDGES "      << static_cast<double>(listResult[0])
                                / result.getNumCompareTopology()
                                << " TRIANGLES "  << static_cast<double>(listResult[1])
                                / result.getNumCompareTopology()
                                << " QUADS "      << static_cast<double>(listResult[2])
                                / result.getNumCompareTopology()
                                << " TETRAHEDRA " << static_cast<double>(listResult[3])
                                / result.getNumCompareTopology()
                                << " HEXAHEDRA "  << static_cast<double>(listResult[4])
                                / result.getNumCompareTopology();
            }
            else
            {
                sofa::component::misc::CompareStateResult result(sofa::core::ExecParams::defaultInstance());
                result.execute(groot);
                std::cout
                        << "ERROR " << result.getTotalError() << " ERRORBYDOF "
                                << static_cast<double>(result.getErrorByDof())
                                / result.getNumCompareState() << std::endl;
            }
        }
        std::cout << std::endl;

        //Clear and prepare for next scene
        simulation->unload(groot);
        delete groot;
    }
}

int main(int argc, char** argv)
{
    sofa::helper::BackTrace::autodump();

    std::string directory;
    std::vector<std::string> fileArguments;
    std::vector<std::string> sceneFiles;
    std::vector<std::string> plugins;
    unsigned int iterations = 100;
    bool reinit = false;
    bool topology = false;
    unsigned lifetime = 0;

    sofa::simulation::setSimulation(new sofa::simulation::tree::TreeSimulation());

    sofa::helper::parse(
        &fileArguments,
        "This is SOFA verification. "
        "To use it, specify in the command line the scene files you want to test, "
        "or a \".ini\" file containing the path to the scenes.")
    .option(&reinit, 'r', "reinit", "Recreate the references state files")
    .option(&iterations, 'i', "iteration", "Number of iterations for testing")
    .option(&directory, 'd', "directory", "The directory for reference files")
    .option(&plugins,'p',"plugin","load given plugins")
    .option(&topology, 't', "topology", "Specific mode to run tests on topology")
    .option(&lifetime, 'l', "lifetime", "Maximum execution time in seconds (default: 0 -> no limit")
    (argc, argv);

#ifdef SOFA_HAVE_BOOST
    sofa::helper::system::thread::TimeoutWatchdog watchdog;
    if(lifetime > 0)
    {
        watchdog.start(lifetime);
    }
#endif

    for (unsigned int i=0; i<plugins.size(); i++)
        loadPlugin(plugins[i].c_str());

    for(size_t i = 0; i < fileArguments.size(); ++i)
    {
        std::string currentFile = fileArguments[i];
        DataRepository.findFile(currentFile);

        if (currentFile.compare(currentFile.size() - 4, 4, ".ini") == 0)
        {
            //This is an ini file: get the list of scenes to test
            std::ifstream iniFileStream(currentFile.c_str());
            while (!iniFileStream.eof())
            {
                std::string line;
                std::string currentScene;
                // extracting the filename line by line because each line can contain
                // extra data, ignored by this program but that may be useful for
                // other tools.
                getline(iniFileStream, line);
                std::istringstream lineStream(line);
                lineStream >> currentScene;
                DataRepository.findFile(currentScene);
                sceneFiles.push_back(currentScene);
            }
        }
        else
        {
            // this is supposed to be a scene file
            sceneFiles.push_back(currentFile);
        }
    }

    std::cout
            << "*********************************************************************\n"
                    << "******* Arguments ***************************************************\n"
                    << "iterations: "  << iterations << '\n'
                    << "reinit: "      << reinit     << '\n'
                    << "useTopology: " << topology   << '\n'
                    << "files : "                    << '\n';
    for(size_t i = 0; i < sceneFiles.size(); ++i)
    {
        std::cout << "  " << sceneFiles[i] << '\n';
    }

    apply(directory, sceneFiles, iterations, reinit, topology);

    return 0;
}
<|endoftext|>