<commit_before>/*! \file main.cpp
 *  \brief Program to run the grid code. */

#ifdef MPI_CHOLLA
#include <mpi.h>
#include "mpi_routines.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "grid3D.h"
#include "io.h"
#include "error_handling.h"

#define OUTPUT
//#define CPU_TIME

int main(int argc, char *argv[])
{
  // timing variables
  double start_total, stop_total, start_step, stop_step;
  #ifdef CPU_TIME
  double stop_init, init_min, init_max, init_avg;
  double start_bound, stop_bound, bound_min, bound_max, bound_avg;
  double start_hydro, stop_hydro, hydro_min, hydro_max, hydro_avg;
  double init, bound, hydro;
  init = bound = hydro = 0;
  #endif //CPU_TIME

  // start the total time
  start_total = get_time();

  /* Initialize MPI communication */
  #ifdef MPI_CHOLLA
  InitializeChollaMPI(&argc, &argv);
  #endif /*MPI_CHOLLA*/

  Real dti = 0; // inverse time step, 1.0 / dt

  // input parameter variables
  char *param_file;
  struct parameters P;
  int nfile = 0; // number of output files
  Real outtime = 0; // current output time

  // read in command line arguments
  if (argc != 2)
  {
    chprintf("usage: %s <parameter_file>\n", argv[0]);
    chexit(-1);
  } else {
    param_file = argv[1];
  }

  // create the grid
  Grid3D G;

  // read in the parameters
  parse_params (param_file, &P);
  // and output to screen
  chprintf ("Parameter values:  nx = %d, ny = %d, nz = %d, tout = %f, init = %s, boundaries = %d %d %d %d %d %d\n",
    P.nx, P.ny, P.nz, P.tout, P.init, P.xl_bcnd, P.xu_bcnd, P.yl_bcnd, P.yu_bcnd, P.zl_bcnd, P.zu_bcnd);
  chprintf ("Output directory:  %s\n", P.outdir);

  // initialize the grid
  G.Initialize(&P);
  chprintf("Local number of grid cells: %d %d %d %d\n", G.H.nx_real, G.H.ny_real, G.H.nz_real, G.H.n_cells);

  // Set initial conditions and calculate first dt
  chprintf("Setting initial conditions...\n");
  G.Set_Initial_Conditions(P);
  chprintf("Initial conditions set.\n");
  // set main variables for Read_Grid inital conditions
  if (strcmp(P.init, "Read_Grid") == 0) {
    dti = C_cfl / G.H.dt;
    outtime += G.H.t;
    nfile = P.nfile*P.nfull;
  }

  #ifdef CPU_TIME
  G.Timer.Initialize();
  #endif

  #ifdef GRAVITY
  G.Initialize_Gravity(&P);
  #endif

  #ifdef PARTICLES
  G.Initialize_Particles(&P);
  #endif

  #ifdef GRAVITY
  G.Compute_Gravitational_Potential( &P);
  #endif

  // set boundary conditions (assign appropriate values to ghost cells)
  chprintf("Setting boundary conditions...\n");
  G.Set_Boundary_Conditions_All(P);
  chprintf("Boundary conditions set.\n");

  #ifdef PARTICLES
  G.Get_Particles_Accelration();
  #endif

  chprintf("Dimensions of each cell: dx = %f dy = %f dz = %f\n", G.H.dx, G.H.dy, G.H.dz);
  chprintf("Ratio of specific heats gamma = %f\n",gama);
  chprintf("Nstep = %d  Timestep = %f  Simulation time = %f\n", G.H.n_step, G.H.dt, G.H.t);

  #ifdef OUTPUT
  if (strcmp(P.init, "Read_Grid") != 0) {
  // write the initial conditions to file
  chprintf("Writing initial conditions to file...\n");
  WriteData(G, P, nfile);
  }
  // add one to the output file count
  nfile++;
  #endif //OUTPUT
  // increment the next output time
  outtime += P.outstep;

  #ifdef CPU_TIME
  stop_init = get_time();
  init = stop_init - start_total;
  #ifdef MPI_CHOLLA
  init_min = ReduceRealMin(init);
  init_max = ReduceRealMax(init);
  init_avg = ReduceRealAvg(init);
  chprintf("Init  min: %9.4f  max: %9.4f  avg: %9.4f\n", init_min, init_max, init_avg);
  #else
  printf("Init %9.4f\n", init);
  #endif //MPI_CHOLLA
  #endif //CPU_TIME

  // Evolve the grid, one timestep at a time
  chprintf("Starting calculations.\n");
  while (G.H.t < P.tout)
  //while (G.H.n_step < 1)
  {
    chprintf("n_step: %d \n", G.H.n_step + 1 );
    // get the start time
    start_step = get_time();

    // calculate the timestep
    G.set_dt(dti);

    #ifdef GRAVITY
    G.set_dt_Gravity();
    #endif

    if (G.H.t + G.H.dt > outtime)
    {
      G.H.dt = outtime - G.H.t;
    }

    #ifdef MPI_CHOLLA
    G.H.dt = ReduceRealMin(G.H.dt);
    #endif

    #ifdef PARTICLES
    //Advance the particles KDK( first step )
    G.Advance_Particles( 1 );
    #endif

    // Advance the grid by one timestep
    dti = G.Update_Hydro_Grid();

    // update the simulation time ( t += dt )
    G.Update_Time();

    #ifdef GRAVITY
    //Compute Gravitational potential for next step
    G.Compute_Gravitational_Potential( &P);
    #endif

    // add one to the timestep count
    G.H.n_step++;

    // set boundary conditions for next time step
    G.Set_Boundary_Conditions_All(P);

    #ifdef PARTICLES
    //Advance the particles KDK( second step )
    G.Advance_Particles( 2 );
    #endif

    #ifdef CPU_TIME
    G.Timer.Print_Times();
    #endif

    // get the time to compute the total timestep
    stop_step = get_time();
    stop_total = get_time();
    G.H.t_wall = stop_total-start_total;
    #ifdef MPI_CHOLLA
    G.H.t_wall = ReduceRealMax(G.H.t_wall);
    #endif
    chprintf("n_step: %d   sim time: %10.7f   sim timestep: %7.4e  timestep time = %9.3f ms   total time = %9.4f s\n\n",
      G.H.n_step, G.H.t, G.H.dt, (stop_step-start_step)*1000, G.H.t_wall);

    if (G.H.t == outtime)
    {
      #ifdef OUTPUT
      /*output the grid data*/
      WriteData(G, P, nfile);
      // add one to the output file count
      nfile++;
      #endif //OUTPUT
      // update to the next output time
      outtime += P.outstep;
    }
/*
    // check for failures
    for (int i=G.H.n_ghost; i<G.H.nx-G.H.n_ghost; i++) {
      for (int j=G.H.n_ghost; j<G.H.ny-G.H.n_ghost; j++) {
        for (int k=G.H.n_ghost; k<G.H.nz-G.H.n_ghost; k++) {
          int id = i + j*G.H.nx + k*G.H.nx*G.H.ny;
          if (G.C.density[id] < 0.0 || G.C.density[id] != G.C.density[id]) {
            printf("Failure in cell %d %d %d. Density %e\n", i, j, k, G.C.density[id]);
            #ifdef MPI_CHOLLA
            MPI_Finalize();
            chexit(-1);
            #endif
            exit(0);
          }
        }
      }
    }
*/

  } /*end loop over timesteps*/

  // free the grid
  G.Reset();

  #ifdef MPI_CHOLLA
  MPI_Finalize();
  #endif /*MPI_CHOLLA*/

  return 0;

}
<commit_msg>commented unnecessary min_dt<commit_after>/*! \file main.cpp
 *  \brief Program to run the grid code. */

#ifdef MPI_CHOLLA
#include <mpi.h>
#include "mpi_routines.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "global.h"
#include "grid3D.h"
#include "io.h"
#include "error_handling.h"

#define OUTPUT
//#define CPU_TIME

