<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: storcach.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:44:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _STORE_STORCACH_HXX
#define _STORE_STORCACH_HXX "$Revision: 1.5 $"

#ifndef _SAL_TYPES_H_
#include <sal/types.h>
#endif

#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _STORE_TYPES_H_
#include <store/types.h>
#endif

#ifndef INCLUDED_CSTDDEF
#include <cstddef>
#define INCLUDED_CSTDDEF
#endif

namespace store
{

struct OStorePageDescriptor;
struct OStorePageData;
class  OStorePageBIOS;

/*========================================================================
 *
 * OStorePageCache interface.
 * (OStorePageData in external representation)
 *
 *======================================================================*/
#define STORE_LIMIT_CACHEPAGES   256
#define STORE_DEFAULT_CACHEPAGES STORE_LIMIT_CACHEPAGES

struct OStorePageCacheEntry;

class OStorePageCache
{
    typedef OStorePageCacheEntry entry;

public:
    /** Allocation.
     */
    static void * operator new (std::size_t n) SAL_THROW(());
    static void   operator delete (void * p, std::size_t) SAL_THROW(());

    /** Construction.
    */
    OStorePageCache (
        sal_uInt16 nPages = STORE_DEFAULT_CACHEPAGES);

    /** Destruction.
    */
    ~OStorePageCache (void);

    /** load.
    */
    storeError load (
        const OStorePageDescriptor &rDescr,
        OStorePageData             &rData,
        OStorePageBIOS             &rBIOS,
        osl::Mutex                 *pMutex = NULL);

    /** update.
    */
    enum UpdateMode
    {
        UPDATE_WRITE_THROUGH = 0,
        UPDATE_WRITE_DELAYED = 1
    };

    storeError update (
        const OStorePageDescriptor &rDescr,
        const OStorePageData       &rData,
        OStorePageBIOS             &rBIOS,
        osl::Mutex                 *pMutex = NULL,
        UpdateMode                  eMode  = UPDATE_WRITE_THROUGH);

    /** invalidate.
    */
    storeError invalidate (
        const OStorePageDescriptor &rDescr,
        osl::Mutex                 *pMutex = NULL);

    /** flush.
    */
    storeError flush (
        OStorePageBIOS &rBIOS,
        osl::Mutex     *pMutex = NULL);

    /** hitRatio [nHit / (nHit + nMissed)].
     */
    inline double hitRatio (void) const;

    /** usageRatio [nUsed / nSize].
    */
    inline double usageRatio (void) const;

private:
    /** Representation.
    */
    sal_uInt16  m_nSize;
    sal_uInt16  m_nUsed;
    entry      *m_pData[STORE_LIMIT_CACHEPAGES];
    entry      *m_pHead;

    sal_uInt32  m_nHit;
    sal_uInt32  m_nMissed;
    sal_uInt32  m_nUpdHit;
    sal_uInt32  m_nUpdLRU;
    sal_uInt32  m_nWrtBack;

    /** Implementation.
    */
    sal_uInt16 find (const OStorePageDescriptor &rDescr) const;
    void       move (sal_uInt16 nSI, sal_uInt16 nDI);

    /** insert.
    */
    enum InsertMode
    {
        INSERT_CLEAN = 0,
        INSERT_DIRTY = 1
    };

    storeError insert (
        sal_uInt16                  nIndex,
        const OStorePageDescriptor &rDescr,
        const OStorePageData       &rData,
        OStorePageBIOS             &rBIOS,
        InsertMode                  eMode = INSERT_CLEAN);

    /** Not implemented.
    */
    OStorePageCache (const OStorePageCache& rOther);
    OStorePageCache& operator= (const OStorePageCache& rOther);
};

/*
 * hitRatio [nHit / (nHit + nMissed)].
 */
inline double OStorePageCache::hitRatio (void) const
{
    if (m_nHit || m_nMissed)
        return ((double)m_nHit / (double)(m_nHit + m_nMissed));
    else
        return 1.0;
}

/*
 * usageRatio [nUsed / nSize].
 */
inline double OStorePageCache::usageRatio (void) const
{
    if (m_nUsed < m_nSize)
        return ((double)m_nUsed / (double)m_nSize);
    else
        return 1.0;
}

/*========================================================================
 *
 * The End.
 *
 *======================================================================*/

} // namespace store

#endif /* !_STORE_STORCACH_HXX */

<commit_msg>INTEGRATION: CWS changefileheader (1.5.66); FILE MERGED 2008/04/01 15:42:43 thb 1.5.66.3: #i85898# Stripping all external header guards 2008/04/01 12:41:54 thb 1.5.66.2: #i85898# Stripping all external header guards 2008/03/31 15:27:47 rt 1.5.66.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: storcach.hxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _STORE_STORCACH_HXX
#define _STORE_STORCACH_HXX "$Revision: 1.6 $"

#include <sal/types.h>
#include <osl/mutex.hxx>
#include <store/types.h>

#ifndef INCLUDED_CSTDDEF
#include <cstddef>
#define INCLUDED_CSTDDEF
#endif

namespace store
{

struct OStorePageDescriptor;
struct OStorePageData;
class  OStorePageBIOS;

/*========================================================================
 *
 * OStorePageCache interface.
 * (OStorePageData in external representation)
 *
 *======================================================================*/
#define STORE_LIMIT_CACHEPAGES   256
#define STORE_DEFAULT_CACHEPAGES STORE_LIMIT_CACHEPAGES

struct OStorePageCacheEntry;

class OStorePageCache
{
    typedef OStorePageCacheEntry entry;

public:
    /** Allocation.
     */
    static void * operator new (std::size_t n) SAL_THROW(());
    static void   operator delete (void * p, std::size_t) SAL_THROW(());

    /** Construction.
    */
    OStorePageCache (
        sal_uInt16 nPages = STORE_DEFAULT_CACHEPAGES);

    /** Destruction.
    */
    ~OStorePageCache (void);

    /** load.
    */
    storeError load (
        const OStorePageDescriptor &rDescr,
        OStorePageData             &rData,
        OStorePageBIOS             &rBIOS,
        osl::Mutex                 *pMutex = NULL);

    /** update.
    */
    enum UpdateMode
    {
        UPDATE_WRITE_THROUGH = 0,
        UPDATE_WRITE_DELAYED = 1
    };

    storeError update (
        const OStorePageDescriptor &rDescr,
        const OStorePageData       &rData,
        OStorePageBIOS             &rBIOS,
        osl::Mutex                 *pMutex = NULL,
        UpdateMode                  eMode  = UPDATE_WRITE_THROUGH);

    /** invalidate.
    */
    storeError invalidate (
        const OStorePageDescriptor &rDescr,
        osl::Mutex                 *pMutex = NULL);

    /** flush.
    */
    storeError flush (
        OStorePageBIOS &rBIOS,
        osl::Mutex     *pMutex = NULL);

    /** hitRatio [nHit / (nHit + nMissed)].
     */
    inline double hitRatio (void) const;

    /** usageRatio [nUsed / nSize].
    */
    inline double usageRatio (void) const;

private:
    /** Representation.
    */
    sal_uInt16  m_nSize;
    sal_uInt16  m_nUsed;
    entry      *m_pData[STORE_LIMIT_CACHEPAGES];
    entry      *m_pHead;

    sal_uInt32  m_nHit;
    sal_uInt32  m_nMissed;
    sal_uInt32  m_nUpdHit;
    sal_uInt32  m_nUpdLRU;
    sal_uInt32  m_nWrtBack;

    /** Implementation.
    */
    sal_uInt16 find (const OStorePageDescriptor &rDescr) const;
    void       move (sal_uInt16 nSI, sal_uInt16 nDI);

    /** insert.
    */
    enum InsertMode
    {
        INSERT_CLEAN = 0,
        INSERT_DIRTY = 1
    };

    storeError insert (
        sal_uInt16                  nIndex,
        const OStorePageDescriptor &rDescr,
        const OStorePageData       &rData,
        OStorePageBIOS             &rBIOS,
        InsertMode                  eMode = INSERT_CLEAN);

    /** Not implemented.
    */
    OStorePageCache (const OStorePageCache& rOther);
    OStorePageCache& operator= (const OStorePageCache& rOther);
};

/*
 * hitRatio [nHit / (nHit + nMissed)].
 */
inline double OStorePageCache::hitRatio (void) const
{
    if (m_nHit || m_nMissed)
        return ((double)m_nHit / (double)(m_nHit + m_nMissed));
    else
        return 1.0;
}

/*
 * usageRatio [nUsed / nSize].
 */
inline double OStorePageCache::usageRatio (void) const
{
    if (m_nUsed < m_nSize)
        return ((double)m_nUsed / (double)m_nSize);
    else
        return 1.0;
}

/*========================================================================
 *
 * The End.
 *
 *======================================================================*/

} // namespace store

#endif /* !_STORE_STORCACH_HXX */

<|endoftext|>


<commit_before>#include <chord.h>
#include <modlogger.h>
#include <id_utils.h>
#include "merkle.h"
#include "merkle_tree_disk.h"
#include <location.h>
#include <transport_prot.h>
#include <comm.h>

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_server> server;
  ptr<asrv> srv;
} SERVER;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_syncer> syncer;
  ptr<aclnt> clnt;
} SYNCER;

vec<chordID> keys_for_server;
vec<chordID> keys_for_syncer;

str server_index = "/tmp/server.index.mrk";
str server_internal = "/tmp/server.internal.mrk";
str server_leaf = "/tmp/server.leaf.mrk";
str syncer_index = "/tmp/syncer.index.mrk";
str syncer_internal = "/tmp/syncer.internal.mrk";
str syncer_leaf = "/tmp/syncer.leaf.mrk";

static void
sendblock (bigint blockID, bool missingLocal)
{
  if (missingLocal)
    keys_for_syncer.push_back (blockID);
  else
    keys_for_server.push_back (blockID);
}

static void
doRPCcb (xdrproc_t proc, dorpc_res *res, aclnt_cb cb, void *out, clnt_stat err)
{
  xdrmem x ((char *)res->resok->results.base (),
	    res->resok->results.size (), XDR_DECODE);

  if (err) {
    warnx << "doRPC: err = " << err << "\n";
  } else if (!proc (x.xdrp (), out)) {
    warnx << "failed to unmarshall result\n";
    cb (RPC_CANTSEND);
    return;
  }
  cb (err);
  delete res;
}

// called by syncer to perform merkle RPC to server
static void
doRPC (RPC_delay_args *a)
{
  //form the transport RPC
  ptr<dorpc_arg> arg = New refcounted<dorpc_arg> ();
  // Other fields don't matter.
  arg->progno = a->prog.progno;
  arg->procno = a->procno;

  xdrproc_t inproc = a->prog.tbl[a->procno].xdr_arg;
  xdrproc_t outproc = a->prog.tbl[a->procno].xdr_res;
  assert (outproc);
  xdrsuio x (XDR_ENCODE);
  if ((!inproc) || (!inproc (x.xdrp (), (void *)a->in))) {
    fatal << "failed to marshall args\n";
  }
  int args_len = x.uio ()->resid ();
  arg->args.setsize (args_len);
  void *marshalled_args = suio_flatten (x.uio ());
  memcpy (arg->args.base (), marshalled_args, args_len);
  free (marshalled_args);

  dorpc_res *res = New dorpc_res (DORPC_OK);
  SYNCER.clnt->call (TRANSPORTPROC_DORPC, arg, res,
                     wrap (&doRPCcb, outproc, res, a->cb, a->out));
}

vec<const rpc_program *> handledProgs;
vec<cbdispatch_t> handlers;