int main(int argc, char *argv[])
{
  // timing variables
  double start_total, stop_total, start_step, stop_step;
  #ifdef CPU_TIME
  double stop_init, init_min, init_max, init_avg;
  double start_bound, stop_bound, bound_min, bound_max, bound_avg;
  double start_hydro, stop_hydro, hydro_min, hydro_max, hydro_avg;
  double init, bound, hydro;
  init = bound = hydro = 0;
  #endif //CPU_TIME

  // start the total time
  start_total = get_time();

  /* Initialize MPI communication */
  #ifdef MPI_CHOLLA
  InitializeChollaMPI(&argc, &argv);
  #endif /*MPI_CHOLLA*/

  Real dti = 0; // inverse time step, 1.0 / dt

  // input parameter variables
  char *param_file;
  struct parameters P;
  int nfile = 0; // number of output files
  Real outtime = 0; // current output time

  // read in command line arguments
  if (argc != 2)
  {
    chprintf("usage: %s <parameter_file>\n", argv[0]);
    chexit(-1);
  } else {
    param_file = argv[1];
  }

  // create the grid
  Grid3D G;

  // read in the parameters
  parse_params (param_file, &P);
  // and output to screen
  chprintf ("Parameter values:  nx = %d, ny = %d, nz = %d, tout = %f, init = %s, boundaries = %d %d %d %d %d %d\n",
    P.nx, P.ny, P.nz, P.tout, P.init, P.xl_bcnd, P.xu_bcnd, P.yl_bcnd, P.yu_bcnd, P.zl_bcnd, P.zu_bcnd);
  chprintf ("Output directory:  %s\n", P.outdir);

  // initialize the grid
  G.Initialize(&P);
  chprintf("Local number of grid cells: %d %d %d %d\n", G.H.nx_real, G.H.ny_real, G.H.nz_real, G.H.n_cells);

  // Set initial conditions and calculate first dt
  chprintf("Setting initial conditions...\n");
  G.Set_Initial_Conditions(P);
  chprintf("Initial conditions set.\n");
  // set main variables for Read_Grid inital conditions
  if (strcmp(P.init, "Read_Grid") == 0) {
    dti = C_cfl / G.H.dt;
    outtime += G.H.t;
    nfile = P.nfile*P.nfull;
  }

  #ifdef CPU_TIME
  G.Timer.Initialize();
  #endif

  #ifdef GRAVITY
  G.Initialize_Gravity(&P);
  #endif

  #ifdef PARTICLES
  G.Initialize_Particles(&P);
  #endif

  #ifdef GRAVITY
  G.Compute_Gravitational_Potential( &P);
  #endif

  // set boundary conditions (assign appropriate values to ghost cells)
  chprintf("Setting boundary conditions...\n");
  G.Set_Boundary_Conditions_All(P);
  chprintf("Boundary conditions set.\n");

  #ifdef PARTICLES
  G.Get_Particles_Accelration();
  #endif

  chprintf("Dimensions of each cell: dx = %f dy = %f dz = %f\n", G.H.dx, G.H.dy, G.H.dz);
  chprintf("Ratio of specific heats gamma = %f\n",gama);
  chprintf("Nstep = %d  Timestep = %f  Simulation time = %f\n", G.H.n_step, G.H.dt, G.H.t);

  #ifdef OUTPUT
  if (strcmp(P.init, "Read_Grid") != 0) {
  // write the initial conditions to file
  chprintf("Writing initial conditions to file...\n");
  WriteData(G, P, nfile);
  }
  // add one to the output file count
  nfile++;
  #endif //OUTPUT
  // increment the next output time
  outtime += P.outstep;

  #ifdef CPU_TIME
  stop_init = get_time();
  init = stop_init - start_total;
  #ifdef MPI_CHOLLA
  init_min = ReduceRealMin(init);
  init_max = ReduceRealMax(init);
  init_avg = ReduceRealAvg(init);
  chprintf("Init  min: %9.4f  max: %9.4f  avg: %9.4f\n", init_min, init_max, init_avg);
  #else
  printf("Init %9.4f\n", init);
  #endif //MPI_CHOLLA
  #endif //CPU_TIME

  // Evolve the grid, one timestep at a time
  chprintf("Starting calculations.\n");
  while (G.H.t < P.tout)
  //while (G.H.n_step < 1)
  {
    chprintf("n_step: %d \n", G.H.n_step + 1 );
    // get the start time
    start_step = get_time();

    // calculate the timestep
    G.set_dt(dti);
    #ifdef GRAVITY
    G.set_dt_Gravity();
    #endif

    if (G.H.t + G.H.dt > outtime)
    {
      G.H.dt = outtime - G.H.t;
    }

    // This is not necessary, G.set_dt finds the global max_dti, dt is the same in all processes by now
    // #ifdef MPI_CHOLLA
    // G.H.dt = ReduceRealMin(G.H.dt);
    // #endif

    #ifdef PARTICLES
    //Advance the particles KDK( first step )
    G.Advance_Particles( 1 );
    #endif

    // Advance the grid by one timestep
    dti = G.Update_Hydro_Grid();

    // update the simulation time ( t += dt )
    G.Update_Time();

    #ifdef GRAVITY
    //Compute Gravitational potential for next step
    G.Compute_Gravitational_Potential( &P);
    #endif

    // add one to the timestep count
    G.H.n_step++;

    // set boundary conditions for next time step
    G.Set_Boundary_Conditions_All(P);

    #ifdef PARTICLES
    //Advance the particles KDK( second step )
    G.Advance_Particles( 2 );
    #endif

    #ifdef CPU_TIME
    G.Timer.Print_Times();
    #endif

    // get the time to compute the total timestep
    stop_step = get_time();
    stop_total = get_time();
    G.H.t_wall = stop_total-start_total;
    #ifdef MPI_CHOLLA
    G.H.t_wall = ReduceRealMax(G.H.t_wall);
    #endif
    chprintf("n_step: %d   sim time: %10.7f   sim timestep: %7.4e  timestep time = %9.3f ms   total time = %9.4f s\n\n",
      G.H.n_step, G.H.t, G.H.dt, (stop_step-start_step)*1000, G.H.t_wall);

    if (G.H.t == outtime)
    {
      #ifdef OUTPUT
      /*output the grid data*/
      WriteData(G, P, nfile);
      // add one to the output file count
      nfile++;
      #endif //OUTPUT
      // update to the next output time
      outtime += P.outstep;
    }
/*
    // check for failures
    for (int i=G.H.n_ghost; i<G.H.nx-G.H.n_ghost; i++) {
      for (int j=G.H.n_ghost; j<G.H.ny-G.H.n_ghost; j++) {
        for (int k=G.H.n_ghost; k<G.H.nz-G.H.n_ghost; k++) {
          int id = i + j*G.H.nx + k*G.H.nx*G.H.ny;
          if (G.C.density[id] < 0.0 || G.C.density[id] != G.C.density[id]) {
            printf("Failure in cell %d %d %d. Density %e\n", i, j, k, G.C.density[id]);
            #ifdef MPI_CHOLLA
            MPI_Finalize();
            chexit(-1);
            #endif
            exit(0);
          }
        }
      }
    }
*/

  } /*end loop over timesteps*/

  // free the grid
  G.Reset();

  #ifdef MPI_CHOLLA
  MPI_Finalize();
  #endif /*MPI_CHOLLA*/

  return 0;

}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/make_shared.hpp>

#include <qi/preproc.hpp>
#include <qi/log.hpp>
#include <qi/application.hpp>
#include <qi/threadpool.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

qiLogCategory("qi.eventloop");

namespace qi {

  EventLoopAsio::EventLoopAsio()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
  }

  void EventLoopAsio::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopAsio::~EventLoopAsio()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError() << "Destroying EventLoopPrivate from itself while running";
    stop();
    join();
  }

  void EventLoopAsio::destroy()
  {
    if (isInEventLoopThread())
      boost::thread(&EventLoopAsio::destroy, this);
    else
    {
      delete this;
    }
  }

  void EventLoopAsio::run()
  {
    qiLogDebug() << this << "run starting";
    qi::os::setCurrentThreadName("eventloop");
    _running = true;
    _id = boost::this_thread::get_id();
    _work = new boost::asio::io_service::work(_io);
    _io.run();
    bool destroyMe;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      destroyMe = _destroyMe;
    }
    if (destroyMe)
      delete this;
  }

  bool EventLoopAsio::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopAsio::stop()
  {
    qiLogDebug() << "stopping eventloopasio: " << this;
    boost::recursive_mutex::scoped_lock sl(_mutex);
    if (_work)
    {
      delete _work;
      _work = 0;
    }
  }

  void EventLoopAsio::join()
  {
    if (boost::this_thread::get_id() == _id)
    {
      qiLogError() << "Cannot join from within event loop thread";
      return;
    }
    if (_threaded)
      try {
        _thd.join();
      }
      catch(const boost::thread_resource_error& e)
      {
        qiLogWarning() << "Join an already joined thread: " << e.what();
      }
    else
      while (_running)
        qi::os::msleep(0);
  }

  void EventLoopAsio::post(uint64_t usDelay, const boost::function<void ()>& cb)
  {
    if (!usDelay)
      _io.post(cb);
    else
      asyncCall(usDelay, cb);
  }

  static void invoke_maybe(boost::function<void()> f, qi::Promise<void> p, const boost::system::error_code& erc)
  {
    if (!erc)
    {
      f();
      p.setValue(0);
    }
    else
      p.setError("Operation canceled");
  }

  qi::Future<void> EventLoopAsio::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    boost::shared_ptr<boost::asio::deadline_timer> timer = boost::make_shared<boost::asio::deadline_timer>(boost::ref(_io));
    timer->expires_from_now(boost::posix_time::microseconds(usDelay));
    qi::Promise<void> prom(boost::bind(&boost::asio::deadline_timer::cancel, timer));
    timer->async_wait(boost::bind(&invoke_maybe, cb, prom, _1));
    return prom.future();
  }

  void* EventLoopAsio::nativeHandle()
  {
    return static_cast<void*>(&_io);
  }

  EventLoopThreadPool::EventLoopThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    _stopping = false;
    _pool = new ThreadPool(minWorkers, maxWorkers, minIdleWorkers, maxIdleWorkers);
  }

  bool EventLoopThreadPool::isInEventLoopThread()
  {
    // The point is to know if a call will be synchronous. It never is
    // with thread pool
    return false;
  }

  void EventLoopThreadPool::start()
  {
  }

  void EventLoopThreadPool::run()
  {
  }

  void EventLoopThreadPool::join()
  {
    _pool->waitForAll();
  }

  void EventLoopThreadPool::stop()
  {
    _stopping = true;
  }

  void* EventLoopThreadPool::nativeHandle()
  {
    return 0;
  }

  void EventLoopThreadPool::destroy()
  {
    _stopping = true;
    // Ensure delete is not called from one of the threads of the event loop
    boost::thread(&EventLoopThreadPool::_destroy, this);
  }
  void EventLoopThreadPool::_destroy()
  {
    delete this;
  }

  EventLoopThreadPool::~EventLoopThreadPool()
  {
    delete _pool;
  }

  static void delay_call(uint64_t usDelay, boost::function<void()>* callback)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      (*callback)();
    }
    catch(const std::exception& e)
    {
      qiLogError() << "Exception caught in async call: " << e.what();
    }
    catch(...)
    {
      qiLogError() << "Unknown exception caught in async call";
    }
    delete callback;
  }

  static void delay_call_notify(uint64_t usDelay, boost::function<void()> callback,
    qi::Promise<void> promise)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      callback();
      promise.setValue(0);
    }
    catch(const std::exception& e)
    {
      promise.setError(std::string("Exception caught in async call: ")  + e.what());
    }
    catch(...)
    {
      promise.setError("Unknown exception caught in async call");
    }
  }

  void EventLoopThreadPool::post(uint64_t usDelay,
      const boost::function<void ()>& callback)
  {
    _pool->schedule(boost::bind(&delay_call, usDelay, new boost::function<void ()>(callback)));
  }

  qi::Future<void>  EventLoopThreadPool::asyncCall(uint64_t usDelay,
      boost::function<void ()> callback)
  {
    if (_stopping)
      return qi::makeFutureError<void>("Schedule attempt on destroyed thread pool");
    qi::Promise<void> promise;
    _pool->schedule(boost::bind(&delay_call_notify, usDelay, callback, promise));
    return promise.future();
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::make_shared<AsyncCallHandlePrivate>();
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  : _p(0)
  {
  }

  EventLoop::~EventLoop()
  {
    if (_p)
      _p->destroy();
    _p = 0;
  }

  #define CHECK_STARTED                                                            \
  do {                                                                             \
    if (!_p)                                                                       \
      throw std::runtime_error("EventLoop " __HERE " : EventLoop not started");  \
  } while(0)

  bool EventLoop::isInEventLoopThread()
  {
    CHECK_STARTED;
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    CHECK_STARTED;
    _p->join();
  }

  void EventLoop::start()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->start();
  }

  void EventLoop::startThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    #define OR(name, val) (name==-1?val:name)
    if (_p)
      return;
    _p = new EventLoopThreadPool(OR(minWorkers, 2), OR(maxWorkers, 8), OR(minIdleWorkers,1), OR(maxIdleWorkers, 4));
    #undef OR
  }

  void EventLoop::stop()
  {
    CHECK_STARTED;
    _p->stop();
  }

  void EventLoop::run()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    CHECK_STARTED;
    return _p->nativeHandle();
  }

  void EventLoop::post(const boost::function<void ()>& callback,uint64_t usDelay)
  {
    CHECK_STARTED;
    _p->post(usDelay, callback);
  }

  qi::Future<void>
  EventLoop::async(
    boost::function<void ()> callback,
    uint64_t usDelay)
  {
    CHECK_STARTED;
    return _p->asyncCall(usDelay, callback);
  }

  struct MonitorContext
  {
    EventLoop* target;
    EventLoop* helper;
    Future<void> mon;
    bool isFired;  // true: pinging, false: waiting for next ping.
    bool ending;
    uint64_t maxDelay;
    Promise<void> promise;
    int64_t startTime;
  };

  static void monitor_pingtimeout(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON timeout " << ctx->isFired
    // << ' ' << (os::ustime() - ctx->startTime);
    if (!ctx->isFired)
      return; // Got the pong in the meantime, abort
    ctx->promise.setError("Event loop monitor timeout");
    /* Ping system is still on, but promise is set.
     * So future invocations of cancel() will be ignored, which makes the
     * monitoring unstopable.
     * So reset the value.
    */
    ctx->promise.reset();
  }

  static void monitor_cancel(qi::Promise<void>, boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON cancel " << ctx->isFired;
    ctx->ending = true;
    try {
      ctx->mon.cancel();
    }
    catch (...)
    {}
  }

  static void monitor_ping(boost::shared_ptr<MonitorContext> ctx)
  {
    if (ctx->ending)
      return;
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON ping " << ctx->isFired;
    if (ctx->isFired)
    { // This is a pong
      ctx->isFired = false;
      // Cancel monitoring async call
      try {
        ctx->mon.cancel();
      }
      catch (const std::exception& /*e*/) {
        //qiLogDebug("qi.EventLoop") << "MON " << e.what();
      }
      uint64_t pingDelay = os::ustime() - ctx->startTime;
      if (pingDelay > ctx->maxDelay / 2)
        qiLogDebug() << "Long ping " << pingDelay;
      // Wait a bit before pinging againg
      //qiLogDebug("qi.EventLoop") << os::ustime() << " MON delay " << ctx->maxDelay;
      ctx->helper->async(boost::bind(&monitor_ping, ctx), ctx->maxDelay*5);
    }
    else
    { // Delay between pings reached, ping again
      ctx->startTime = os::ustime();
      ctx->isFired = true;
      // Start monitor async first, or the ping async can trigger before the
      // monitor async is setup
      ctx->mon = ctx->helper->async(boost::bind(&monitor_pingtimeout, ctx), ctx->maxDelay);
      ctx->target->post(boost::bind(&monitor_ping, ctx));
      assert(ctx->mon.isCanceleable());
    }
  }

  qi::Future<void> EventLoop::monitorEventLoop(EventLoop* helper, uint64_t maxDelay)
  {
    // Context data is a Future*[2]
    boost::shared_ptr<MonitorContext> ctx = boost::make_shared<MonitorContext>();
    ctx->target = this;
    ctx->helper = helper;
    ctx->maxDelay = maxDelay;
    ctx->promise = Promise<void>(boost::bind<void>(&monitor_cancel, _1, ctx));
    ctx->isFired = false;
    ctx->ending = false;
    monitor_ping(ctx);
    return ctx->promise.future();
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    delete ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  static EventLoop* _poolEventLoop = 0;
  static double     _monitorInterval = 0;

  static void monitor_notify(const char* which)
  {
    qiLogError() << which << " event loop stuck?";
  }
  static EventLoop* _get(EventLoop* &ctx, bool isPool)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogInfo() << "Creating event loop while no qi::Application() is running";
      }
      ctx = new EventLoop();
      if (isPool)
        ctx->startThreadPool();
      else
        ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
      if (!isPool && _netEventLoop && _objEventLoop && _monitorInterval)
      {
        int64_t d = static_cast<qi::int64_t>(_monitorInterval * 1e6);
        _netEventLoop->monitorEventLoop(_objEventLoop, d)
          .connect(boost::bind(&monitor_notify, "network"));
        _objEventLoop->monitorEventLoop(_netEventLoop, d)
          .connect(boost::bind(&monitor_notify, "object"));
      }
    }
    return ctx;
  }

  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop, false);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop, false);
  }

  EventLoop* getDefaultThreadPoolEventLoop()
  {
    return _get(_poolEventLoop, true);
  }
  static void setMonitorInterval(double v)
  {
    _monitorInterval = v;
  }
  namespace {
  _QI_COMMAND_LINE_OPTIONS(
    "EventLoop monitoring",
    ("loop-monitor-latency", value<double>()->notifier(&setMonitorInterval), "Warn if event loop is stuck more than given duration in seconds")
    )
  }
}
<commit_msg>eventloop: force the network eventloop to always run on the same cpu core<commit_after>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/make_shared.hpp>