static void
transport_dispatch (svccb *sbp)
{
  if (!sbp) {
    warnx << "transport server eof\n";
    return;
  }

  dorpc_arg *arg = sbp->Xtmpl getarg<dorpc_arg> ();

  chord_node_wire nw;
  bzero (&nw, sizeof (chord_node_wire));

  const rpc_program *prog (NULL);
  unsigned int i (0);
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (arg->progno == (int)handledProgs[i]->progno) {
      prog = handledProgs[i];
      break;
    }
  char *arg_base = (char *)(arg->args.base ());
  int arg_len = arg->args.size ();

  xdrmem x (arg_base, arg_len, XDR_DECODE);
  xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
  assert (proc);

  void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
  if (!proc (x.xdrp (), unmarshalled_args)) {
    warn << "dispatch: error unmarshalling arguments: "
	 << arg->progno << "." << arg->procno << "\n";
    xdr_delete (prog->tbl[arg->procno].xdr_arg, unmarshalled_args);
    sbp->replyref (rpcstat (DORPC_MARSHALLERR));
    return;
  }
  user_args *ua = New user_args (sbp, unmarshalled_args,
				 prog, arg->procno, 0);
  ua->me_ = New refcounted<location> (make_chord_node (nw));
  handlers[i] (ua);
}

// called by server to register handler fielding merkle RPCs
static void
addHandler (const rpc_program &prog, cbdispatch_t cb)
{
  handledProgs.push_back (&prog);
  handlers.push_back (cb);
}

void
finish ()
{
  // Force all destructors to be called, hopefully.
  handledProgs.clear ();
  handlers.clear ();

  SYNCER.syncer = NULL;
  SERVER.server = NULL;
  SYNCER.clnt = NULL;
  SERVER.srv  = NULL;
  SYNCER.tree = NULL;
  SERVER.tree = NULL;

  unlink (server_index);
  unlink (server_internal);
  unlink (server_leaf);

  unlink (syncer_index);
  unlink (syncer_internal);
  unlink (syncer_leaf);

}

void
setup ()
{
  warn << " => setup() +++++++++++++++++++++++++++\n";
  err_flush ();

  SERVER.tree = New refcounted<merkle_tree_disk> (server_index,
						  server_internal, server_leaf,
						  true);
  SYNCER.tree = New refcounted<merkle_tree_disk> (syncer_index,
						  syncer_internal, syncer_leaf,
						  true);

  // these are closed by axprt_stream's dtor, right?
  int fds[2];
  assert (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) == 0);
  warn << "sockets: " << fds[0] << ":" << fds[1] << "\n";
  SERVER.srv = asrv::alloc (axprt_stream::alloc (fds[0]), transport_program_1);
  SYNCER.clnt = aclnt::alloc (axprt_stream::alloc (fds[1]), transport_program_1);
  assert (SERVER.srv && SYNCER.clnt);
  SERVER.srv->setcb (wrap (&transport_dispatch));

  SYNCER.syncer = New refcounted<merkle_syncer> (0, DHASH_CONTENTHASH,
						 SYNCER.tree,
						 wrap (doRPC),
						 wrap (sendblock));
  SERVER.server = New refcounted<merkle_server> (SERVER.tree);
  addHandler(merklesync_program_1,
      wrap(SERVER.server, &merkle_server::dispatch));
  warn << " <= setup() DONE!\n";
  err_flush ();
}

void
addrand (ptr<merkle_tree> tr, int count)
{
  for (int i = 0; i < count; i++) {
    if (i == 40000)
      exit (0);

    merkle_hash key;
    key.randomize ();
    tr->insert (key);

    if ((i % 1000) == 0) {
      warn << "a) inserted " << i << " blocks..of " << count << "\n";
      err_flush ();
    }
  }
}

void
dump_stats ()
{
  warn << "\n\n=======================================================================\n";
  merkle_node *serv_root = SERVER.tree->get_root();
  merkle_node *sync_root = SYNCER.tree->get_root();
  warn << "SERVER.tree->root " << serv_root->hash << " cnt " << serv_root->count << "\n";
  warn << "SYNCER.tree->root " << sync_root->hash << " cnt " << sync_root->count << "\n";
  SERVER.tree->lookup_release(serv_root);
  SYNCER.tree->lookup_release(sync_root);

  warn  << "+++++++++++++++++++++++++SERVER.tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  SERVER.tree->check_invariants ();
  // SERVER.tree->dump ();
  warn  << "+++++++++++++++++++++++++SYNCER.tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  SYNCER.tree->check_invariants ();
  // SYNCER.tree->dump ();
}

void
test (uint progress, uint data_points)
{
  u_int64_t large_sz = (1 << 30) / (1 << 13);  // 1 GB
  large_sz /= 100;
  u_int64_t small_sz = (large_sz * progress) / (data_points - 1);

  warn << "\n\n\n\n############################################################\n";
  warn << "REPLICA TEST " << large_sz << "/" << small_sz << "\n";
  setup ();
  if (progress % 2) {
    addrand (SERVER.tree, large_sz);
    addrand (SYNCER.tree, small_sz);
  } else {
    addrand (SERVER.tree, small_sz);
    addrand (SYNCER.tree, large_sz);
  }

  warn  << "+++++++++++++++++++++++++server tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  warn  << "+++++++++++++++++++++++++syncer tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  err_flush();

  warn << "\n\n************************* RUNNING TEST ************************\n";
  bigint rngmin = 0;
  bigint rngmax = (bigint (1) << 160)  - 1;
  SYNCER.syncer->sync (rngmin, rngmax);

  while (!SYNCER.syncer->done ()) {
    acheck ();

    while (keys_for_server.size ()) {
      chordID k = keys_for_server.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SERVER.tree->insert (key);
    }
    while (keys_for_syncer.size ()) {
      chordID k = keys_for_syncer.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SYNCER.tree->insert (key);
    }
  }

  warn << "\n\n*********************** DONE *****************************\n";

  dump_stats ();
  finish ();
}

int
main (int argc, char *argv[])
{
  if (argc > 1)
    modlogger::setmaxprio (modlogger::TRACE);
  u_int start_point = 0;
  u_int data_points = 100;
  for (u_int i = start_point; i < data_points; i++)
    test (i, data_points);
}
<commit_msg>Improve and begin to refactor test_merkle_syncer.<commit_after>#include <chord.h>
#include <modlogger.h>
#include <id_utils.h>
#include "merkle.h"
#include "merkle_tree_disk.h"
#include <location.h>
#include <transport_prot.h>
#include <comm.h>

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_server> server;
  ptr<asrv> srv;
} SERVER;

static struct {
  ptr<merkle_tree> tree;
  ptr<merkle_syncer> syncer;
  ptr<aclnt> clnt;
} SYNCER;

vec<chordID> keys_for_server;
vec<chordID> keys_for_syncer;

str server_index = "/tmp/server.index.mrk";
str server_internal = "/tmp/server.internal.mrk";
str server_leaf = "/tmp/server.leaf.mrk";
str syncer_index = "/tmp/syncer.index.mrk";
str syncer_internal = "/tmp/syncer.internal.mrk";
str syncer_leaf = "/tmp/syncer.leaf.mrk";

static void
sendblock (bigint blockID, bool missingLocal)
{
  if (missingLocal)
    keys_for_syncer.push_back (blockID);
  else
    keys_for_server.push_back (blockID);
}

static void
doRPCcb (xdrproc_t proc, dorpc_res *res, aclnt_cb cb, void *out, clnt_stat err)
{
  xdrmem x ((char *)res->resok->results.base (),
	    res->resok->results.size (), XDR_DECODE);

  if (err) {
    warnx << "doRPC: err = " << err << "\n";
  } else if (!proc (x.xdrp (), out)) {
    warnx << "failed to unmarshall result\n";
    cb (RPC_CANTSEND);
    return;
  }
  cb (err);
  delete res;
}

// called by syncer to perform merkle RPC to server
static void
doRPC (RPC_delay_args *a)
{
  //form the transport RPC
  ptr<dorpc_arg> arg = New refcounted<dorpc_arg> ();
  // Other fields don't matter.
  arg->progno = a->prog.progno;
  arg->procno = a->procno;

  xdrproc_t inproc = a->prog.tbl[a->procno].xdr_arg;
  xdrproc_t outproc = a->prog.tbl[a->procno].xdr_res;
  assert (outproc);
  xdrsuio x (XDR_ENCODE);
  if ((!inproc) || (!inproc (x.xdrp (), (void *)a->in))) {
    fatal << "failed to marshall args\n";
  }
  int args_len = x.uio ()->resid ();
  arg->args.setsize (args_len);
  void *marshalled_args = suio_flatten (x.uio ());
  memcpy (arg->args.base (), marshalled_args, args_len);
  free (marshalled_args);

  dorpc_res *res = New dorpc_res (DORPC_OK);
  SYNCER.clnt->call (TRANSPORTPROC_DORPC, arg, res,
                     wrap (&doRPCcb, outproc, res, a->cb, a->out));
}

vec<const rpc_program *> handledProgs;
vec<cbdispatch_t> handlers;

static void
transport_dispatch (svccb *sbp)
{
  if (!sbp) {
    warnx << "transport server eof\n";
    return;
  }

  dorpc_arg *arg = sbp->Xtmpl getarg<dorpc_arg> ();

  chord_node_wire nw;
  bzero (&nw, sizeof (chord_node_wire));

  const rpc_program *prog (NULL);
  unsigned int i (0);
  for (unsigned int i = 0; i < handledProgs.size (); i++)
    if (arg->progno == (int)handledProgs[i]->progno) {
      prog = handledProgs[i];
      break;
    }
  char *arg_base = (char *)(arg->args.base ());
  int arg_len = arg->args.size ();

  xdrmem x (arg_base, arg_len, XDR_DECODE);
  xdrproc_t proc = prog->tbl[arg->procno].xdr_arg;
  assert (proc);

  void *unmarshalled_args = prog->tbl[arg->procno].alloc_arg ();
  if (!proc (x.xdrp (), unmarshalled_args)) {
    warn << "dispatch: error unmarshalling arguments: "
	 << arg->progno << "." << arg->procno << "\n";
    xdr_delete (prog->tbl[arg->procno].xdr_arg, unmarshalled_args);
    sbp->replyref (rpcstat (DORPC_MARSHALLERR));
    return;
  }
  user_args *ua = New user_args (sbp, unmarshalled_args,
				 prog, arg->procno, 0);
  ua->me_ = New refcounted<location> (make_chord_node (nw));
  handlers[i] (ua);
}

// called by server to register handler fielding merkle RPCs
static void
addHandler (const rpc_program &prog, cbdispatch_t cb)
{
  handledProgs.push_back (&prog);
  handlers.push_back (cb);
}

void
finish ()
{
  // Force all destructors to be called, hopefully.
  handledProgs.clear ();
  handlers.clear ();

  SYNCER.syncer = NULL;
  SERVER.server = NULL;
  SYNCER.clnt = NULL;
  SERVER.srv  = NULL;
  SYNCER.tree = NULL;
  SERVER.tree = NULL;

  unlink (server_index);
  unlink (server_internal);
  unlink (server_leaf);

  unlink (syncer_index);
  unlink (syncer_internal);
  unlink (syncer_leaf);

}

void
setup ()
{
  warn << " => setup() +++++++++++++++++++++++++++\n";
  err_flush ();

  SERVER.tree = New refcounted<merkle_tree_disk> (server_index,
						  server_internal, server_leaf,
						  true);
  SYNCER.tree = New refcounted<merkle_tree_disk> (syncer_index,
						  syncer_internal, syncer_leaf,
						  true);

  // these are closed by axprt_stream's dtor, right?
  int fds[2];
  assert (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) == 0);
  warn << "sockets: " << fds[0] << ":" << fds[1] << "\n";
  SERVER.srv = asrv::alloc (axprt_stream::alloc (fds[0]), transport_program_1);
  SYNCER.clnt = aclnt::alloc (axprt_stream::alloc (fds[1]), transport_program_1);
  assert (SERVER.srv && SYNCER.clnt);
  SERVER.srv->setcb (wrap (&transport_dispatch));

  SYNCER.syncer = New refcounted<merkle_syncer> (0, DHASH_CONTENTHASH,
						 SYNCER.tree,
						 wrap (doRPC),
						 wrap (sendblock));
  SERVER.server = New refcounted<merkle_server> (SERVER.tree);
  addHandler(merklesync_program_1,
      wrap(SERVER.server, &merkle_server::dispatch));
  warn << " <= setup() DONE!\n";
  err_flush ();
}