#include <qi/preproc.hpp>
#include <qi/log.hpp>
#include <qi/application.hpp>
#include <qi/threadpool.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

qiLogCategory("qi.eventloop");

namespace qi {

  EventLoopAsio::EventLoopAsio()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
  }

  void EventLoopAsio::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopAsio::~EventLoopAsio()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError() << "Destroying EventLoopPrivate from itself while running";
    stop();
    join();
  }

  void EventLoopAsio::destroy()
  {
    if (isInEventLoopThread())
      boost::thread(&EventLoopAsio::destroy, this);
    else
    {
      delete this;
    }
  }

  void EventLoopAsio::run()
  {
    qiLogDebug() << this << "run starting";
    std::string dontusecpuaffinity = qi::os::getenv("QI_EVENTLOOP_NO_CPU_AFFINITY");
    if (dontusecpuaffinity.empty()) {
      std::vector<int> cpus;
      cpus.push_back(0);
      bool ret = qi::os::setCurrentThreadCPUAffinity(cpus);
      qiLogVerbose() << "AsioEventLoop: Set cpu thread affinity to " << 1 << " (" << ret <<")";
    } else {
      qiLogVerbose() << "AsioEventLoop: Cpu thread affinity not set because QI_EVENTLOOP_NO_CPU_AFFINITY is set.";
    }
    qi::os::setCurrentThreadName("asioeventloop");
    _running = true;
    _id = boost::this_thread::get_id();
    _work = new boost::asio::io_service::work(_io);
    _io.run();
    bool destroyMe;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      destroyMe = _destroyMe;
    }
    if (destroyMe)
      delete this;
  }

  bool EventLoopAsio::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopAsio::stop()
  {
    qiLogDebug() << "stopping eventloopasio: " << this;
    boost::recursive_mutex::scoped_lock sl(_mutex);
    if (_work)
    {
      delete _work;
      _work = 0;
    }
  }

  void EventLoopAsio::join()
  {
    if (boost::this_thread::get_id() == _id)
    {
      qiLogError() << "Cannot join from within event loop thread";
      return;
    }
    if (_threaded)
      try {
        _thd.join();
      }
      catch(const boost::thread_resource_error& e)
      {
        qiLogWarning() << "Join an already joined thread: " << e.what();
      }
    else
      while (_running)
        qi::os::msleep(0);
  }

  void EventLoopAsio::post(uint64_t usDelay, const boost::function<void ()>& cb)
  {
    if (!usDelay)
      _io.post(cb);
    else
      asyncCall(usDelay, cb);
  }

  static void invoke_maybe(boost::function<void()> f, qi::Promise<void> p, const boost::system::error_code& erc)
  {
    if (!erc)
    {
      f();
      p.setValue(0);
    }
    else
      p.setError("Operation canceled");
  }

  qi::Future<void> EventLoopAsio::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    boost::shared_ptr<boost::asio::deadline_timer> timer = boost::make_shared<boost::asio::deadline_timer>(boost::ref(_io));
    timer->expires_from_now(boost::posix_time::microseconds(usDelay));
    qi::Promise<void> prom(boost::bind(&boost::asio::deadline_timer::cancel, timer));
    timer->async_wait(boost::bind(&invoke_maybe, cb, prom, _1));
    return prom.future();
  }

  void* EventLoopAsio::nativeHandle()
  {
    return static_cast<void*>(&_io);
  }

  EventLoopThreadPool::EventLoopThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    _stopping = false;
    _pool = new ThreadPool(minWorkers, maxWorkers, minIdleWorkers, maxIdleWorkers);
  }

  bool EventLoopThreadPool::isInEventLoopThread()
  {
    // The point is to know if a call will be synchronous. It never is
    // with thread pool
    return false;
  }

  void EventLoopThreadPool::start()
  {
  }

  void EventLoopThreadPool::run()
  {
  }

  void EventLoopThreadPool::join()
  {
    _pool->waitForAll();
  }

  void EventLoopThreadPool::stop()
  {
    _stopping = true;
  }

  void* EventLoopThreadPool::nativeHandle()
  {
    return 0;
  }

  void EventLoopThreadPool::destroy()
  {
    _stopping = true;
    // Ensure delete is not called from one of the threads of the event loop
    boost::thread(&EventLoopThreadPool::_destroy, this);
  }
  void EventLoopThreadPool::_destroy()
  {
    delete this;
  }

  EventLoopThreadPool::~EventLoopThreadPool()
  {
    delete _pool;
  }

  static void delay_call(uint64_t usDelay, boost::function<void()>* callback)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      (*callback)();
    }
    catch(const std::exception& e)
    {
      qiLogError() << "Exception caught in async call: " << e.what();
    }
    catch(...)
    {
      qiLogError() << "Unknown exception caught in async call";
    }
    delete callback;
  }

  static void delay_call_notify(uint64_t usDelay, boost::function<void()> callback,
    qi::Promise<void> promise)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      callback();
      promise.setValue(0);
    }
    catch(const std::exception& e)
    {
      promise.setError(std::string("Exception caught in async call: ")  + e.what());
    }
    catch(...)
    {
      promise.setError("Unknown exception caught in async call");
    }
  }

  void EventLoopThreadPool::post(uint64_t usDelay,
      const boost::function<void ()>& callback)
  {
    _pool->schedule(boost::bind(&delay_call, usDelay, new boost::function<void ()>(callback)));
  }

  qi::Future<void>  EventLoopThreadPool::asyncCall(uint64_t usDelay,
      boost::function<void ()> callback)
  {
    if (_stopping)
      return qi::makeFutureError<void>("Schedule attempt on destroyed thread pool");
    qi::Promise<void> promise;
    _pool->schedule(boost::bind(&delay_call_notify, usDelay, callback, promise));
    return promise.future();
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::make_shared<AsyncCallHandlePrivate>();
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  : _p(0)
  {
  }

  EventLoop::~EventLoop()
  {
    if (_p)
      _p->destroy();
    _p = 0;
  }

  #define CHECK_STARTED                                                            \
  do {                                                                             \
    if (!_p)                                                                       \
      throw std::runtime_error("EventLoop " __HERE " : EventLoop not started");  \
  } while(0)

  bool EventLoop::isInEventLoopThread()
  {
    CHECK_STARTED;
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    CHECK_STARTED;
    _p->join();
  }

  void EventLoop::start()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->start();
  }

  void EventLoop::startThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    #define OR(name, val) (name==-1?val:name)
    if (_p)
      return;
    _p = new EventLoopThreadPool(OR(minWorkers, 2), OR(maxWorkers, 8), OR(minIdleWorkers,1), OR(maxIdleWorkers, 4));
    #undef OR
  }

  void EventLoop::stop()
  {
    CHECK_STARTED;
    _p->stop();
  }

  void EventLoop::run()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    CHECK_STARTED;
    return _p->nativeHandle();
  }

  void EventLoop::post(const boost::function<void ()>& callback,uint64_t usDelay)
  {
    CHECK_STARTED;
    _p->post(usDelay, callback);
  }

  qi::Future<void>
  EventLoop::async(
    boost::function<void ()> callback,
    uint64_t usDelay)
  {
    CHECK_STARTED;
    return _p->asyncCall(usDelay, callback);
  }

  struct MonitorContext
  {
    EventLoop* target;
    EventLoop* helper;
    Future<void> mon;
    bool isFired;  // true: pinging, false: waiting for next ping.
    bool ending;
    uint64_t maxDelay;
    Promise<void> promise;
    int64_t startTime;
  };

  static void monitor_pingtimeout(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON timeout " << ctx->isFired
    // << ' ' << (os::ustime() - ctx->startTime);
    if (!ctx->isFired)
      return; // Got the pong in the meantime, abort
    ctx->promise.setError("Event loop monitor timeout");
    /* Ping system is still on, but promise is set.
     * So future invocations of cancel() will be ignored, which makes the
     * monitoring unstopable.
     * So reset the value.
    */
    ctx->promise.reset();
  }

  static void monitor_cancel(qi::Promise<void>, boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON cancel " << ctx->isFired;
    ctx->ending = true;
    try {
      ctx->mon.cancel();
    }
    catch (...)
    {}
  }

  static void monitor_ping(boost::shared_ptr<MonitorContext> ctx)
  {
    if (ctx->ending)
      return;
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON ping " << ctx->isFired;
    if (ctx->isFired)
    { // This is a pong
      ctx->isFired = false;
      // Cancel monitoring async call
      try {
        ctx->mon.cancel();
      }
      catch (const std::exception& /*e*/) {
        //qiLogDebug("qi.EventLoop") << "MON " << e.what();
      }
      uint64_t pingDelay = os::ustime() - ctx->startTime;
      if (pingDelay > ctx->maxDelay / 2)
        qiLogDebug() << "Long ping " << pingDelay;
      // Wait a bit before pinging againg
      //qiLogDebug("qi.EventLoop") << os::ustime() << " MON delay " << ctx->maxDelay;
      ctx->helper->async(boost::bind(&monitor_ping, ctx), ctx->maxDelay*5);
    }
    else
    { // Delay between pings reached, ping again
      ctx->startTime = os::ustime();
      ctx->isFired = true;
      // Start monitor async first, or the ping async can trigger before the
      // monitor async is setup
      ctx->mon = ctx->helper->async(boost::bind(&monitor_pingtimeout, ctx), ctx->maxDelay);
      ctx->target->post(boost::bind(&monitor_ping, ctx));
      assert(ctx->mon.isCanceleable());
    }
  }

  qi::Future<void> EventLoop::monitorEventLoop(EventLoop* helper, uint64_t maxDelay)
  {
    // Context data is a Future*[2]
    boost::shared_ptr<MonitorContext> ctx = boost::make_shared<MonitorContext>();
    ctx->target = this;
    ctx->helper = helper;
    ctx->maxDelay = maxDelay;
    ctx->promise = Promise<void>(boost::bind<void>(&monitor_cancel, _1, ctx));
    ctx->isFired = false;
    ctx->ending = false;
    monitor_ping(ctx);
    return ctx->promise.future();
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    delete ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  static EventLoop* _poolEventLoop = 0;
  static double     _monitorInterval = 0;

  static void monitor_notify(const char* which)
  {
    qiLogError() << which << " event loop stuck?";
  }
  static EventLoop* _get(EventLoop* &ctx, bool isPool)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogInfo() << "Creating event loop while no qi::Application() is running";
      }
      ctx = new EventLoop();
      if (isPool)
        ctx->startThreadPool();
      else
        ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
      if (!isPool && _netEventLoop && _objEventLoop && _monitorInterval)
      {
        int64_t d = static_cast<qi::int64_t>(_monitorInterval * 1e6);
        _netEventLoop->monitorEventLoop(_objEventLoop, d)
          .connect(boost::bind(&monitor_notify, "network"));
        _objEventLoop->monitorEventLoop(_netEventLoop, d)
          .connect(boost::bind(&monitor_notify, "object"));
      }
    }
    return ctx;
  }

  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop, false);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop, false);
  }

  EventLoop* getDefaultThreadPoolEventLoop()
  {
    return _get(_poolEventLoop, true);
  }
  static void setMonitorInterval(double v)
  {
    _monitorInterval = v;
  }
  namespace {
  _QI_COMMAND_LINE_OPTIONS(
    "EventLoop monitoring",
    ("loop-monitor-latency", value<double>()->notifier(&setMonitorInterval), "Warn if event loop is stuck more than given duration in seconds")
    )
  }
}
<|endoftext|>


<commit_before>#include <terminal.h>
#include <x86.h>
#include <stdio.h>
#include <version.h>
extern "C" void kernel_init()
{
	terminal_init();
	printf("Beryllium %s v. %s (%s) \n",BERYLLIUM_RELEASE,BERYLLIUM_VERSION,BERYLLIUM_SOURCE);
	init_x86();
	asm("hlt");
}
<commit_msg>Added cli to fix QEMU OSX Specific Problem<commit_after>#include <terminal.h>
#include <x86.h>
#include <stdio.h>
#include <version.h>
extern "C" void kernel_init()
{
	asm("cli");
	terminal_init();
	printf("Beryllium %s v. %s (%s) \n",BERYLLIUM_RELEASE,BERYLLIUM_VERSION,BERYLLIUM_SOURCE);
	init_x86();
	asm("hlt");
}
<|endoftext|>


<commit_before>//
//  main.cpp
//  RosterDesNurses
//
//  Created by J��r��my Omer on 16/11/2014.
//  Copyright (c) 2014 J��r��my Omer. All rights reserved.
//

#include "main_test.h"
#include "MyTools.h"
#include "ReadWrite.h"
#include "Solver.h"
#include "Greedy.h"
#include <exception>
#include "Modeler.h"
#include "MasterProblem.h"

//initialize the counter of object
unsigned int MyObject::s_count = 0;
unsigned int Rotation::s_count = 0;

void main_test()
{
	testFunction_Antoine();
	//testFunction_Jeremy();
	//testFunction_Samuel();
}

int main(int argc, char** argv)
{
	std::cout << "Number of arguments= " << argc << std::endl;

	// Detect errors in the number of arguments
	//
	if (argc%2 != 1) {
		Tools::throwError("main: There should be an even number of arguments!");
	}
	else if (argc > 1 && (argc < 9 || argc > 15)) {
		Tools::throwError("main: There is either too many or not enough arguments!");
	}

	// During tests, only run some test methods
	//
	if (argc == 1) {
		std::cout << "Running the test methods..."<< std::endl;
		// Tests functions to check the functions one by one
		main_test();
	}
	// Nominal behavior of the executable, as required by INRCII
	//
	else {
		// Retrieve the file names in arguments
		//
		int narg = 1;
		string scenarioFile="", initialHistoryFile="", weekDataFile="", solutionFile="";
		string customInputFile="", customOutputFile="", randSeed="";

		while (narg < argc) {
			std::cout << "arg = " << argv[narg] << " " << argv[narg+1] << std::endl;
			// Attention usine �� gaz: problem with the java simulator that add quote
			// marks in the arguments, which fucks up the open file methods
			// the code below is here to remove these quote marks
			//
			string str(argv[narg+1]);
			std::size_t found = str.find("\"");
			while (found!=std::string::npos) {
				str.erase(found,1);
				found = str.find("\"");
			}

			if (!strcmp(argv[narg],"--sce")) {
				scenarioFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--his")) {
				initialHistoryFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--week")) {
				weekDataFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--sol")) {
				solutionFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--cusIn")) {
				customInputFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--cusOut")) {
				customOutputFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--rand")) {
				randSeed = str;
				narg += 2;
			}
			else {
				Tools::throwError("main: the argument does not match the expected list!");
			}
		}
		// Throw an error if a necessary input file is missing
		if ( scenarioFile.empty() || initialHistoryFile.empty()
				|| weekDataFile.empty() || solutionFile.empty() ) {
			throw Tools::myException("A necessary file name is missing!",__LINE__);
		}

		// Read the input files
		//
		Scenario* pScen(0);
		pScen = initializeScenario(scenarioFile,weekDataFile,initialHistoryFile);
		std::cout << "Scenario file is read\n";
		if (!customInputFile.empty()) {
			vector<Demand*> demandHistory;
			demandHistory.push_back(pScen->pWeekDemand());
			int coWeek = ReadWrite::readCustom(customInputFile, pScen, demandHistory);
		}

		// Instantiate the solver class as a test
		//
		Greedy* pSolverTest =
		new Greedy(pScen, pScen->pWeekDemand(),	pScen->pWeekPreferences(), pScen->pInitialState());
		pSolverTest->constructiveGreedy();

		// Write the solution in the required output format
		//
		Tools::LogOutput outStream(solutionFile);
		outStream << pSolverTest->solutionToString();
		if (!customOutputFile.empty()) {
			ReadWrite::writeCustom(customOutputFile,weekDataFile,customInputFile);
		}
		// Todo: the method that writes the history file corresponding to the
		// solution
		string outputHistoryFile("history-week");
		outputHistoryFile += std::to_string(pScen->thisWeek()) + ".txt";
		std::cout << "Output history file: " << outputHistoryFile << std::endl;

		// Todo: delete the demand history (careful of not deleting current demand twice)
	}

}
<commit_msg>SR: main<commit_after>//
//  main.cpp
//  RosterDesNurses
//
//  Created by J��r��my Omer on 16/11/2014.
//  Copyright (c) 2014 J��r��my Omer. All rights reserved.
//