void
addrand (ptr<merkle_tree> tr, int count)
{
  for (int i = 0; i < count; i++) {
    if (i == 40000)
      exit (0);

    merkle_hash key;
    key.randomize ();
    tr->insert (key);

    if ((i % 1000) == 0) {
      warn << "a) inserted " << i << " blocks..of " << count << "\n";
      err_flush ();
    }
  }
}

void
dump_stats ()
{
  warn << "\n\n=======================================================================\n";
  merkle_node *serv_root = SERVER.tree->get_root();
  merkle_node *sync_root = SYNCER.tree->get_root();
  warn << "SERVER.tree->root " << serv_root->hash << " cnt " << serv_root->count << "\n";
  warn << "SYNCER.tree->root " << sync_root->hash << " cnt " << sync_root->count << "\n";
  if (serv_root->hash != sync_root->hash)
    fatal << "Roots do not match!\n";

  SERVER.tree->lookup_release(serv_root);
  SYNCER.tree->lookup_release(sync_root);

  warn  << "+++++++++++++++++++++++++SERVER.tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  SERVER.tree->check_invariants ();
  // SERVER.tree->dump ();
  warn  << "+++++++++++++++++++++++++SYNCER.tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  SYNCER.tree->check_invariants ();
  // SYNCER.tree->dump ();
}

void
joshtree (uint progress, uint data_points)
{
  u_int64_t large_sz = (1 << 30) / (1 << 13);  // 1 GB
  large_sz /= 100;
  u_int64_t small_sz = (large_sz * progress) / (data_points - 1);

  warn << "\n\n\n\n############################################################\n";
  warn << "REPLICA TEST " << large_sz << "/" << small_sz << "\n";
  setup ();
  if (progress % 2) {
    addrand (SERVER.tree, large_sz);
    addrand (SYNCER.tree, small_sz);
  } else {
    addrand (SERVER.tree, small_sz);
    addrand (SYNCER.tree, large_sz);
  }
}

void
test ()
{
  warn  << "+++++++++++++++++++++++++server tree++++++++++++++++++++++++++++++\n";
  SERVER.tree->compute_stats ();
  warn  << "+++++++++++++++++++++++++syncer tree++++++++++++++++++++++++++++++\n";
  SYNCER.tree->compute_stats ();
  err_flush();

  warn << "\n\n************************* RUNNING TEST ************************\n";
  bigint rngmin = 0;
  bigint rngmax = (bigint (1) << 160)  - 1;
  SYNCER.syncer->sync (rngmin, rngmax);

  while (!SYNCER.syncer->done ()) {
    acheck ();

    while (keys_for_server.size ()) {
      chordID k = keys_for_server.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SERVER.tree->insert (key);
    }
    while (keys_for_syncer.size ()) {
      chordID k = keys_for_syncer.pop_front ();
      merkle_hash key = to_merkle_hash (k);
      SYNCER.tree->insert (key);
    }
  }

  warn << "\n\n*********************** DONE *****************************\n";

  dump_stats ();
  finish ();
}

int
main (int argc, char *argv[])
{
  if (argc > 1)
    modlogger::setmaxprio (modlogger::TRACE);

  // Make sure no old state remains on disk.
  finish ();

  u_int start_point = 0;
  u_int data_points = 100;
  for (u_int i = start_point; i < data_points; i++) {
    joshtree (i, data_points);
    test ();
  }
}
<|endoftext|>


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

#include "tensorflow/lite/kernels/internal/reference/integer_ops/conv_accel_gen_2.h"

#include <cstdio>

#include "gateware_constants.h"
#include "hps_cfu.h"
#include "tensorflow/lite/kernels/internal/common.h"

#if GATEWARE_GEN == 2

namespace tflite {
namespace reference_integer_ops {

namespace {

// Loads Post process parameters into the CFU
void LoadPostProcessParameters(int output_depth, const int32_t* bias_data,
                               const int32_t* output_shift,
                               const int32_t* output_multiplier) {
  for (int i = 0; i < output_depth; i++) {
    cfu_set(REG_POST_PROCESS_BIAS, bias_data[i]);
    // Note : shift is stored as a negative number in tflite model
    cfu_set(REG_POST_PROCESS_SHIFT, -output_shift[i]);
    cfu_set(REG_POST_PROCESS_MULTIPLIER, output_multiplier[i]);
  }
}

// Loads filter parameters, correctly split between the two
// stores
void LoadFilterData(const RuntimeShape& filter_shape,
                    const int8_t* filter_data) {
  const int num_filter_words_per_output =
      filter_shape.Dims(1) * filter_shape.Dims(2) * filter_shape.Dims(3) / 4;
  const int num_output_channels = filter_shape.Dims(0);
  const uint32_t* filter_words = reinterpret_cast<const uint32_t*>(filter_data);

  size_t addr_base = 0;
  for (int chan = 0; chan < num_output_channels; chan += 2) {
    for (int store = 0; store < 2; store++) {
      for (int i = 0; i < num_filter_words_per_output; i++) {
        uint32_t data = *filter_words++;
        uint32_t addr = addr_base + i;
        cfu_setx(REG_FILTER_WRITE, (store << 16 | addr), data);
      }
    }
    addr_base += num_filter_words_per_output;
  }
}

};  // namespace

bool CanAccelerateConv4x4(const ConvParams& params,
                          const RuntimeShape& input_shape,
                          const RuntimeShape& filter_shape,
                          const RuntimeShape& output_shape,
                          const int32_t* bias_data) {
  // No padding allowed
  if (params.padding_type != PaddingType::kValid) return false;

  // Must have bias_data and single batch
  if (!bias_data) return false;
  const int batches = MatchingDim(input_shape, 0, output_shape, 0);
  if (batches != 1) return false;

  // Input and output depths must be a multiple of 16
  const int input_depth = input_shape.Dims(3);
  const int output_depth = output_shape.Dims(3);
  if (input_depth % 16 != 0) return false;
  if (output_depth % 16 != 0) return false;

  // Must be 4x4
  const int filter_height = filter_shape.Dims(1);
  const int filter_width = filter_shape.Dims(2);
  if (filter_height != 4 || filter_width != 4) return false;

  // Must fit in filter word storag   e
  const int num_filter_words = input_depth * output_depth * 4 * 4 / 4;
  if (num_filter_words > NUM_FILTER_STORES * FILTER_WORDS_PER_STORE)
    return false;

  // Dilation must be 1
  if (params.dilation_height_factor != 1 || params.dilation_width_factor != 1)
    return false;

  // Stride must be 1
  const int stride_width = params.stride_width;
  const int stride_height = params.stride_height;
  if (stride_height != 1 || stride_width != 1) return false;

  return true;
}

// Fixed-point per-channel-quantization convolution reference kernel.
void ConvPerChannel4x4(const ConvParams& params,
                       const int32_t* output_multiplier,
                       const int32_t* output_shift,
                       const RuntimeShape& input_shape,
                       const int8_t* input_data,
                       const RuntimeShape& filter_shape,
                       const int8_t* filter_data,
                       const RuntimeShape& bias_shape, const int32_t* bias_data,
                       const RuntimeShape& output_shape, int8_t* output_data) {
  // Get parameters.
  const int32_t input_offset = params.input_offset;  // r = s(q - Z)
  // TODO: handle stride
  // const int stride_width = params.stride_width;
  // const int stride_height = params.stride_height;
  // TODO: handle padding
  // const int pad_width = params.padding_values.width;
  // const int pad_height = params.padding_values.height;
  const int32_t output_offset = params.output_offset;

  // Set min and max value of the output.
  const int32_t output_activation_min = params.quantized_activation_min;
  const int32_t output_activation_max = params.quantized_activation_max;

  // Consistency checks
  TFLITE_DCHECK_LE(output_activation_min, output_activation_max);
  TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
  TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4);
  TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
  const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3);
  const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3);
  TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth);

  // Get dimensions of the tensors.
  const int input_width = input_shape.Dims(2);
  const int output_height = output_shape.Dims(1);
  const int output_width = output_shape.Dims(2);
  const int filter_size_words = filter_shape.FlatSize() / 4;
  const int num_output_values = output_shape.FlatSize();

  // TODO: Calculate in tranches limited by filter memory size

  // Base address is bank address (4 words per bank) within 256K arena
  uint32_t input_base_addr =
      (reinterpret_cast<uint32_t>(input_data) & 0x3ffff) / 16;

  // Reset to ensure important state is initialized
  cfu_set(REG_ACCELERATOR_RESET, 0);

  // Configure simple values
  cfu_set(REG_INPUT_OFFSET, input_offset);
  cfu_set(REG_NUM_FILTER_WORDS, filter_size_words / 2);
  cfu_set(REG_OUTPUT_OFFSET, output_offset);
  cfu_set(REG_OUTPUT_ACTIVATION_MIN, output_activation_min);
  cfu_set(REG_OUTPUT_ACTIVATION_MAX, output_activation_max);
  cfu_set(REG_INPUT_BASE_ADDR, input_base_addr);
  cfu_set(REG_NUM_PIXELS_X, output_width);
  cfu_set(REG_PIXEL_ADVANCE_X, input_depth / 16);
  cfu_set(REG_PIXEL_ADVANCE_Y, (input_depth / 16) * input_width);
  cfu_set(REG_NUM_REPEATS, output_depth / SYS_ARRAY_WIDTH);
  cfu_set(REG_OUTPUT_CHANNEL_DEPTH, output_depth);
  cfu_set(REG_NUM_OUTPUT_VALUES, num_output_values);

  LoadPostProcessParameters(output_depth, bias_data, output_shift,
                            output_multiplier);
  LoadFilterData(filter_shape, filter_data);

  // Start Accelerator
  cfu_set(REG_ACCELERATOR_START, 0);

  // Collect data for groups of four pixels
  // TODO: handle number of pixels not being a multiple of 4
  const int num_output_pixels = output_height * output_width;
  const int num_groups = num_output_pixels / 4;
  const int num_words_per_output_pixel = output_depth / 4;
  uint32_t* output_words = reinterpret_cast<uint32_t*>(output_data);
  uint32_t* group_base = output_words;
  for (int group = 0; group < num_groups; group++) {
    uint32_t* g0 = group_base;
    uint32_t* g1 = g0 + num_words_per_output_pixel;
    uint32_t* g2 = g1 + num_words_per_output_pixel;
    uint32_t* g3 = g2 + num_words_per_output_pixel;
    for (int word = 0; word < num_words_per_output_pixel; word++) {
      *g0++ = cfu_get(REG_OUTPUT_WORD);
      *g1++ = cfu_get(REG_OUTPUT_WORD);
      *g2++ = cfu_get(REG_OUTPUT_WORD);
      *g3++ = cfu_get(REG_OUTPUT_WORD);
    }
    group_base += num_words_per_output_pixel * 4;
  }
}

}  // namespace reference_integer_ops
}  // namespace tflite
#endif  // GATEWARE_GEN
<commit_msg>hps_accel/conv_accel_gen_2.cc: fix gating<commit_after>/*
 * Copyright 2021 The CFU-Playground Authors
 * Copyright 2019 The TensorFlow Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "tensorflow/lite/kernels/internal/reference/integer_ops/conv_accel_gen_2.h"

#include <cstdio>

#include "gateware_constants.h"
#include "hps_cfu.h"
#include "tensorflow/lite/kernels/internal/common.h"

#if GATEWARE_GEN == 2

namespace tflite {
namespace reference_integer_ops {

namespace {

// Loads Post process parameters into the CFU
void LoadPostProcessParameters(int output_depth, const int32_t* bias_data,
                               const int32_t* output_shift,
                               const int32_t* output_multiplier) {
  for (int i = 0; i < output_depth; i++) {
    cfu_set(REG_POST_PROCESS_BIAS, bias_data[i]);
    // Note : shift is stored as a negative number in tflite model
    cfu_set(REG_POST_PROCESS_SHIFT, -output_shift[i]);
    cfu_set(REG_POST_PROCESS_MULTIPLIER, output_multiplier[i]);
  }
}

// Loads filter parameters, correctly split between the two
// stores
void LoadFilterData(const RuntimeShape& filter_shape,
                    const int8_t* filter_data) {
  const int num_filter_words_per_output =
      filter_shape.Dims(1) * filter_shape.Dims(2) * filter_shape.Dims(3) / 4;
  const int num_output_channels = filter_shape.Dims(0);
  const uint32_t* filter_words = reinterpret_cast<const uint32_t*>(filter_data);

  size_t addr_base = 0;
  for (int chan = 0; chan < num_output_channels; chan += 2) {
    for (int store = 0; store < 2; store++) {
      for (int i = 0; i < num_filter_words_per_output; i++) {
        uint32_t data = *filter_words++;
        uint32_t addr = addr_base + i;
        cfu_setx(REG_FILTER_WRITE, (store << 16 | addr), data);
      }
    }
    addr_base += num_filter_words_per_output;
  }
}

};  // namespace

bool CanAccelerateConv4x4(const ConvParams& params,
                          const RuntimeShape& input_shape,
                          const RuntimeShape& filter_shape,
                          const RuntimeShape& output_shape,
                          const int32_t* bias_data) {
  // No padding allowed
  if (params.padding_type != PaddingType::kValid) return false;

  // Must have bias_data and single batch
  if (!bias_data) return false;
  const int batches = MatchingDim(input_shape, 0, output_shape, 0);
  if (batches != 1) return false;

  // Input and output depths must be a multiple of 16
  // NB: We could probably relax output depth to be a multiple of 4
  const int input_depth = input_shape.Dims(3);
  const int output_depth = output_shape.Dims(3);
  // if (input_depth % 16 != 0) return false;
  // if (output_depth % 16 != 0) return false;
  // Currently, only works where input and output depths are exactly 16
  if (input_depth != 16) return false;
  if (output_depth != 16) return false;

  // Must be 4x4
  const int filter_height = filter_shape.Dims(1);
  const int filter_width = filter_shape.Dims(2);
  if (filter_height != 4 || filter_width != 4) return false;

  // Must fit in filter word storag   e
  const int num_filter_words = input_depth * output_depth * 4 * 4 / 4;
  if (num_filter_words > NUM_FILTER_STORES * FILTER_WORDS_PER_STORE)
    return false;

  // Dilation must be 1
  if (params.dilation_height_factor != 1 || params.dilation_width_factor != 1)
    return false;

  // Stride must be 1
  const int stride_width = params.stride_width;
  const int stride_height = params.stride_height;
  if (stride_height != 1 || stride_width != 1) return false;

  return true;
}

// Fixed-point per-channel-quantization convolution reference kernel.
void ConvPerChannel4x4(const ConvParams& params,
                       const int32_t* output_multiplier,
                       const int32_t* output_shift,
                       const RuntimeShape& input_shape,
                       const int8_t* input_data,
                       const RuntimeShape& filter_shape,
                       const int8_t* filter_data,
                       const RuntimeShape& bias_shape, const int32_t* bias_data,
                       const RuntimeShape& output_shape, int8_t* output_data) {
  // Get parameters.
  const int32_t input_offset = params.input_offset;  // r = s(q - Z)
  // TODO: handle stride
  // const int stride_width = params.stride_width;
  // const int stride_height = params.stride_height;
  // TODO: handle padding
  // const int pad_width = params.padding_values.width;
  // const int pad_height = params.padding_values.height;
  const int32_t output_offset = params.output_offset;

  // Set min and max value of the output.
  const int32_t output_activation_min = params.quantized_activation_min;
  const int32_t output_activation_max = params.quantized_activation_max;

  // Consistency checks
  TFLITE_DCHECK_LE(output_activation_min, output_activation_max);
  TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
  TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4);
  TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
  const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3);
  const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3);
  TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth);

  // Get dimensions of the tensors.
  const int input_width = input_shape.Dims(2);
  const int output_height = output_shape.Dims(1);
  const int output_width = output_shape.Dims(2);
  const int filter_size_words = filter_shape.FlatSize() / 4;
  const int num_output_values = output_shape.FlatSize();

  // TODO: Calculate in tranches limited by filter memory size

  // Base address is bank address (4 words per bank) within 256K arena
  uint32_t input_base_addr =
      (reinterpret_cast<uint32_t>(input_data) & 0x3ffff) / 16;

  // Reset to ensure important state is initialized
  cfu_set(REG_ACCELERATOR_RESET, 0);

  // Configure simple values
  cfu_set(REG_INPUT_OFFSET, input_offset);
  cfu_set(REG_NUM_FILTER_WORDS, filter_size_words / 2);
  cfu_set(REG_OUTPUT_OFFSET, output_offset);
  cfu_set(REG_OUTPUT_ACTIVATION_MIN, output_activation_min);
  cfu_set(REG_OUTPUT_ACTIVATION_MAX, output_activation_max);
  cfu_set(REG_INPUT_BASE_ADDR, input_base_addr);
  cfu_set(REG_NUM_PIXELS_X, output_width);
  cfu_set(REG_PIXEL_ADVANCE_X, input_depth / 16);
  cfu_set(REG_PIXEL_ADVANCE_Y, (input_depth / 16) * input_width);
  cfu_set(REG_NUM_REPEATS, output_depth / SYS_ARRAY_WIDTH);
  cfu_set(REG_OUTPUT_CHANNEL_DEPTH, output_depth);
  cfu_set(REG_NUM_OUTPUT_VALUES, num_output_values);

  LoadPostProcessParameters(output_depth, bias_data, output_shift,
                            output_multiplier);
  LoadFilterData(filter_shape, filter_data);

  // Start Accelerator
  cfu_set(REG_ACCELERATOR_START, 0);

  // Collect data for groups of four pixels
  // TODO: handle number of pixels not being a multiple of 4
  const int num_output_pixels = output_height * output_width;
  const int num_groups = num_output_pixels / 4;
  const int num_words_per_output_pixel = output_depth / 4;
  uint32_t* output_words = reinterpret_cast<uint32_t*>(output_data);
  uint32_t* group_base = output_words;
  for (int group = 0; group < num_groups; group++) {
    uint32_t* g0 = group_base;
    uint32_t* g1 = g0 + num_words_per_output_pixel;
    uint32_t* g2 = g1 + num_words_per_output_pixel;
    uint32_t* g3 = g2 + num_words_per_output_pixel;
    for (int word = 0; word < num_words_per_output_pixel; word++) {
      *g0++ = cfu_get(REG_OUTPUT_WORD);
      *g1++ = cfu_get(REG_OUTPUT_WORD);
      *g2++ = cfu_get(REG_OUTPUT_WORD);
      *g3++ = cfu_get(REG_OUTPUT_WORD);
    }
    group_base += num_words_per_output_pixel * 4;
  }
}

}  // namespace reference_integer_ops
}  // namespace tflite
#endif  // GATEWARE_GEN
<|endoftext|>


<commit_before>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include "ParallelLoop.hpp"

#include <boost/test/unit_test.hpp>

#include "Grappa.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "CompletionEvent.hpp"
#include "ConditionVariable.hpp"
#include "Delegate.hpp"
#include "Tasking.hpp"
#include "GlobalAllocator.hpp"

BOOST_AUTO_TEST_SUITE( New_loop_tests );

using namespace Grappa;
using Grappa::wait;

static bool touched = false;

void test_on_all_cores() {
  BOOST_MESSAGE("Testing on_all_cores...");

  on_all_cores([] {
    BOOST_MESSAGE("hello world from " << mycore() << "!");
    touched = true;
  });

  BOOST_CHECK_EQUAL(delegate::read(make_global(&touched,1)), true);
  BOOST_CHECK_EQUAL(touched, true);
}

void test_loop_decomposition() {
  int N = 16;

  CompletionEvent ce(N);

  impl::loop_decomposition_private<2>(0, N, [&ce](int64_t start, int64_t iters) {
    VLOG(1) << "loop(" << start << ", " << iters << ")";
    ce.complete(iters);
  });
  ce.wait();
}

void test_loop_decomposition_global() {
  int N = 16;

  CompletionEvent ce(N);
  auto ce_addr = make_global(&ce);

  impl::loop_decomposition_public(0, N, [ce_addr](int64_t start, int64_t iters) {
    VLOG(1) << "loop(" << start << ", " << iters << ")";
    complete(ce_addr,iters);
  });
  ce.wait();
}

CompletionEvent my_ce;

void test_forall_here() {
  BOOST_MESSAGE("Testing forall_here...");
  const int N = 15;

  {
    int x = 0;
    forall_here(0, N, [&x](int64_t start, int64_t iters) {
      CHECK(mycore() == 0);
      for (int64_t i=0; i<iters; i++) {
        x++;
      }
    });
    BOOST_CHECK_EQUAL(x, N);
  }

  {
    int x = 0;
    forall_here<&my_ce,2>(0, N, [&x](int64_t start, int64_t iters) {
      CHECK(mycore() == 0);
      for (int64_t i=0; i<iters; i++) {
        x++;
      }
    });
    BOOST_CHECK_EQUAL(x, N);
  }

}

static int test_global = 0;
CompletionEvent test_global_ce;

void test_forall_global() {
  BOOST_MESSAGE("Testing forall_global...");
  const int64_t N = 1 << 8;

  forall_global_private(0, N, [](int64_t start, int64_t iters) {
    for (int i=0; i<iters; i++) {
      test_global++;
    }
  });

  on_all_cores([]{
    BOOST_CHECK_EQUAL(test_global, N/cores());
    test_global = 0;
  });

  forall_global_private<&test_global_ce>(0, N, [](int64_t start, int64_t iters) {
    for (int i=0; i<iters; i++) {
      test_global++;
    }
  });

}

void test_forall_localized() {
  BOOST_MESSAGE("Testing forall_localized...");
  const int64_t N = 1 << 8;

  auto array = Grappa_typed_malloc<int64_t>(N);

  forall_localized(array, N, [](int64_t i, int64_t& e){
    e = 1;
  });

  forall_here(0, N, [array](int64_t s, int64_t n) {
    for (int i=s; i<s+n; i++) { BOOST_CHECK_EQUAL(delegate::read(array+i), 1); }
  });
}

void user_main(void * args) {
  CHECK(Grappa::cores() >= 2); // at least 2 nodes for these tests...

  test_on_all_cores();

  test_loop_decomposition();
  test_loop_decomposition_global();

  test_forall_here();
  test_forall_global();

  test_forall_localized();
}

BOOST_AUTO_TEST_CASE( test1 ) {

  Grappa_init( &(boost::unit_test::framework::master_test_suite().argc),
	       &(boost::unit_test::framework::master_test_suite().argv)
	       );

  Grappa_activate();

  Grappa_run_user_main( &user_main, (void*)NULL );

  Grappa_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Do loop check serially (problem running out of tasks to receive)<commit_after>
// Copyright 2010-2012 University of Washington. All Rights Reserved.
// LICENSE_PLACEHOLDER
// This software was created with Government support under DE
// AC05-76RL01830 awarded by the United States Department of
// Energy. The Government has certain rights in the software.

#include "ParallelLoop.hpp"

#include <boost/test/unit_test.hpp>

#include "Grappa.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "CompletionEvent.hpp"
#include "ConditionVariable.hpp"
#include "Delegate.hpp"
#include "Tasking.hpp"
#include "GlobalAllocator.hpp"

BOOST_AUTO_TEST_SUITE( New_loop_tests );

using namespace Grappa;
using Grappa::wait;

static bool touched = false;

void test_on_all_cores() {
  BOOST_MESSAGE("Testing on_all_cores...");

  on_all_cores([] {
    BOOST_MESSAGE("hello world from " << mycore() << "!");
    touched = true;
  });

  BOOST_CHECK_EQUAL(delegate::read(make_global(&touched,1)), true);
  BOOST_CHECK_EQUAL(touched, true);
}

void test_loop_decomposition() {
  int N = 16;

  CompletionEvent ce(N);

  impl::loop_decomposition_private<2>(0, N, [&ce](int64_t start, int64_t iters) {
    VLOG(1) << "loop(" << start << ", " << iters << ")";
    ce.complete(iters);
  });
  ce.wait();
}

void test_loop_decomposition_global() {
  int N = 16;

  CompletionEvent ce(N);
  auto ce_addr = make_global(&ce);

  impl::loop_decomposition_public(0, N, [ce_addr](int64_t start, int64_t iters) {
    VLOG(1) << "loop(" << start << ", " << iters << ")";
    complete(ce_addr,iters);
  });
  ce.wait();
}

CompletionEvent my_ce;

void test_forall_here() {
  BOOST_MESSAGE("Testing forall_here...");
  const int N = 15;

  {
    int x = 0;
    forall_here(0, N, [&x](int64_t start, int64_t iters) {
      CHECK(mycore() == 0);
      for (int64_t i=0; i<iters; i++) {
        x++;
      }
    });
    BOOST_CHECK_EQUAL(x, N);
  }

  {
    int x = 0;
    forall_here<&my_ce,2>(0, N, [&x](int64_t start, int64_t iters) {
      CHECK(mycore() == 0);
      for (int64_t i=0; i<iters; i++) {
        x++;
      }
    });
    BOOST_CHECK_EQUAL(x, N);
  }

}

static int test_global = 0;
CompletionEvent test_global_ce;

void test_forall_global() {
  BOOST_MESSAGE("Testing forall_global...");
  const int64_t N = 1 << 8;

  forall_global_private(0, N, [](int64_t start, int64_t iters) {
    for (int i=0; i<iters; i++) {
      test_global++;
    }
  });

  on_all_cores([]{
    BOOST_CHECK_EQUAL(test_global, N/cores());
    test_global = 0;
  });

  forall_global_private<&test_global_ce>(0, N, [](int64_t start, int64_t iters) {
    for (int i=0; i<iters; i++) {
      test_global++;
    }
  });

}

void test_forall_localized() {
  BOOST_MESSAGE("Testing forall_localized...");
  const int64_t N = 1 << 8;

  auto array = Grappa_typed_malloc<int64_t>(N);

  forall_localized(array, N, [](int64_t i, int64_t& e){
    e = 1;
  });
  for (int i=0; i<N; i++) {
    BOOST_CHECK_EQUAL(delegate::read(array+i), 1);
  }
}

void user_main(void * args) {
  CHECK(Grappa::cores() >= 2); // at least 2 nodes for these tests...

  test_on_all_cores();

  test_loop_decomposition();
  test_loop_decomposition_global();

  test_forall_here();
  test_forall_global();

  test_forall_localized();
}

BOOST_AUTO_TEST_CASE( test1 ) {

  Grappa_init( &(boost::unit_test::framework::master_test_suite().argc),
	       &(boost::unit_test::framework::master_test_suite().argv)
	       );

  Grappa_activate();

  Grappa_run_user_main( &user_main, (void*)NULL );

  Grappa_finish( 0 );
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
    Copyright (c) 2013 <benemorius@gmail.com>

    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.
*/