#include "main_test.h"
#include "MyTools.h"
#include "ReadWrite.h"
#include "Solver.h"
#include "Greedy.h"
#include <exception>
#include "Modeler.h"
#include "MasterProblem.h"

//initialize the counter of object
unsigned int MyObject::s_count = 0;
unsigned int Rotation::s_count = 0;

void main_test()
{
	//testFunction_Antoine();
	//testFunction_Jeremy();
	testFunction_Samuel();
}

int main(int argc, char** argv)
{
	std::cout << "Number of arguments= " << argc << std::endl;

	// Detect errors in the number of arguments
	//
	if (argc%2 != 1) {
		Tools::throwError("main: There should be an even number of arguments!");
	}
	else if (argc > 1 && (argc < 9 || argc > 15)) {
		Tools::throwError("main: There is either too many or not enough arguments!");
	}

	// During tests, only run some test methods
	//
	if (argc == 1) {
		std::cout << "Running the test methods..."<< std::endl;
		// Tests functions to check the functions one by one
		main_test();
	}
	// Nominal behavior of the executable, as required by INRCII
	//
	else {
		// Retrieve the file names in arguments
		//
		int narg = 1;
		string scenarioFile="", initialHistoryFile="", weekDataFile="", solutionFile="";
		string customInputFile="", customOutputFile="", randSeed="";

		while (narg < argc) {
			std::cout << "arg = " << argv[narg] << " " << argv[narg+1] << std::endl;
			// Attention usine �� gaz: problem with the java simulator that add quote
			// marks in the arguments, which fucks up the open file methods
			// the code below is here to remove these quote marks
			//
			string str(argv[narg+1]);
			std::size_t found = str.find("\"");
			while (found!=std::string::npos) {
				str.erase(found,1);
				found = str.find("\"");
			}

			if (!strcmp(argv[narg],"--sce")) {
				scenarioFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--his")) {
				initialHistoryFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--week")) {
				weekDataFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--sol")) {
				solutionFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--cusIn")) {
				customInputFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--cusOut")) {
				customOutputFile = str;
				narg += 2;
			}
			else if (!strcmp(argv[narg],"--rand")) {
				randSeed = str;
				narg += 2;
			}
			else {
				Tools::throwError("main: the argument does not match the expected list!");
			}
		}
		// Throw an error if a necessary input file is missing
		if ( scenarioFile.empty() || initialHistoryFile.empty()
				|| weekDataFile.empty() || solutionFile.empty() ) {
			throw Tools::myException("A necessary file name is missing!",__LINE__);
		}

		// Read the input files
		//
		Scenario* pScen(0);
		pScen = initializeScenario(scenarioFile,weekDataFile,initialHistoryFile);
		std::cout << "Scenario file is read\n";
		if (!customInputFile.empty()) {
			vector<Demand*> demandHistory;
			demandHistory.push_back(pScen->pWeekDemand());
			int coWeek = ReadWrite::readCustom(customInputFile, pScen, demandHistory);
		}

		// Instantiate the solver class as a test
		//
		Greedy* pSolverTest =
		new Greedy(pScen, pScen->pWeekDemand(),	pScen->pWeekPreferences(), pScen->pInitialState());
		pSolverTest->constructiveGreedy();

		// Write the solution in the required output format
		//
		Tools::LogOutput outStream(solutionFile);
		outStream << pSolverTest->solutionToString();
		if (!customOutputFile.empty()) {
			ReadWrite::writeCustom(customOutputFile,weekDataFile,customInputFile);
		}
		// Todo: the method that writes the history file corresponding to the
		// solution
		string outputHistoryFile("history-week");
		outputHistoryFile += std::to_string(pScen->thisWeek()) + ".txt";
		std::cout << "Output history file: " << outputHistoryFile << std::endl;

		// Todo: delete the demand history (careful of not deleting current demand twice)
	}

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2007 Marc Boris Duerner
 * Copyright (C) 2007 Laurentiu-Gheorghe Crisan
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "selectorimpl.h"
#include "cxxtools/eventloop.h"
#include "cxxtools/mutex.h"
#include "cxxtools/log.h"
#include <deque>

log_define("cxxtools.eventloop")

namespace cxxtools
{
namespace
{
    struct EvPtr
    {
        Event* ev;
        explicit EvPtr(Event* ev_)
            : ev(ev_)
        { }

        ~EvPtr()
        { if (ev) ev->destroy(); }

    };
}

class EventLoop::Impl
{
public:
    Impl()
        : _exitLoop(false),
          _selector(new SelectorImpl()),
          _eventsPerLoop(16)
        { }
    ~Impl();

    bool eventQueueEmpty()
    { return _eventQueue.empty() && _priorityEventQueue.empty() && _activeEventQueue.empty(); }

    Event* front()
    {
        if (_priorityEventQueue.empty())
            return _eventQueue.front();
        else
            return _priorityEventQueue.front();
    }

    void pop_front()
    {
        if (_priorityEventQueue.empty())
            _eventQueue.pop_front();
        else
            _priorityEventQueue.pop_front();
    }

    bool _exitLoop;
    SelectorImpl* _selector;
    std::deque<Event*> _eventQueue;
    std::deque<Event*> _priorityEventQueue;
    std::deque<Event*> _activeEventQueue;
    bool _activeEventQueueIsPriority;
    Mutex _queueMutex;
    unsigned _eventsPerLoop;
};

EventLoop::Impl::~Impl()
{
    try
    {
        while ( ! _eventQueue.empty() )
        {
            Event* ev = _eventQueue.front();
            _eventQueue.pop_front();
            ev->destroy();
        }

        while ( ! _priorityEventQueue.empty() )
        {
            Event* ev = _priorityEventQueue.front();
            _priorityEventQueue.pop_front();
            ev->destroy();
        }

        while ( ! _activeEventQueue.empty() )
        {
            Event* ev = _activeEventQueue.front();
            _activeEventQueue.pop_front();
            if (ev)
                ev->destroy();
        }

    }
    catch(...)
    {}

    delete _selector;
}

EventLoop::EventLoop()
: _impl(new Impl())
{
}

EventLoop::~EventLoop()
{
    delete _impl;
}

unsigned EventLoop::eventsPerLoop()
{
    return _impl->_eventsPerLoop;
}

void EventLoop::eventsPerLoop(unsigned n)
{
    _impl->_eventsPerLoop = n;
}

void EventLoop::onAdd( Selectable& s )
{
    return _impl->_selector->add( s );
}

void EventLoop::onRemove( Selectable& s )
{
    _impl->_selector->remove( s );
}

void EventLoop::onReinit(Selectable& /*s*/)
{
}

void EventLoop::onChanged(Selectable& s)
{
    _impl->_selector->changed(s);
}

void EventLoop::onRun()
{
    started();

    while (true)
    {
        MutexLock lock(_impl->_queueMutex);

        if (_impl->_exitLoop)
        {
            _impl->_exitLoop = false;
            break;
        }

        bool eventQueueEmpty = _impl->eventQueueEmpty();
        if (!eventQueueEmpty)
        {
            lock.unlock();
            processEvents(_impl->_eventsPerLoop);
            eventQueueEmpty = _impl->eventQueueEmpty();
        }

        lock.unlock();

        if (eventQueueEmpty)
        {
            idle();

            bool active = wait(idleTimeout());
            if (!active)
                timeout.send();
        }
        else
        {
            // process I/O events
            wait(0);
        }
    }

    exited();
}

bool EventLoop::onWaitUntil(Timespan timeout)
{
    if (_impl->_selector->waitUntil(timeout))
    {
        MutexLock lock(_impl->_queueMutex);

        if (!_impl->eventQueueEmpty())
        {
            lock.unlock();
            processEvents(_impl->_eventsPerLoop);
        }

        return true;
    }

    return false;
}

void EventLoop::onWake()
{
    _impl->_selector->wake();
}

void EventLoop::onExit()
{
    log_debug("exit loop");

    {
        MutexLock lock(_impl->_queueMutex);
        _impl->_exitLoop = true;
    }

    wake();
}

void EventLoop::onQueueEvent(const Event& ev, bool priority)
{
    log_debug("queue event");

    MutexLock lock( _impl->_queueMutex );

    EvPtr cloned(ev.clone());

    if (priority)
        _impl->_priorityEventQueue.push_back(cloned.ev);
    else
        _impl->_eventQueue.push_back(cloned.ev);

    cloned.ev = 0;
}

void EventLoop::onCommitEvent(const Event& ev, bool priority)
{
    onQueueEvent(ev, priority);
    _impl->_selector->wake();
}

void EventLoop::onProcessEvents(unsigned max)
{
    unsigned count = 0;

    auto& exitLoop = _impl->_exitLoop;
    auto& eventQueue = _impl->_eventQueue;
    auto& priorityEventQueue = _impl->_priorityEventQueue;
    auto& activeEventQueue = _impl->_activeEventQueue;
    auto& activeEventQueueIsPriority = _impl->_activeEventQueueIsPriority;
    auto& queueMutex = _impl->_queueMutex;

    log_debug("processEvents(max:" << max << ") normal/priority/active(priority): " << eventQueue.size() << '/' << priorityEventQueue.size() << '/' << activeEventQueue.size() << '(' << activeEventQueueIsPriority << ')');

    if (!activeEventQueue.empty() && !activeEventQueueIsPriority)
    {
        MutexLock lock(queueMutex);
        if (!priorityEventQueue.empty())
        {
            log_debug("priority events bypass active events");

            if (eventQueue.empty())
            {
                eventQueue.swap(activeEventQueue);
            }
            else
            {
                eventQueue.insert(eventQueue.begin(), activeEventQueue.begin(), activeEventQueue.end());
                activeEventQueue.clear();
            }

            priorityEventQueue.swap(activeEventQueue);
            activeEventQueueIsPriority = true;
        }
    }

    while (!exitLoop)
    {
        if (activeEventQueue.empty())
        {
            MutexLock lock(queueMutex);
            if (!priorityEventQueue.empty())
            {
                log_debug("move " << priorityEventQueue.size() << " priority events to active event queue");
                activeEventQueueIsPriority = true;
                activeEventQueue.swap(priorityEventQueue);
            }
            else if (!eventQueue.empty())
            {
                log_debug("move " << eventQueue.size() << " events to active event queue");
                activeEventQueueIsPriority = false;
                activeEventQueue.swap(eventQueue);
            }
        }

        if (exitLoop || activeEventQueue.empty())
        {
            log_debug_if(activeEventQueue.empty(), "no events to process");
            break;
        }

        EvPtr ev(activeEventQueue.front());
        activeEventQueue.pop_front();

        ++count;

        log_debug("send event " << count);
        event.send(*ev.ev);

        if (max != 0 && count >= max)
        {
            log_debug("maximum number of events per loop " << max << " reached");
            break;
        }
    }
}

} // namespace cxxtools
<commit_msg>make cxxtools compatible with C++03 again<commit_after>/*
 * Copyright (C) 2007 Marc Boris Duerner
 * Copyright (C) 2007 Laurentiu-Gheorghe Crisan
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "selectorimpl.h"
#include "cxxtools/eventloop.h"
#include "cxxtools/mutex.h"
#include "cxxtools/log.h"
#include <deque>

log_define("cxxtools.eventloop")

namespace cxxtools
{
namespace
{
    struct EvPtr
    {
        Event* ev;
        explicit EvPtr(Event* ev_)
            : ev(ev_)
        { }

        ~EvPtr()
        { if (ev) ev->destroy(); }

    };
}

class EventLoop::Impl
{
public:
    Impl()
        : _exitLoop(false),
          _selector(new SelectorImpl()),
          _eventsPerLoop(16)
        { }
    ~Impl();

    bool eventQueueEmpty()
    { return _eventQueue.empty() && _priorityEventQueue.empty() && _activeEventQueue.empty(); }

    Event* front()
    {
        if (_priorityEventQueue.empty())
            return _eventQueue.front();
        else
            return _priorityEventQueue.front();
    }

    void pop_front()
    {
        if (_priorityEventQueue.empty())
            _eventQueue.pop_front();
        else
            _priorityEventQueue.pop_front();
    }

    bool _exitLoop;
    SelectorImpl* _selector;
    std::deque<Event*> _eventQueue;
    std::deque<Event*> _priorityEventQueue;
    std::deque<Event*> _activeEventQueue;
    bool _activeEventQueueIsPriority;
    Mutex _queueMutex;
    unsigned _eventsPerLoop;
};

EventLoop::Impl::~Impl()
{
    try
    {
        while ( ! _eventQueue.empty() )
        {
            Event* ev = _eventQueue.front();
            _eventQueue.pop_front();
            ev->destroy();
        }

        while ( ! _priorityEventQueue.empty() )
        {
            Event* ev = _priorityEventQueue.front();
            _priorityEventQueue.pop_front();
            ev->destroy();
        }

        while ( ! _activeEventQueue.empty() )
        {
            Event* ev = _activeEventQueue.front();
            _activeEventQueue.pop_front();
            if (ev)
                ev->destroy();
        }

    }
    catch(...)
    {}

    delete _selector;
}

EventLoop::EventLoop()
: _impl(new Impl())
{
}

EventLoop::~EventLoop()
{
    delete _impl;
}

unsigned EventLoop::eventsPerLoop()
{
    return _impl->_eventsPerLoop;
}

void EventLoop::eventsPerLoop(unsigned n)
{
    _impl->_eventsPerLoop = n;
}

void EventLoop::onAdd( Selectable& s )
{
    return _impl->_selector->add( s );
}

void EventLoop::onRemove( Selectable& s )
{
    _impl->_selector->remove( s );
}

void EventLoop::onReinit(Selectable& /*s*/)
{
}

void EventLoop::onChanged(Selectable& s)
{
    _impl->_selector->changed(s);
}

void EventLoop::onRun()
{
    started();

    while (true)
    {
        MutexLock lock(_impl->_queueMutex);

        if (_impl->_exitLoop)
        {
            _impl->_exitLoop = false;
            break;
        }

        bool eventQueueEmpty = _impl->eventQueueEmpty();
        if (!eventQueueEmpty)
        {
            lock.unlock();
            processEvents(_impl->_eventsPerLoop);
            eventQueueEmpty = _impl->eventQueueEmpty();
        }

        lock.unlock();

        if (eventQueueEmpty)
        {
            idle();

            bool active = wait(idleTimeout());
            if (!active)
                timeout.send();
        }
        else
        {
            // process I/O events
            wait(0);
        }
    }

    exited();
}

bool EventLoop::onWaitUntil(Timespan timeout)
{
    if (_impl->_selector->waitUntil(timeout))
    {
        MutexLock lock(_impl->_queueMutex);

        if (!_impl->eventQueueEmpty())
        {
            lock.unlock();
            processEvents(_impl->_eventsPerLoop);
        }

        return true;
    }

    return false;
}

void EventLoop::onWake()
{
    _impl->_selector->wake();
}

void EventLoop::onExit()
{
    log_debug("exit loop");

    {
        MutexLock lock(_impl->_queueMutex);
        _impl->_exitLoop = true;
    }

    wake();
}

void EventLoop::onQueueEvent(const Event& ev, bool priority)
{
    log_debug("queue event");

    MutexLock lock( _impl->_queueMutex );

    EvPtr cloned(ev.clone());

    if (priority)
        _impl->_priorityEventQueue.push_back(cloned.ev);
    else
        _impl->_eventQueue.push_back(cloned.ev);

    cloned.ev = 0;
}

void EventLoop::onCommitEvent(const Event& ev, bool priority)
{
    onQueueEvent(ev, priority);
    _impl->_selector->wake();
}

void EventLoop::onProcessEvents(unsigned max)
{
    unsigned count = 0;

    bool& exitLoop = _impl->_exitLoop;
    std::deque<Event*>& eventQueue = _impl->_eventQueue;
    std::deque<Event*>& priorityEventQueue = _impl->_priorityEventQueue;
    std::deque<Event*>& activeEventQueue = _impl->_activeEventQueue;
    bool& activeEventQueueIsPriority = _impl->_activeEventQueueIsPriority;
    Mutex& queueMutex = _impl->_queueMutex;

    log_debug("processEvents(max:" << max << ") normal/priority/active(priority): " << eventQueue.size() << '/' << priorityEventQueue.size() << '/' << activeEventQueue.size() << '(' << activeEventQueueIsPriority << ')');

    if (!activeEventQueue.empty() && !activeEventQueueIsPriority)
    {
        MutexLock lock(queueMutex);
        if (!priorityEventQueue.empty())
        {
            log_debug("priority events bypass active events");

            if (eventQueue.empty())
            {
                eventQueue.swap(activeEventQueue);
            }
            else
            {
                eventQueue.insert(eventQueue.begin(), activeEventQueue.begin(), activeEventQueue.end());
                activeEventQueue.clear();
            }

            priorityEventQueue.swap(activeEventQueue);
            activeEventQueueIsPriority = true;
        }
    }

    while (!exitLoop)
    {
        if (activeEventQueue.empty())
        {
            MutexLock lock(queueMutex);
            if (!priorityEventQueue.empty())
            {
                log_debug("move " << priorityEventQueue.size() << " priority events to active event queue");
                activeEventQueueIsPriority = true;
                activeEventQueue.swap(priorityEventQueue);
            }
            else if (!eventQueue.empty())
            {
                log_debug("move " << eventQueue.size() << " events to active event queue");
                activeEventQueueIsPriority = false;
                activeEventQueue.swap(eventQueue);
            }
        }

        if (exitLoop || activeEventQueue.empty())
        {
            log_debug_if(activeEventQueue.empty(), "no events to process");
            break;
        }

        EvPtr ev(activeEventQueue.front());
        activeEventQueue.pop_front();

        ++count;

        log_debug("send event " << count);
        event.send(*ev.ev);

        if (max != 0 && count >= max)
        {
            log_debug("maximum number of events per loop " << max << " reached");
            break;
        }
    }
}

} // namespace cxxtools
<|endoftext|>


<commit_before>/*
 * Copyright (c) Oona Räisänen
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */
#include "src/input.h"

#include <cassert>
#include <iostream>
#include <stdexcept>
#include <string>

#include "src/groups.h"
#include "src/util.h"