#include "ObcCode.h"
#include <ObcUI.h>

using namespace ObcCodeState;

ObcCode::ObcCode(OpenOBC& obc) : ObcUITask(obc)
{
	registerButton(ObcUITaskFocus::background, BUTTON_CODE_MASK);
	setDisplayRefreshPeriod(0.100);
	setDisplay("ObcCode");
	state = CodeInactive;
}

ObcCode::~ObcCode()
{

}

void ObcCode::runTask()
{
	if(isActive())
	{
// 		DEBUG("running, ACTIVE\r\n");
	}
	else
	{
// 		DEBUG("running, INACTIVE\r\n");
	}
}

void ObcCode::wake()
{
	DEBUG("wake\r\n");
    if((state == CodeArmed) || (state == CodePrompt))
	{
		state = CodePrompt;
		codeSet = 0;
		setDisplay("input code: %04i", codeSet);
		obc.ui->setActiveTask(this);
	}
}

void ObcCode::sleep()
{
	DEBUG("sleep\r\n");
	if((state == CodeArmed) || (state == CodePrompt))
	{
		state = CodeArmed;
		obc.ews->on();
	}
}

void ObcCode::buttonHandler(ObcUITaskFocus::type focus, uint32_t buttonMask)
{
// 	DEBUG("buttonHandler\r\n");
	if(focus == ObcUITaskFocus::background)
	{
		if(buttonMask == BUTTON_CODE_MASK)
			obc.ui->setActiveTask(this);
		return;
	}

	if(state == CodeSet)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			code = codeSet;
			state = CodeActive;
			setDisplay("code active");
			obc.codeLed->on();
		}
		if(buttonMask == BUTTON_CODE_MASK)
		{
			state = CodeInactive;
			setDisplay("code inactive");
			obc.codeLed->off();
		}
	}

	else if(state == CodeActive)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			state = CodeSet;
			codeSet = code;
			setDisplay("set code: %04i", codeSet);
		}
	}

	else if(state == CodeInactive)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			state = CodeSet;
			codeSet = code;
			setDisplay("set code: %04i", codeSet);
		}
	}

	else if(state == CodePrompt)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			if(code == codeSet)
			{
				state = CodeActive;
				setDisplay("code accepted");
				obc.ews->off();
			}
			else
			{
				setDisplay("code invalid: %04i", codeSet);
				codeSet = 0;
			}
		}
	}

	if((state == CodeSet) || (state == CodePrompt))
	{
		if(buttonMask == BUTTON_1000_MASK)
		{
			codeSet += 1000;
		}
		if(buttonMask == BUTTON_100_MASK)
		{
			codeSet += 100;
		}
		if(buttonMask == BUTTON_10_MASK)
		{
			codeSet += 10;
		}
		if(buttonMask == BUTTON_1_MASK)
		{
			codeSet += 1;
		}

		codeSet %= 10000;
		setDisplay("input code: %04i", codeSet);
	}
}
<commit_msg>new ObcCode task maybe mostly working, but not fully tested<commit_after>/*
    Copyright (c) 2013 <benemorius@gmail.com>

    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.
*/

#include "ObcCode.h"
#include <ObcUI.h>
#include <cstdlib>

using namespace ObcCodeState;

ObcCode::ObcCode(OpenOBC& obc) : ObcUITask(obc)
{
	registerButton(ObcUITaskFocus::background, BUTTON_CODE_MASK);
	setDisplayRefreshPeriod(0.100);

	//restore state from config //TODO relying on the sd card for this is bad
	code = atof(obc.config->getValueByName("ObcCode").c_str());
	std::string stateConfig = obc.config->getValueByName("ObcCodeState");
	if(stateConfig == "CodeActive")
	{
		state = CodeActive;
		setDisplay("code active");
		obc.codeLed->on();
	}
	else if((stateConfig == "CodeArmed") || (stateConfig == "CodePrompt"))
	{
		state = CodeArmed;
		obc.codeLed->on();
		obc.ews->on();
	}
	else
	{
		state = CodeInactive;
		setDisplay("code inactive");
		obc.ews->off();
		obc.codeLed->off();
	}
}

ObcCode::~ObcCode()
{

}

void ObcCode::runTask()
{
	if(isActive())
	{
// 		DEBUG("running, ACTIVE\r\n");
	}
	else
	{
// 		DEBUG("running, INACTIVE\r\n");
	}
}

void ObcCode::wake()
{
// 	DEBUG("wake\r\n");
    if((state == CodeArmed) || (state == CodePrompt))
	{
		state = CodePrompt;
		codeSet = 0;
		setDisplay("input code: %04u", codeSet);
		obc.ui->setActiveTask(this);
	}
}

void ObcCode::sleep()
{
// 	DEBUG("sleep\r\n");
	if((state == CodeArmed) || (state == CodePrompt) || (state == CodeActive))
	{
		state = CodeArmed;
		obc.codeLed->on();
		obc.ews->on();
	}

	//store state to config
	char* codeBuffer = new char[5];
	snprintf(codeBuffer, 5, "%04u", code);
	obc.config->setValueByName("ObcCode", codeBuffer);
	delete[] codeBuffer;
	if((state == CodeInactive) || (state == CodeSet))
		obc.config->setValueByName("ObcCodeState", "CodeInactive");
	else if((state == CodeActive) || (state == CodeArmed) || (state == CodePrompt))
		obc.config->setValueByName("ObcCodeState", "CodeArmed");
}

void ObcCode::buttonHandler(ObcUITaskFocus::type focus, uint32_t buttonMask)
{
// 	DEBUG("buttonHandler\r\n");
	if(focus == ObcUITaskFocus::background)
	{
		if(buttonMask == BUTTON_CODE_MASK)
			obc.ui->setActiveTask(this);
		return;
	}

	if(state == CodeSet)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			code = codeSet;
			state = CodeActive;
			setDisplay("code active");
			obc.codeLed->on();
		}
		if(buttonMask == BUTTON_CODE_MASK)
		{
			state = CodeInactive;
			setDisplay("code inactive");
			obc.codeLed->off();
		}
	}

	else if(state == CodeActive)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			state = CodeSet;
			codeSet = code;
			setDisplay("set code: %04u", codeSet);
		}
	}

	else if(state == CodeInactive)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			state = CodeSet;
			codeSet = 0;
			setDisplay("set code: %04u", codeSet);
		}
	}

	else if(state == CodePrompt)
	{
		if(buttonMask == BUTTON_SET_MASK)
		{
			if(code == codeSet)
			{
				state = CodeActive;
				setDisplay("code accepted");
				obc.ews->off();
			}
			else
			{
				setDisplay("code invalid: %04u", codeSet);
				codeSet = 0;
			}
		}
	}

	if(((state == CodeSet) || (state == CodePrompt)) && (buttonMask & (BUTTON_1000_MASK | BUTTON_100_MASK | BUTTON_10_MASK | BUTTON_1_MASK)))
	{
		if(buttonMask == BUTTON_1000_MASK)
		{
			codeSet += 1000;
		}
		if(buttonMask == BUTTON_100_MASK)
		{
			codeSet += 100;
		}
		if(buttonMask == BUTTON_10_MASK)
		{
			codeSet += 10;
		}
		if(buttonMask == BUTTON_1_MASK)
		{
			codeSet += 1;
		}

		codeSet %= 10000;
		if(state == CodeSet)
			setDisplay("set code: %04u", codeSet);
		else if(state == CodePrompt)
			setDisplay("input code: %04u", codeSet);
	}
}
<|endoftext|>


<commit_before>#include <cvd/fast_corner.h>

#include <vector>
#include <list>
#include <cvd/utility.h>
using namespace CVD;
using namespace std;
#include <emmintrin.h>