namespace redsea {

/*
 * An MPXReader deals with reading an FM multiplex signal from an audio file or
 * raw PCM via stdin, separating it into channels and converting to chunks of
 * floating-point samples.
 *
 */
MPXReader::MPXReader(const Options& options) :
    input_type_(options.input_type),
    feed_thru_(options.feed_thru),
    sfinfo_({0, 0, 0, 0, 0, 0}) {
  is_eof_ = false;

  if (options.input_type == INPUT_MPX_STDIN ||
      options.input_type == INPUT_MPX_SNDFILE) {

    if (options.input_type == INPUT_MPX_STDIN) {
      sfinfo_.channels = 1;
      sfinfo_.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
      sfinfo_.samplerate = options.samplerate;
      sfinfo_.frames = 0;
      file_ = sf_open_fd(fileno(stdin), SFM_READ, &sfinfo_, SF_TRUE);

      outfile_ = sf_open_fd(fileno(stdout), SFM_WRITE, &sfinfo_, SF_TRUE);
    } else if (options.input_type == INPUT_MPX_SNDFILE) {
      file_ = sf_open(options.sndfilename.c_str(), SFM_READ, &sfinfo_);
    }

    if (file_ == nullptr) {
      int err = sf_error (file_) ;
      std::cerr << "error: failed to open file: " << sf_error_number(err);
      is_eof_ = true;
    } else if (sfinfo_.samplerate < 128000.f) {
      std::cerr << "error: sample rate must be 128000 Hz or higher" << '\n';
      is_eof_ = true;
    } else {
      assert(sfinfo_.channels < static_cast<int>(buffer_.size()));
      used_buffer_size_ =
          (buffer_.size() / sfinfo_.channels) * sfinfo_.channels;
    }
  }
}

MPXReader::~MPXReader() {
  sf_close(file_);
}

bool MPXReader::eof() const {
  return is_eof_;
}

std::vector<float> MPXReader::ReadChunk() {
  std::vector<float> chunk;
  if (is_eof_)
    return chunk;

  sf_count_t num_read =
      sf_read_float(file_, buffer_.data(), used_buffer_size_);
  if (num_read < static_cast<long long>(used_buffer_size_))
    is_eof_ = true;

  if (sfinfo_.channels == 1) {
    chunk = std::vector<float>(buffer_.begin(), buffer_.end());
  } else {
    chunk = std::vector<float>(num_read / sfinfo_.channels);
    for (size_t i = 0; i < chunk.size(); i++)
      chunk[i] = buffer_[i * sfinfo_.channels];
  }
  return chunk;
}

float MPXReader::samplerate() const {
  return sfinfo_.samplerate;
}

AsciiBitReader::AsciiBitReader(const Options& options) :
    is_eof_(false), feed_thru_(options.feed_thru) {
}

AsciiBitReader::~AsciiBitReader() {
}

bool AsciiBitReader::ReadNextBit() {
  int chr = 0;
  while (chr != '0' && chr != '1' && chr != EOF) {
    chr = getchar();
    if (feed_thru_)
      putchar(chr);
  }

  if (chr == EOF)
    is_eof_ = true;

  return (chr == '1');
}

bool AsciiBitReader::eof() const {
  return is_eof_;
}

/*
 * Read a single line containing an RDS group in the RDS Spy hex format.
 *
 */
Group ReadNextHexGroup(const Options& options) {
  Group group;
  group.disable_offsets();

  bool finished = false;

  while (!(finished || std::cin.eof())) {
    std::string line;
    std::getline(std::cin, line);
    if (options.feed_thru)
      std::cout << line << '\n';

    if (line.length() < 16)
      continue;

    for (eBlockNumber block_num : {BLOCK1, BLOCK2, BLOCK3, BLOCK4}) {
      uint16_t block_data = 0;
      bool block_still_valid = true;

      int nyb = 0;
      while (nyb < 4) {
        if (line.length() < 1) {
          finished = true;
          break;
        }

        std::string single = line.substr(0, 1);

        if (single != " ") {
          try {
            int nval = std::stoi(std::string(single), nullptr, 16);
            block_data = (block_data << 4) + nval;
          } catch (std::invalid_argument) {
            block_still_valid = false;
          }
          nyb++;
        }
        line = line.substr(1);
      }

      if (block_still_valid)
        group.set(block_num, block_data);

      if (block_num == BLOCK4)
        finished = true;
    }
  }

  if (options.timestamp)
    group.set_time(std::chrono::system_clock::now());

  return group;
}

}  // namespace redsea
<commit_msg>feed-thru for audio files<commit_after>/*
 * Copyright (c) Oona Räisänen
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */
#include "src/input.h"

#include <cassert>
#include <iostream>
#include <stdexcept>
#include <string>

#include "src/groups.h"
#include "src/util.h"

namespace redsea {

/*
 * An MPXReader deals with reading an FM multiplex signal from an audio file or
 * raw PCM via stdin, separating it into channels and converting to chunks of
 * floating-point samples.
 *
 */
MPXReader::MPXReader(const Options& options) :
    input_type_(options.input_type),
    feed_thru_(options.feed_thru),
    sfinfo_({0, 0, 0, 0, 0, 0}) {
  is_eof_ = false;

  if (options.input_type == INPUT_MPX_STDIN ||
      options.input_type == INPUT_MPX_SNDFILE) {

    if (options.input_type == INPUT_MPX_STDIN) {
      sfinfo_.channels = 1;
      sfinfo_.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
      sfinfo_.samplerate = options.samplerate;
      sfinfo_.frames = 0;
      file_ = sf_open_fd(fileno(stdin), SFM_READ, &sfinfo_, SF_TRUE);
    } else if (options.input_type == INPUT_MPX_SNDFILE) {
      file_ = sf_open(options.sndfilename.c_str(), SFM_READ, &sfinfo_);
    }

    if (file_ == nullptr) {
      int err = sf_error (file_) ;
      std::cerr << "error: failed to open file: " << sf_error_number(err);
      is_eof_ = true;
    } else if (sfinfo_.samplerate < 128000.f) {
      std::cerr << "error: sample rate must be 128000 Hz or higher" << '\n';
      is_eof_ = true;
    } else {
      assert(sfinfo_.channels < static_cast<int>(buffer_.size()));
      used_buffer_size_ =
          (buffer_.size() / sfinfo_.channels) * sfinfo_.channels;

      outfile_ = sf_open_fd(fileno(stdout), SFM_WRITE, &sfinfo_, SF_TRUE);
    }
  }
}

MPXReader::~MPXReader() {
  sf_close(file_);
}

bool MPXReader::eof() const {
  return is_eof_;
}

std::vector<float> MPXReader::ReadChunk() {
  std::vector<float> chunk;
  if (is_eof_)
    return chunk;

  sf_count_t num_read =
      sf_read_float(file_, buffer_.data(), used_buffer_size_);
  if (num_read < static_cast<long long>(used_buffer_size_))
    is_eof_ = true;

  if (sfinfo_.channels == 1) {
    chunk = std::vector<float>(buffer_.begin(), buffer_.end());
  } else {
    chunk = std::vector<float>(num_read / sfinfo_.channels);
    for (size_t i = 0; i < chunk.size(); i++)
      chunk[i] = buffer_[i * sfinfo_.channels];
  }
  return chunk;
}

float MPXReader::samplerate() const {
  return sfinfo_.samplerate;
}

AsciiBitReader::AsciiBitReader(const Options& options) :
    is_eof_(false), feed_thru_(options.feed_thru) {
}

AsciiBitReader::~AsciiBitReader() {
}

bool AsciiBitReader::ReadNextBit() {
  int chr = 0;
  while (chr != '0' && chr != '1' && chr != EOF) {
    chr = getchar();
    if (feed_thru_)
      putchar(chr);
  }

  if (chr == EOF)
    is_eof_ = true;

  return (chr == '1');
}

bool AsciiBitReader::eof() const {
  return is_eof_;
}

/*
 * Read a single line containing an RDS group in the RDS Spy hex format.
 *
 */
Group ReadNextHexGroup(const Options& options) {
  Group group;
  group.disable_offsets();

  bool finished = false;

  while (!(finished || std::cin.eof())) {
    std::string line;
    std::getline(std::cin, line);
    if (options.feed_thru)
      std::cout << line << '\n';

    if (line.length() < 16)
      continue;

    for (eBlockNumber block_num : {BLOCK1, BLOCK2, BLOCK3, BLOCK4}) {
      uint16_t block_data = 0;
      bool block_still_valid = true;

      int nyb = 0;
      while (nyb < 4) {
        if (line.length() < 1) {
          finished = true;
          break;
        }

        std::string single = line.substr(0, 1);

        if (single != " ") {
          try {
            int nval = std::stoi(std::string(single), nullptr, 16);
            block_data = (block_data << 4) + nval;
          } catch (std::invalid_argument) {
            block_still_valid = false;
          }
          nyb++;
        }
        line = line.substr(1);
      }

      if (block_still_valid)
        group.set(block_num, block_data);

      if (block_num == BLOCK4)
        finished = true;
    }
  }

  if (options.timestamp)
    group.set_time(std::chrono::system_clock::now());

  return group;
}

}  // namespace redsea
<|endoftext|>


<commit_before>// Copyright (c) Burator 2014-2015
#include <QDir>
#include <QFile>
#include <QImage>
#include <QDebug>
#include <QString>
#include <QDateTime>
#include <QFileInfo>
#include <QByteArray>
#include <QStringList>
#include <QCoreApplication>
#include <QCommandLineParser>

#include <cmath>

#include "Util.h"
#include "Types.h"
#include "Global.h"
#include "Version.h"
#include "FaceDetector.h"

B_USE_NAMESPACE

// Show console output.
static const bool showOutput = true;

// Show debug/info output.
static const bool showDebug = true;

void msgHandler(QtMsgType type, const QMessageLogContext &ctx,
                const QString &msg);