#include "cvd_src/fast/prototypes.h"
#include "cvd_src/faster_corner_utilities.h"
namespace CVD
{
    #include "cvd_src/corner_12.h"

    template <int I, int N> struct BitCheck {
	template <class C> static inline void eval(unsigned int three, const byte* p, const int w, const int barrier, C& corners) {
	    const int BIT = 1<<I;
	    if (three & BIT) {
		if (three & (BIT << 16)) {
		    if (is_corner_12<Greater>(p, w, *p+barrier))
			corners.push_back(p);
		} else {
		    if (is_corner_12<Less>(p, w, *p-barrier))
			corners.push_back(p);
		}
	    }
	    BitCheck<I+1,N>::eval(three, p+1, w, barrier, corners);
	}
    };

    template <int N> struct BitCheck<N,N> {
	template <class C> static inline void eval(unsigned int three, const byte* p, const int w, const int barrier, C& corners) {}
    };

    template <int CHUNKS, class C> inline void process_16(unsigned int three, const byte* p, const int w, const int barrier, C& corners)
    {
	three |= (three >> 16);
	const int BITS = 16/CHUNKS;
	const int mask = ((1<<BITS)-1);
	for (int i=0; i<CHUNKS; ++i) {
	    if (three & mask)
		BitCheck<0,BITS>::eval(three, p, w, barrier, corners);
	    p += BITS;
	    three >>= BITS;
	}
    }

    template <bool Aligned> void faster_corner_detect_12(const BasicImage<byte>& I, std::vector<ImageRef>& corners, int barrier)
    {
	const int w = I.size().x;
	const int stride = 3*w;
	typedef std::list<const byte*> Passed;
	Passed passed;

	// The compiler refuses to reserve a register for this,
	// even though xmm6 and xmm7 go unused.
	// It loads it from memory each time.  I am stymied.
	register const __m128i barriers = _mm_set1_epi8((byte)barrier);

	for (int i=3; i<I.size().y-3; ++i) {
	    const byte* p = I[i];
	    for (int j=0; j<w/16; ++j, p+=16) {
		__m128i lo, hi;
		{
		    const __m128i here = load_si128<Aligned>((const __m128i*)(p));
		    lo = _mm_subs_epu8(here, barriers);
		    hi = _mm_adds_epu8(barriers, here);
		}
		const __m128i above = load_si128<Aligned>((const __m128i*)(p-stride));
		const __m128i below = load_si128<Aligned>((const __m128i*)(p+stride));
		unsigned int up_flags, down_flags;
		CHECK_BARRIER(lo, hi, above, up_flags);
		CHECK_BARRIER(lo, hi, below, down_flags);
		const unsigned int either_ud = up_flags | down_flags;
		if (either_ud) {
		    unsigned int left_flags;
		    {
			const __m128i other = _mm_loadu_si128((const __m128i*)(p-3));
			CHECK_BARRIER(lo, hi, other, left_flags);
		    }
		    const unsigned int both_ud = up_flags & down_flags;
		    if (both_ud | (either_ud&left_flags)) {
			unsigned int right_flags;
			{
			    const __m128i other = _mm_loadu_si128((const __m128i*)(p+3));
			    CHECK_BARRIER(lo, hi, other, right_flags);
			}
			const unsigned int at_least_three = (either_ud & (left_flags & right_flags)) | (both_ud & (left_flags | right_flags));
			if (at_least_three) {
			    process_16<4>(at_least_three, p, w, barrier, passed);
			}
		    }
		}
	    }
	    passed.push_back(0);
	}
	corners.reserve(passed.size());
	int row = 3;
	const byte* row_start = I[3];
	for (Passed::iterator it = passed.begin(); it != passed.end(); ++it) {
	    if (*it == 0) {
		row_start=I[++row];
		continue;
	    }
	    int x = *it - row_start;
	    if (x > 2 && x < w-3)
		corners.push_back(ImageRef(x, row));
	}
    }

    void fast_corner_detect_12(const BasicImage<byte>& I, std::vector<ImageRef>& corners, int barrier)
    {
	if (I.size().x < 22) {
	    fast_corner_detect_plain_12(I,corners,barrier);
	    return;
	} else if (I.size().x < 22 || I.size().y < 7)
	    return;

	if (is_aligned<16>(I[0]) && is_aligned<16>(I[1]))
	    faster_corner_detect_12<true>(I, corners, barrier);
	else
	    faster_corner_detect_12<false>(I, corners, barrier);
    }
}

<commit_msg>Fixed most of the problems in FAST-12 (is_corner_12 takes pointer, width and barrier. It computes *p+b or *p-b itself).<commit_after>#include <cvd/fast_corner.h>

#include <vector>
#include <list>
#include <cvd/utility.h>
using namespace CVD;
using namespace std;
#include <emmintrin.h>

#include "cvd_src/fast/prototypes.h"
#include "cvd_src/faster_corner_utilities.h"
namespace CVD
{
    #include "cvd_src/corner_12.h"

    template <int I, int N> struct BitCheck {
	template <class C> static inline void eval(unsigned int three, const byte* p, const int w, const int barrier, C& corners) {
	    const int BIT = 1<<I;
	    if (three & BIT) {
		if (three & (BIT << 16)) {
		    if (is_corner_12<Greater>(p, w, barrier))
			corners.push_back(p);
		} else {
		    if (is_corner_12<Less>(p, w, barrier))
			corners.push_back(p);
		}
	    }
	    BitCheck<I+1,N>::eval(three, p+1, w, barrier, corners);
	}
    };

    template <int N> struct BitCheck<N,N> {
	template <class C> static inline void eval(unsigned int three, const byte* p, const int w, const int barrier, C& corners) {}
    };

    template <int CHUNKS, class C> inline void process_16(unsigned int three, const byte* p, const int w, const int barrier, C& corners)
    {
	three |= (three >> 16);
	const int BITS = 16/CHUNKS;
	const int mask = ((1<<BITS)-1);
	for (int i=0; i<CHUNKS; ++i) {
	    if (three & mask)
		BitCheck<0,BITS>::eval(three, p, w, barrier, corners);
	    p += BITS;
	    three >>= BITS;
	}
    }

    template <bool Aligned> void faster_corner_detect_12(const BasicImage<byte>& I, std::vector<ImageRef>& corners, int barrier)
    {
	const int w = I.size().x;
	const int stride = 3*w;
	typedef std::list<const byte*> Passed;
	Passed passed;

	// The compiler refuses to reserve a register for this,
	// even though xmm6 and xmm7 go unused.
	// It loads it from memory each time.  I am stymied.
	register const __m128i barriers = _mm_set1_epi8((byte)barrier);

	for (int i=3; i<I.size().y-3; ++i) {
	    const byte* p = I[i];
	    for (int j=0; j<w/16; ++j, p+=16) {
		__m128i lo, hi;
		{
		    const __m128i here = load_si128<Aligned>((const __m128i*)(p));
		    lo = _mm_subs_epu8(here, barriers);
		    hi = _mm_adds_epu8(barriers, here);
		}
		const __m128i above = load_si128<Aligned>((const __m128i*)(p-stride));
		const __m128i below = load_si128<Aligned>((const __m128i*)(p+stride));
		unsigned int up_flags, down_flags;
		CHECK_BARRIER(lo, hi, above, up_flags);
		CHECK_BARRIER(lo, hi, below, down_flags);
		const unsigned int either_ud = up_flags | down_flags;
		if (either_ud) {
		    unsigned int left_flags;
		    {
			const __m128i other = _mm_loadu_si128((const __m128i*)(p-3));
			CHECK_BARRIER(lo, hi, other, left_flags);
		    }
		    const unsigned int both_ud = up_flags & down_flags;
		    if (both_ud | (either_ud&left_flags)) {
			unsigned int right_flags;
			{
			    const __m128i other = _mm_loadu_si128((const __m128i*)(p+3));
			    CHECK_BARRIER(lo, hi, other, right_flags);
			}
			const unsigned int at_least_three = (either_ud & (left_flags & right_flags)) | (both_ud & (left_flags | right_flags));
			if (at_least_three) {
			    process_16<4>(at_least_three, p, w, barrier, passed);
			}
		    }
		}
	    }
	    passed.push_back(0);
	}
	corners.reserve(passed.size());
	int row = 3;
	const byte* row_start = I[3];
	for (Passed::iterator it = passed.begin(); it != passed.end(); ++it) {
	    if (*it == 0) {
		row_start=I[++row];
		continue;
	    }
	    int x = *it - row_start;
	    if (x > 2 && x < w-3)
		corners.push_back(ImageRef(x, row));
	}
    }

    void fast_corner_detect_12(const BasicImage<byte>& I, std::vector<ImageRef>& corners, int barrier)
    {
	if (I.size().x < 22) {
	    fast_corner_detect_plain_12(I,corners,barrier);
	    return;
	} else if (I.size().x < 22 || I.size().y < 7)
	    return;

	if (is_aligned<16>(I[0]) && is_aligned<16>(I[1]))
	    faster_corner_detect_12<true>(I, corners, barrier);
	else
	    faster_corner_detect_12<false>(I, corners, barrier);
    }
}

<|endoftext|>


<commit_before>//bash -c 'gcc -O2 -Wall d.cpp `pkg-config --cflags --libs glib-2.0` -o ../d'

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/time.h>
#include <glib.h>
#include <errno.h>

void errif(bool cond, const char* fmt, ...) {
	if(cond) {
		va_list args;
		va_start(args, fmt);
		vfprintf(stderr, fmt, args);
		va_end(args);
		exit(1);
	}
}

typedef long long int randval_t;

void rand_init(void) {
	// 1-second precision is annoying
	// Even, run 'd' two times in one second and get the same results!
	// #include <time.h> ..... srand(time(NULL));
	struct timeval now;
	gettimeofday(&now, NULL);
	srand(now.tv_usec ^ now.tv_sec);
}

randval_t rand_val(void) {
	return ((randval_t)rand()) + ((randval_t)rand()>>16)
		+ ((randval_t)rand()<<16) + ((randval_t)rand()<<31);
}

const char help_string[] =
"Usage: d sides [times[!]]\n"
"\t`d` rolls imaginary dice.\n"
"\n"
"\t`d 6` prints a number from 1 to 6 inclusive.\n"
"\t`d 6 10` prints ten numbers from 1 to 6 inclusive.\n"
"\t`d 6 4!` prints four non-repeating numbers from 1\n"
"\t\t\tto 6 inclusive.  For example,\n"
"\t\t\t`d 5 5!`\n"
"\t\t\tlets you choose a random order\n"
"\t\t\tfor five items you've lined up.\n"
"\t\t\tFor short:\n"
"\t`d 5 !` arranges the numbers 1 to 5 in a random\n"
"\t\t\torder, equivalent to `d 5 5!`.\n"
"\n"
"\t\"sides\" may be any number from 1 on up.\n"
"\t\"times\" can't be negative, and if you want non-repeating.\n"
"\t\t\tnumbers then must be no greater than sides.\n"
;

int main(int argc, char** argv)
{
	if(argc <= 1) {
		fprintf(stderr, help_string);
		exit(1);
	}
	if(strcmp(argv[1], "--help") == 0 ||
	   strcmp(argv[1], "--version") == 0) {
		fprintf(stdout, help_string);
		exit(0);
	}

	rand_init();

	randval_t sides;
	{
		const char* sides_arg = argv[1];
		char* nextc;
		errno = 0;
		sides = strtoll(sides_arg, &nextc, 10);
		errif(nextc == sides_arg || sides <= 0, "Sides ('%s'?) must be a positive number.\n", sides_arg);
		errif(errno == ERANGE && sides == LLONG_MAX, "Implementation limit: sides ('%s') must be no greater than %lli (*pout*)\n", sides_arg, LLONG_MAX);
		errif(*nextc != '\0', "Sides ('%s') must contain only a number.", sides_arg);
	}
	randval_t times = 1;
	bool factorial = false;
	if(argc >= 3) {
		const char* times_arg = argv[2];
		char* nextc;
		errno = 0;
		times = strtoll(times_arg, &nextc, 10);
		errif(times < 0, "Can't take an action less than zero (%lli) times!\n", times);
		errif(errno == ERANGE && sides == LLONG_MAX, "Implementation limit: times ('%s') must be no greater than %lli (*pout*)\n", times_arg, LLONG_MAX);
		if(*nextc == '!') {
			factorial = true;
			if(nextc == times_arg) {
				times = sides;
			}
			++nextc;
			errif(times > sides, "Can't pigeonhole %i nums in %lli possibilities.\n", times, sides);
		}
		if(times == 0) {
			// This is allowed, but helpfully point out why
			// the user is getting zero output.
			fprintf(stderr, "(You roll the die zero times.)\n");
		}
		errif(nextc == times_arg || *nextc != '\0', "Times ('%s'?) must be a non-negative number and/or \"!\".\n", times_arg);
	}

	randval_t* results = (randval_t*)malloc(times * sizeof(randval_t));
	GHashTable* already = g_hash_table_new(&g_int64_hash, &g_int64_equal);

	for(randval_t i = 0; i < times; ++i) {
		do {
			results[i] = rand_val() % sides + 1;
		} while(g_hash_table_lookup(already, &results[i]));

		if(factorial) {
			g_hash_table_insert(already, &results[i], &results[i]);
		}

		printf("%lld\n", results[i]);
	}

	g_hash_table_destroy(already);
	free(results);
}
<commit_msg>fix doc summary accuracy<commit_after>//bash -c 'gcc -O2 -Wall d.cpp `pkg-config --cflags --libs glib-2.0` -o ../d'

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/time.h>
#include <glib.h>
#include <errno.h>

void errif(bool cond, const char* fmt, ...) {
	if(cond) {
		va_list args;
		va_start(args, fmt);
		vfprintf(stderr, fmt, args);
		va_end(args);
		exit(1);
	}
}

typedef long long int randval_t;

void rand_init(void) {
	// 1-second precision is annoying
	// Even, run 'd' two times in one second and get the same results!
	// #include <time.h> ..... srand(time(NULL));
	struct timeval now;
	gettimeofday(&now, NULL);
	srand(now.tv_usec ^ now.tv_sec);
}

randval_t rand_val(void) {
	return ((randval_t)rand()) + ((randval_t)rand()>>16)
		+ ((randval_t)rand()<<16) + ((randval_t)rand()<<31);
}

const char help_string[] =
"Usage: d sides [[times][!]]\n"
"\t`d` rolls imaginary dice.\n"
"\n"
"\t`d 6` prints a number from 1 to 6 inclusive.\n"
"\t`d 6 10` prints ten numbers from 1 to 6 inclusive.\n"
"\t`d 6 4!` prints four non-repeating numbers from 1\n"
"\t\t\tto 6 inclusive.  For example,\n"
"\t\t\t`d 5 5!`\n"
"\t\t\tlets you choose a random order\n"
"\t\t\tfor five items you've lined up.\n"
"\t\t\tFor short:\n"
"\t`d 5 !` arranges the numbers 1 to 5 in a random\n"
"\t\t\torder, equivalent to `d 5 5!`.\n"
"\n"
"\t\"sides\" may be any number from 1 on up.\n"
"\t\"times\" can't be negative, and if you want non-repeating.\n"
"\t\t\tnumbers then must be no greater than sides.\n"
;

int main(int argc, char** argv)
{
	if(argc <= 1) {
		fprintf(stderr, help_string);
		exit(1);
	}
	if(strcmp(argv[1], "--help") == 0 ||
	   strcmp(argv[1], "--version") == 0) {
		fprintf(stdout, help_string);
		exit(0);
	}

	rand_init();

	randval_t sides;
	{
		const char* sides_arg = argv[1];
		char* nextc;
		errno = 0;
		sides = strtoll(sides_arg, &nextc, 10);
		errif(nextc == sides_arg || sides <= 0, "Sides ('%s'?) must be a positive number.\n", sides_arg);
		errif(errno == ERANGE && sides == LLONG_MAX, "Implementation limit: sides ('%s') must be no greater than %lli (*pout*)\n", sides_arg, LLONG_MAX);
		errif(*nextc != '\0', "Sides ('%s') must contain only a number.", sides_arg);
	}
	randval_t times = 1;
	bool factorial = false;
	if(argc >= 3) {
		const char* times_arg = argv[2];
		char* nextc;
		errno = 0;
		times = strtoll(times_arg, &nextc, 10);
		errif(times < 0, "Can't take an action less than zero (%lli) times!\n", times);
		errif(errno == ERANGE && sides == LLONG_MAX, "Implementation limit: times ('%s') must be no greater than %lli (*pout*)\n", times_arg, LLONG_MAX);
		if(*nextc == '!') {
			factorial = true;
			if(nextc == times_arg) {
				times = sides;
			}
			++nextc;
			errif(times > sides, "Can't pigeonhole %i nums in %lli possibilities.\n", times, sides);
		}
		if(times == 0) {
			// This is allowed, but helpfully point out why
			// the user is getting zero output.
			fprintf(stderr, "(You roll the die zero times.)\n");
		}
		errif(nextc == times_arg || *nextc != '\0', "Times ('%s'?) must be a non-negative number and/or \"!\".\n", times_arg);
	}

	randval_t* results = (randval_t*)malloc(times * sizeof(randval_t));
	GHashTable* already = g_hash_table_new(&g_int64_hash, &g_int64_equal);

	for(randval_t i = 0; i < times; ++i) {
		do {
			results[i] = rand_val() % sides + 1;
		} while(g_hash_table_lookup(already, &results[i]));

		if(factorial) {
			g_hash_table_insert(already, &results[i], &results[i]);
		}

		printf("%lld\n", results[i]);
	}

	g_hash_table_destroy(already);
	free(results);
}
<|endoftext|>


<commit_before>#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <string>
#include <iostream>
#include <unordered_set>
#include <unordered_map>
#include <regex>
#include <future>
#include <atomic>
using namespace std;

#include "scx/Dir.hpp"
#include "scx/FileInfo.hpp"
using namespace scx;

const unordered_set<string> C_EXT = { "c" };
const unordered_set<string> CXX_EXT = { "cc", "cxx", "cpp", "C" };

struct ConsUnit
{
    string in;
    string out;
    string build;
#ifdef DEBUG
    vector<string> deps;
#endif

    explicit ConsUnit(const string& _in): in(_in) { }
};

std::string DoCmd(const string& cmd)
{
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe)
        return "";

    std::string output;
    char buffer[1024];
    while ( !feof(pipe) ) {
        if (fgets(buffer, sizeof(buffer), pipe) != NULL)
            output += buffer;
    }
    pclose(pipe);

    return output;
}

std::vector<std::string> RegexSplit(const string& in, const string& sre)
{
    std::regex re(sre);
    std::sregex_token_iterator
        first { in.begin(), in.end(), re, -1 },
        last;
    return { first, last };
}

bool IsNewer(const string& f1, const string& f2)
{
    struct stat s1, s2;
    ::memset(&s1, 0, sizeof(struct stat));
    ::memset(&s2, 0, sizeof(struct stat));

    ::stat(f1.c_str(), &s1);
    ::stat(f2.c_str(), &s2);
    return ((s1.st_mtim.tv_sec == s2.st_mtim.tv_sec) ?
            (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) :
            (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec));
}

// Maybe we can cache mtime to reduce the stat() system calls.
bool InitConstUnit(ConsUnit& u, const string& c, const string& f)
{
    const string& cmd(c + " -MM " + u.in + " " + f);
    const string& deps( DoCmd(cmd) );
    const string& re("(\\s)+(\\\\)*(\\s)*");

    const auto& l = RegexSplit(deps, re);
    if (l.size() >= 2) {
        u.out = l[0].substr(0, l[0].size()-1);

        bool need = false;
        if ( FileInfo(u.out).Exists() ) {
            for (size_t i = 1; i < l.size(); ++i) {
                if (IsNewer(l[i], u.out)) {
                    need = true;
                    break;
                }
            }
        } else {
            need = true;
        }

        if (need) {
            u.build = c + " -o " + u.out + " -c " + u.in + " " + f;
#ifdef DEBUG
            u.deps.assign(l.begin()+1, l.end());
#endif
        }
        return true;
    } else {
        return false;
    }
}

void Usage(const string& cmd)
{
    const string& sp(cmd.size(), ' ');
    cout << ""
        "Usage:\n"
        "\t" + cmd + " [ file1 file1 | dir1 dir2 ]\n"
        "\t" + sp + " cc=?        C compiler.\n"
        "\t" + sp + " cxx=?       C++ compiler.\n"
        "\t" + sp + " flag=?      Compiler flag.\n"
        "\t" + sp + " ldflag=?    Linker flag.\n"
        //"   " + sp + " with=?,?,? without=?,?,?\n"
        //"   " + sp + " obj=\"outA:dep1, dep2:cmdA; outB:dep1, dep2:cmdB; ...\"\n"
        "\t" + sp + " shared      Generate shared library.\n"
        "\t" + sp + " debug       Build with debug symbols.\n"
        "\t" + sp + " clean       Clean build output.\n"
        "\t" + sp + " help        Show this help message.\n";
}