int main(int argc, char **argv) {
	QCoreApplication app(argc, argv);
	QCoreApplication::setApplicationName("Blurator");
	QCoreApplication::setApplicationVersion(versionString());

  qInstallMessageHandler(msgHandler);

  QCommandLineParser parser;
  parser.setApplicationDescription("Blur license plates and faces.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("paths", "Paths to images.", "paths..");

  // Face detection option
  QCommandLineOption detectFaces(QStringList() << "f" << "faces",
                                 "Detect faces.");
  parser.addOption(detectFaces);

  // License plate detection option
  QCommandLineOption detectPlates(QStringList() << "p" << "plates",
                                  "Detect license plates.");
  parser.addOption(detectPlates);

  // Reply "yes" to everything option
  QCommandLineOption replyYes(QStringList() << "y" << "yes",
                              "Automatically reply \"yes\" to all questions.");
  parser.addOption(replyYes);

  // Reply "no" to everything option
  QCommandLineOption replyNo(QStringList() << "n" << "no",
                             "Automatically reply \"no\" to all questions.");
  parser.addOption(replyNo);

  // No-backup file option
  QCommandLineOption noBackupFile(QStringList() << "no-backup",
                                 "Don't store a backup of the original image.");
  parser.addOption(noBackupFile);

  parser.process(app);
  const QStringList args = parser.positionalArguments();

  // Check optional command line options
  bool dFaces = parser.isSet(detectFaces);
  bool dPlates = parser.isSet(detectPlates);
  bool rYes = parser.isSet(replyYes);
  bool rNo = parser.isSet(replyNo);
  bool noBackup = parser.isSet(noBackupFile);

  // Ensure the arguments are passed.
  if (args.isEmpty()) {
  	qCritical() << "Must provide paths to images!";
  	return -1;
  }

  if (!dPlates && !dFaces) {
    qCritical() << "Must choose to detect plates and/or faces!";
    return -1;
  }

  if (rYes && rNo) {
    qCritical() << "Can't both say yes and no to everything!";
    return -1;
  }

  // If non-null then the boolean value means reply "yes" for true and
  // "no" for false.
  BoolPtr autoReplyYes(nullptr);
  if (rYes || rNo) {
    autoReplyYes.reset(new bool);
    *autoReplyYes = rYes;
  }

  // Find all images from the arguments.
  QStringList images;
  foreach (const QString &path, args) {
    QFileInfo fi(path);
    if (!fi.exists()) {
      qWarning() << "Ignoring nonexistent file:" << path;
      continue;
    }

    if (fi.isFile() && Util::isSupportedImage(path)) {
      images << path;
    }
    else if (fi.isDir()) {
      qWarning() << "Ignoring folder:" << path;
    }
  }

  if (images.isEmpty()) {
    qCritical() << "Found no supported images to process!";
    return -1;
  }

  if (noBackup) {
    qWarning() << "Warning no backup files will be created!";
  }

  QDateTime startDate = QDateTime::currentDateTime();

  const int size = images.size();
  const int fwidth = ceil(log10(size));
  qint64 faceCnt = 0;
  for (int i = 0; i < size; i++) {
    const QString &path = images[i];
    QString msg = QString("%1%2")
      .arg(size > 1 ? QString("[%1/%2] ").arg(i+1, fwidth).arg(size) : "")
      .arg("Processing");
    qDebug() << qPrintable(msg) << path;

    if (dFaces) {
      QFile f(path);
      if (!f.open(QIODevice::ReadOnly)) {
        qCritical() << "Could not read from image file!";
        return -1;
      }
      QByteArray imageData = f.readAll();
      f.close();

      MatPtr image = Util::imageToMat(imageData);
      if (image == nullptr) {
        qCritical() << "Invalid image!";
        return -1;
      }

      FaceDetector detector;
      if (!detector.isValid()) {
        qCritical() << "Could not setup facial detector.";
        return -1;
      }

      QList<FacePtr> faces = detector.detect(image);
      if (faces.isEmpty()) {
        continue;
      }

      faceCnt += faces.size();
      qDebug() << "Found" << faces.size() << "face(s).";
      qDebug() << faces;

      // Render face overlays to an image file to visualize the result.
      if (!faces.isEmpty()) {
        QImage overlay = QImage::fromData(imageData);
        Util::drawFaces(overlay, faces);

        // Save original to backup file.
        if (!noBackup) {
          QString bpath = Util::getBackupPath(path);
          if (QFile::copy(path, bpath)) {
            qDebug() << "Saved backup:" << bpath;
          }
          else {
            qWarning() << "Could not save backup:" << bpath;
            if (!Util::askProceed("Do you want to proceed?", autoReplyYes.get())) {
              qWarning() << "Aborting..";
              return -1;
            }
          }
        }

        if (overlay.save(path)) {
          qDebug() << "Saved face overlays:" << path;
        }
        else {
          qCritical() << "Could not save overlays";
        }
      }
    }

    // TODO: Plate detection
    if (dPlates) {
      qCritical() << "Plate detection not implemented yet!";
      return -1;
    }
  }

  qint64 elapsed = startDate.msecsTo(QDateTime::currentDateTime());

  qDebug() << endl << "Time elapsed:" << qPrintable(Util::formatTime(elapsed));
  if (size > 1) {
    qDebug() << "Time per image:" << qPrintable(Util::formatTime(elapsed / size));
  }
  qDebug() << "Faces found:" << faceCnt;
  if (size > 1) {
    qDebug() << "Faces per image:" << double(faceCnt) / double(size);
  }

  return 0;
}

void msgHandler(QtMsgType type, const QMessageLogContext &ctx,
                const QString &msg) {
  if (!showOutput) return;

  QTextStream stream(stdout);

  switch (type) {
  case QtDebugMsg:
    if (showDebug) {
      if (QString(msg) == "") {
        stream << endl;
        return;
      }
      stream << msg << endl;
    }
    break;

  case QtWarningMsg:
    stream << "(W) " << msg << endl;
    break;

  case QtCriticalMsg:
    stream << "(E) " << msg << endl;
    break;

  case QtFatalMsg:
    stream << "(F) " << msg << endl;
    abort();
  }
}
<commit_msg>Implemeneted new output that updates the same line for progress smartly.<commit_after>// Copyright (c) Burator 2014-2015
#include <QDir>
#include <QFile>
#include <QImage>
#include <QDebug>
#include <QString>
#include <QDateTime>
#include <QFileInfo>
#include <QByteArray>
#include <QStringList>
#include <QCoreApplication>
#include <QCommandLineParser>

#include <cmath>
#include <iostream>

#include "Util.h"
#include "Types.h"
#include "Global.h"
#include "Version.h"
#include "FaceDetector.h"

B_USE_NAMESPACE

// Show console output.
static const bool showOutput = true;

// Show debug/info output.
static const bool showDebug = true;

void msgHandler(QtMsgType type, const QMessageLogContext &ctx,
                const QString &msg);

int main(int argc, char **argv) {
	QCoreApplication app(argc, argv);
	QCoreApplication::setApplicationName("Blurator");
	QCoreApplication::setApplicationVersion(versionString());

  qInstallMessageHandler(msgHandler);

  QCommandLineParser parser;
  parser.setApplicationDescription("Blur license plates and faces.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("paths", "Paths to images.", "paths..");

  // Face detection option
  QCommandLineOption detectFaces(QStringList() << "f" << "faces",
                                 "Detect faces.");
  parser.addOption(detectFaces);

  // License plate detection option
  QCommandLineOption detectPlates(QStringList() << "p" << "plates",
                                  "Detect license plates.");
  parser.addOption(detectPlates);

  // Reply "yes" to everything option
  QCommandLineOption replyYes(QStringList() << "y" << "yes",
                              "Automatically reply \"yes\" to all questions.");
  parser.addOption(replyYes);

  // Reply "no" to everything option
  QCommandLineOption replyNo(QStringList() << "n" << "no",
                             "Automatically reply \"no\" to all questions.");
  parser.addOption(replyNo);

  // No-backup file option
  QCommandLineOption noBackupFile(QStringList() << "no-backup",
                                 "Don't store a backup of the original image.");
  parser.addOption(noBackupFile);

  parser.process(app);
  const QStringList args = parser.positionalArguments();

  // Check optional command line options
  bool dFaces = parser.isSet(detectFaces);
  bool dPlates = parser.isSet(detectPlates);
  bool rYes = parser.isSet(replyYes);
  bool rNo = parser.isSet(replyNo);
  bool noBackup = parser.isSet(noBackupFile);

  // Ensure the arguments are passed.
  if (args.isEmpty()) {
  	qCritical() << "Must provide paths to images!";
  	return -1;
  }

  if (!dPlates && !dFaces) {
    qCritical() << "Must choose to detect plates and/or faces!";
    return -1;
  }

  if (rYes && rNo) {
    qCritical() << "Can't both say yes and no to everything!";
    return -1;
  }

  // If non-null then the boolean value means reply "yes" for true and
  // "no" for false.
  BoolPtr autoReplyYes(nullptr);
  if (rYes || rNo) {
    autoReplyYes.reset(new bool);
    *autoReplyYes = rYes;
  }

  // Find all images from the arguments.
  QStringList images;
  foreach (const QString &path, args) {
    QFileInfo fi(path);
    if (!fi.exists()) {
      qWarning() << "Ignoring nonexistent file:" << path;
      continue;
    }

    if (fi.isFile() && Util::isSupportedImage(path)) {
      images << path;
    }
    else if (fi.isDir()) {
      qWarning() << "Ignoring folder:" << path;
    }
  }

  if (images.isEmpty()) {
    qCritical() << "Found no supported images to process!";
    return -1;
  }

  if (noBackup) {
    qWarning() << "Warning no backup files will be created!";
  }

  QDateTime startDate = QDateTime::currentDateTime();

  const int size = images.size();
  const int fwidth = ceil(log10(size));
  qint64 faceCnt = 0, faceTot = 0;
  for (int i = 0; i < size; i++) {
    const QString &path = images[i];

    if (dFaces) {
      QFile f(path);
      if (!f.open(QIODevice::ReadOnly)) {
        qCritical() << "Could not read from image file!";
        return -1;
      }
      QByteArray imageData = f.readAll();
      f.close();

      MatPtr image = Util::imageToMat(imageData);
      if (image == nullptr) {
        qCritical() << "Invalid image!";
        return -1;
      }

      FaceDetector detector;
      if (!detector.isValid()) {
        qCritical() << "Could not setup facial detector.";
        return -1;
      }

      QList<FacePtr> faces = detector.detect(image);
      faceCnt = faces.size();

      if (faces.isEmpty()) {
        goto updateProgress;
      }

      faceTot += faceCnt;

      // Render face overlays to an image file to visualize the result.
      if (!faces.isEmpty()) {
        QImage overlay = QImage::fromData(imageData);
        Util::drawFaces(overlay, faces);

        // Save original to backup file.
        if (!noBackup) {
          QString bpath = Util::getBackupPath(path);
          if (!QFile::copy(path, bpath)) {
            qWarning() << "Could not save backup:" << bpath;
            if (!Util::askProceed("Do you want to proceed?", autoReplyYes.get())) {
              qWarning() << "Aborting..";
              return -1;
            }
          }
        }

        if (!overlay.save(path)) {
          qCritical() << "Could not save overlays";
        }
      }
    }

    // TODO: Plate detection
    if (dPlates) {
      qCritical() << "Plate detection not implemented yet!";
      return -1;
    }

  updateProgress:
    static int lastLen = 0;

    float progress = float(i+1) / float(size) * 100.0;

    QDateTime now = QDateTime::currentDateTime();
    qint64 elapsed = startDate.msecsTo(now);
    qint64 left = ((100.0 / progress) * elapsed) - elapsed;

    bool last = (i+1 == size);

    QString line1 = QString("Processed %1: %2 faces")
      .arg(path).arg(faceCnt);

    QString line2 = QString("[ %3/%4 (%5%) | %6 faces | %7 %8 ]")
      .arg(i+1).arg(size).arg(progress, 0, 'f', 1).arg(faceTot)
      .arg(!last ? Util::formatTime(left) : Util::formatTime(elapsed))
      .arg(!last ? "left" : "elapsed");

    QString msg = QString("%1\n%2").arg(line1).arg(line2);

    // Rewind to beginning and output message. If at second line or
    // latter then overwrite everything with empty spaces to "blank"
    // out so no traces are left if the new lines are longer than
    // the last ones.
    {
      using namespace std;
      cout << '\r';
      if (i > 0) {
        cout << QString(lastLen, ' ').toStdString() << '\r';
      }
      cout << msg.toStdString();
      cout.flush();
    }

    lastLen = msg.size();
  }

  return 0;
}

void msgHandler(QtMsgType type, const QMessageLogContext &ctx,
                const QString &msg) {
  if (!showOutput) return;

  QTextStream stream(stdout);

  switch (type) {
  case QtDebugMsg:
    if (showDebug) {
      if (QString(msg) == "") {
        stream << endl;
        return;
      }
      stream << msg << endl;
    }
    break;

  case QtWarningMsg:
    stream << "(W) " << msg << endl;
    break;

  case QtCriticalMsg:
    stream << "(E) " << msg << endl;
    break;

  case QtFatalMsg:
    stream << "(F) " << msg << endl;
    abort();
  }
}
<|endoftext|>