int main(int argc, char** argv)
{
    const unsigned int cpus = sysconf(_SC_NPROCESSORS_ONLN);

    unordered_map<string, string> ArgTable = {
        { "out", "a.exe" },
        { "with", "" },
        { "without", "" },
        { "cc", "cc" },
        { "cxx", "c++" },
        { "flag", "" },
        { "ld", "cc" },
        { "ldflag", "" }
    };

    bool shared = false;
    bool debug = false;
    bool clean = false;
    vector<string> with, without, all;

    // Parse arguments.
    for (int i = 1; i < argc; ++i) {
        const string& arg(argv[i]);

        size_t pos = arg.find('=');
        if (pos != string::npos && pos != arg.size()-1) {
            auto iter = ArgTable.find( arg.substr(0, pos) );
            if (iter != ArgTable.end()) {
                iter->second = arg.substr(pos+1);
            }
            continue;
        } else if (arg == "clean") {
            clean = true;
            continue;
        } else if (arg == "debug") {
            debug = true;
            continue;
        } else if (arg == "shared") {
            shared = true;
            continue;
        } else if (arg == "help") {
            Usage(argv[0]);
            return 0;
        }

        switch ( FileInfo(arg).Type() ) {
        case FileType::Directory:
        {
            auto files = Dir::ListTree(arg);
            all.reserve(all.size() + files.size());
            all.insert(all.end(), files.begin(), files.end());
        }
            break;

        case FileType::Regular:
        {
            all.push_back(arg);
        }
            break;

        default:
        {
            cout << "WARN: bad argument." << endl;
            cout << "\targ:" << arg << endl;
        }
            break;
        }
    }

    if (all.empty())
        all = Dir::ListTree(".");
    if (all.empty()) {
        cerr << "FATAL: nothing to build!" << endl;
        return 1;
    }

    // Prepare construct units.
    bool hasCpp = false;
    vector<ConsUnit> units;
    size_t buildCount = 0;
    for (const auto& file: all) {
        ConsUnit unit(file);
        string compiler, flag;

        if (debug)
            flag += "-g ";
        if (shared)
            flag += "-fPIC ";

        // Pick up source file.
        const string ext( FileInfo(file).Suffix() );
        if (C_EXT.find(ext) != C_EXT.end()) {
            compiler = ArgTable["cc"];
            flag += ArgTable["flag"];
        } else if (CXX_EXT.find(ext) != CXX_EXT.end()) {
            compiler = ArgTable["cxx"];
            flag += ArgTable["flag"];
            hasCpp = true;
        } else
            continue;

        // Calculate dependence.
        if ( InitConstUnit(unit, compiler, flag) ) {
            units.push_back(unit);
            if (!unit.build.empty()) ++buildCount;
        } else {
            cerr << "FATAL: failed to calculate dependence!" << endl;
            cerr << "\tfile: " << file << endl;
            cerr << "\tcompiler:" << compiler << endl;
            cerr << "\tflag:" << flag << endl;
            return 1;
        }
    }
    if (hasCpp)
        ArgTable["ld"] = ArgTable["cxx"];

#ifdef DEBUG
    // Debug info.
    for (const auto& unit: units) {
        cout << "in: " <<  unit.in << ", " << "out: " << unit.out << endl;
        cout << "\t" << unit.build << endl;
        cout << "\t";
        for (const auto& dep: unit.deps)
            cout << dep << ", ";
        cout << endl;
    }
#endif

    // Let's build them all.
    if (!clean) {
        bool compiled = false;
        string ldCmd = ArgTable["ld"] + " -o " + ArgTable["out"] + " " + ArgTable["flag"] + " " + ArgTable["ldflag"] + " ";

        if (shared)
            ldCmd += "-shared ";

        cout << "== Compile ==" << endl;
        size_t buildIndex = 0;
        for (const auto& unit: units) {
            if (!unit.build.empty()) {
                assert(buildCount != 0);

                char buf[] = "[ 100% ] ";
                int percent = (double)(++buildIndex) / buildCount * 100;
                ::snprintf(buf, sizeof buf, "[ %3.d%% ] ", percent);
                cout << buf << unit.build << endl;

                if (::system( unit.build.c_str() ) != 0)
                    return 2;
                compiled = true;
            }

            ldCmd += unit.out + " ";
        }

        cout << "== Generate ==" << endl;
        if (compiled || !FileInfo(ArgTable["out"]).Exists() ) {
            cout << ldCmd << endl;
            if (::system( ldCmd.c_str() ) != 0)
                return 3;
        }

        cout << "== Done! ==" << endl;
    } else {
        const string& rm("rm -f ");
        for (const auto& unit: units) {
            const string& cmd(rm + unit.out);
            cout << cmd << endl;
            ::system( cmd.c_str() );
        }
        const string& cmd(rm + ArgTable["out"]);
        cout << cmd << endl;
        ::system( cmd.c_str() );
    }

    return 0;
}
<commit_msg>* new option clang++11<commit_after>#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <string>
#include <iostream>
#include <unordered_set>
#include <unordered_map>
#include <regex>
#include <future>
#include <atomic>
using namespace std;

#include "scx/Dir.hpp"
#include "scx/FileInfo.hpp"
using namespace scx;

const unordered_set<string> C_EXT = { "c" };
const unordered_set<string> CXX_EXT = { "cc", "cxx", "cpp", "C" };

struct ConsUnit
{
    string in;
    string out;
    string build;
#ifdef DEBUG
    vector<string> deps;
#endif

    explicit ConsUnit(const string& _in): in(_in) { }
};

std::string DoCmd(const string& cmd)
{
    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe)
        return "";

    std::string output;
    char buffer[1024];
    while ( !feof(pipe) ) {
        if (fgets(buffer, sizeof(buffer), pipe) != NULL)
            output += buffer;
    }
    pclose(pipe);

    return output;
}

std::vector<std::string> RegexSplit(const string& in, const string& sre)
{
    std::regex re(sre);
    std::sregex_token_iterator
        first { in.begin(), in.end(), re, -1 },
        last;
    return { first, last };
}

bool IsNewer(const string& f1, const string& f2)
{
    struct stat s1, s2;
    ::memset(&s1, 0, sizeof(struct stat));
    ::memset(&s2, 0, sizeof(struct stat));

    ::stat(f1.c_str(), &s1);
    ::stat(f2.c_str(), &s2);
    return ((s1.st_mtim.tv_sec == s2.st_mtim.tv_sec) ?
            (s1.st_mtim.tv_nsec > s2.st_mtim.tv_nsec) :
            (s1.st_mtim.tv_sec > s2.st_mtim.tv_sec));
}

// Maybe we can cache mtime to reduce the stat() system calls.
bool InitConstUnit(ConsUnit& u, const string& c, const string& f)
{
    const string& cmd(c + " -MM " + u.in + " " + f);
    const string& deps( DoCmd(cmd) );
    const string& re("(\\s)+(\\\\)*(\\s)*");

    const auto& l = RegexSplit(deps, re);
    if (l.size() >= 2) {
        u.out = l[0].substr(0, l[0].size()-1);

        bool need = false;
        if ( FileInfo(u.out).Exists() ) {
            for (size_t i = 1; i < l.size(); ++i) {
                if (IsNewer(l[i], u.out)) {
                    need = true;
                    break;
                }
            }
        } else {
            need = true;
        }

        if (need) {
            u.build = c + " -o " + u.out + " -c " + u.in + " " + f;
#ifdef DEBUG
            u.deps.assign(l.begin()+1, l.end());
#endif
        }
        return true;
    } else {
        return false;
    }
}

void Usage(const string& cmd)
{
    const string sp(cmd.size(), ' ');
    cout << ""
        "Usage:\n"
        "\t" + cmd + " [ file1 file1 | dir1 dir2 ]\n"
        "\t" + sp + " cc=?        C compiler.\n"
        "\t" + sp + " cxx=?       C++ compiler.\n"
        "\t" + sp + " flag=?      Compiler flag.\n"
        "\t" + sp + " ldflag=?    Linker flag.\n"
        //"   " + sp + " with=?,?,? without=?,?,?\n"
        //"   " + sp + " obj=\"outA:dep1, dep2:cmdA; outB:dep1, dep2:cmdB; ...\"\n"
        "\t" + sp + " clean       Clean build output.\n"
        "\t" + sp + " help        Show this help message.\n"
        "\n"
        "\t" + sp + " shared      Generate shared library. (*)\n"
        "\t" + sp + " debug       Build with debug symbols. (*)\n"
        "\t" + sp + " clang++11   Use clang & libc++. (*)\n"
        "\n";

    cout << ""
        "Note:\n"
        "\t(*) Just for convenient. You may also use flags to approach the function.\n"
        "\n";

    cout << ""
        "Author:\n"
        "\tYanhui Shen <@pagedir on Twitter>\n";
}

int main(int argc, char** argv)
{
    const unsigned int cpus = sysconf(_SC_NPROCESSORS_ONLN);

    unordered_map<string, string> ArgTable = {
        { "out", "a.exe" },
        { "with", "" },
        { "without", "" },
        { "cc", "cc" },
        { "cxx", "c++" },
        { "flag", "" },
        { "ld", "cc" },
        { "ldflag", "" }
    };

    bool shared = false;
    bool debug = false;
    bool clean = false;
    bool useClangXX11 = false;
    vector<string> with, without, all;

    // Parse arguments.
    for (int i = 1; i < argc; ++i) {
        const string& arg(argv[i]);

        // So obvisously, file name should not contains '='.
        size_t pos = arg.find('=');
        if (pos != string::npos && pos != arg.size()-1) {
            // Update key-value.
            auto iter = ArgTable.find( arg.substr(0, pos) );
            if (iter != ArgTable.end()) {
                iter->second = arg.substr(pos+1);
            }
        } else if (arg == "clean") {
            clean = true;
        } else if (arg == "help") {
            Usage(argv[0]);
            return 0;
        } else if (arg == "debug") {
            debug = true;
        } else if (arg == "shared") {
            shared = true;
        } else if (arg == "clang++11") {
            useClangXX11 = true;
        } else {
            switch ( FileInfo(arg).Type() ) {
            case FileType::Directory:
            {
                auto files = Dir::ListTree(arg);
                all.reserve(all.size() + files.size());
                all.insert(all.end(), files.begin(), files.end());
            }
                break;

            case FileType::Regular:
            {
                all.push_back(arg);
            }
                break;

            default:
            {
                cout << "WARN: bad argument." << endl;
                cout << "\targ:" << arg << endl;
            }
                break;
            }
        }
    }

    if (useClangXX11) {
        ArgTable["cc"] = "clang";
        ArgTable["cxx"] = "clang++";
        ArgTable["flag"] += " -std=c++11 -stdlib=libc++ ";
    }

    if (all.empty())
        all = Dir::ListTree(".");
    if (all.empty()) {
        cerr << "FATAL: nothing to build!" << endl;
        return 1;
    }

    // Prepare construct units.
    bool hasCpp = false;
    vector<ConsUnit> units;
    size_t buildCount = 0;
    for (const auto& file: all) {
        ConsUnit unit(file);
        string compiler, flag;

        if (debug)
            flag += "-g ";
        if (shared)
            flag += "-fPIC ";

        // Pick up source file.
        const string ext( FileInfo(file).Suffix() );
        if (C_EXT.find(ext) != C_EXT.end()) {
            compiler = ArgTable["cc"];
            flag += ArgTable["flag"];
        } else if (CXX_EXT.find(ext) != CXX_EXT.end()) {
            compiler = ArgTable["cxx"];
            flag += ArgTable["flag"];
            hasCpp = true;
        } else
            continue;

        // Calculate dependence.
        if ( InitConstUnit(unit, compiler, flag) ) {
            units.push_back(unit);
            if (!unit.build.empty()) ++buildCount;
        } else {
            cerr << "FATAL: failed to calculate dependence!" << endl;
            cerr << "\tfile: " << file << endl;
            cerr << "\tcompiler:" << compiler << endl;
            cerr << "\tflag:" << flag << endl;
            return 1;
        }
    }
    if (hasCpp)
        ArgTable["ld"] = ArgTable["cxx"];

#ifdef DEBUG
    // Debug info.
    for (const auto& unit: units) {
        cout << "in: " <<  unit.in << ", " << "out: " << unit.out << endl;
        cout << "\t" << unit.build << endl;
        cout << "\t";
        for (const auto& dep: unit.deps)
            cout << dep << ", ";
        cout << endl;
    }
#endif

    // Let's build them all.
    if (!clean) {
        bool compiled = false;
        string ldCmd = ArgTable["ld"] + " -o " + ArgTable["out"] + " " +
                       ArgTable["flag"] + " " + ArgTable["ldflag"] + " ";

        if (shared)
            ldCmd += "-shared ";

        cout << "== Compile ==" << endl;
        size_t buildIndex = 0;
        for (const auto& unit: units) {
            if (!unit.build.empty()) {
                assert(buildCount != 0);

                char buf[] = "[ 100% ] ";
                int percent = (double)(++buildIndex) / buildCount * 100;
                ::snprintf(buf, sizeof buf, "[ %3.d%% ] ", percent);
                cout << buf << unit.build << endl;

                if (::system( unit.build.c_str() ) != 0)
                    return 2;
                compiled = true;
            }

            ldCmd += unit.out + " ";
        }

        cout << "== Generate ==" << endl;
        if (compiled || !FileInfo(ArgTable["out"]).Exists() ) {
            cout << ldCmd << endl;
            if (::system( ldCmd.c_str() ) != 0)
                return 3;
        }

        cout << "== Done! ==" << endl;
    } else {
        const string& rm("rm -f ");
        for (const auto& unit: units) {
            const string& cmd(rm + unit.out);
            cout << cmd << endl;
            ::system( cmd.c_str() );
        }
        const string& cmd(rm + ArgTable["out"]);
        cout << cmd << endl;
        ::system( cmd.c_str() );
    }

    return 0;
}
<|endoftext|>